--- a/jdk/make/copy/Copy-java.base.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/copy/Copy-java.base.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -100,8 +100,7 @@
# Allow override by ALT_JVMCFG_SRC if it exists
JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC))
endif
-JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)
-JVMCFG := $(JVMCFG_DIR)/jvm.cfg
+JVMCFG := $(LIB_DST_DIR)/jvm.cfg
# To do: should this also support -zeroshark?
--- a/jdk/make/copy/Copy-java.desktop.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/copy/Copy-java.desktop.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 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
@@ -64,7 +64,7 @@
ifeq ($(OPENJDK_TARGET_OS), windows)
FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype)
else
- FREETYPE_TARGET_LIB := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)/$(call SHARED_LIBRARY,freetype).6
+ FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
endif
# We can't use $(install-file) in this rule because it preserves symbolic links and
--- a/jdk/make/launcher/Launcher-java.base.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/launcher/Launcher-java.base.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -74,7 +74,7 @@
BUILD_JEXEC :=
BUILD_JEXEC_SRC :=
BUILD_JEXEC_INC :=
-BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
#
# UNHANDLED:
@@ -138,7 +138,7 @@
BUILD_JSPAWNHELPER :=
BUILD_JSPAWNHELPER_SRC := $(JDK_TOPDIR)/src/java.base/unix/native/jspawnhelper
JSPAWNHELPER_CFLAGS := -I$(JDK_TOPDIR)/src/java.base/unix/native/libjava
-BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
LINK_JSPAWNHELPER_OBJECTS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjava/childproc.o
BUILD_JSPAWNHELPER_LDFLAGS :=
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/launcher/Launcher-jdk.aot.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,37 @@
+#
+# 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. 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.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, jaotc, \
+ MAIN_CLASS := jdk.tools.jaotc.Main, \
+ JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
+ -XX:+UseAOT \
+ -Djvmci.UseProfilingInformation=false \
+ -Dgraal.UseExceptionProbability=false \
+ -Djvmci.Compiler=graal \
+ --add-modules ALL-DEFAULT \
+ , \
+))
--- a/jdk/make/launcher/LauncherCommon.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/launcher/LauncherCommon.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -32,13 +32,13 @@
ifeq ($(OPENJDK_TARGET_OS), windows)
DISABLE_MAPFILES := true
endif
- ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR)/jli)
+ ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib/jli)
# Applications expect to be able to link against libjawt without invoking
# System.loadLibrary("jawt") first. This was the behaviour described in the
# devloper documentation of JAWT and what worked with OpenJDK6.
ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
- ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR))
+ ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib)
endif
endif
@@ -190,9 +190,9 @@
$$(ORIGIN_ARG) \
$$($1_LDFLAGS), \
LDFLAGS_linux := \
- -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+ -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \
- -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+ -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
MAPFILE := $$($1_MAPFILE), \
LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
LIBS_unix := $$($1_LIBS_unix), \
--- a/jdk/make/lib/Awt2dLibraries.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/lib/Awt2dLibraries.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -418,6 +418,7 @@
DISABLED_WARNINGS_gcc := format-nonliteral type-limits misleading-indentation, \
DISABLED_WARNINGS_clang := tautological-compare, \
DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
+ DISABLED_WARNINGS_microsoft := 4819, \
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/liblcms/mapfile-vers, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
@@ -681,7 +682,7 @@
DISABLED_WARNINGS_CXX_solstudio := \
truncwarn wvarhidenmem wvarhidemem wbadlkginit identexpected \
hidevf w_novirtualdescr arrowrtn2, \
- DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334, \
+ DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334 4819, \
MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \
LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
--- a/jdk/make/lib/CoreLibraries.gmk Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/lib/CoreLibraries.gmk Mon Dec 19 16:05:38 2016 +0000
@@ -340,9 +340,6 @@
LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS))
-# Append defines depending on target platform
-LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
-
ifneq ($(USE_EXTERNAL_LIBZ), true)
LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
LIBJLI_EXTRA_FILES += \
--- a/jdk/make/mapfiles/libjava/mapfile-vers Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/mapfiles/libjava/mapfile-vers Mon Dec 19 16:05:38 2016 +0000
@@ -150,7 +150,6 @@
Java_java_lang_StrictMath_atan;
Java_java_lang_StrictMath_atan2;
Java_java_lang_StrictMath_cos;
- Java_java_lang_StrictMath_exp;
Java_java_lang_StrictMath_log;
Java_java_lang_StrictMath_log10;
Java_java_lang_StrictMath_sin;
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,6 +26,7 @@
package build.tools.jigsaw;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
@@ -44,7 +45,8 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
-import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
/**
@@ -69,42 +71,25 @@
.map(ModuleReference::descriptor)
.filter(m -> (m.name().startsWith("java.") &&
!m.name().equals("java.smartcardio")))
- .collect(Collectors.toSet()));
+ .collect(toSet()));
Set<ModuleDescriptor> jdkModules
= new TreeSet<>(finder.findAll().stream()
.map(ModuleReference::descriptor)
.filter(m -> !javaSEModules.contains(m))
- .collect(Collectors.toSet()));
+ .collect(toSet()));
- GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules);
+ GenGraphs genGraphs = new GenGraphs(dir, javaSEModules, jdkModules);
Set<String> mods = new HashSet<>();
for (ModuleReference mref: finder.findAll()) {
- ModuleDescriptor descriptor = mref.descriptor();
- String name = descriptor.name();
- mods.add(name);
- Configuration cf = Configuration.empty()
- .resolveRequires(finder,
- ModuleFinder.of(),
- Set.of(name));
- genGraphs.genDotFile(dir, name, cf);
+ mods.add(mref.descriptor().name());
+ genGraphs.genDotFile(mref);
}
- Configuration cf = Configuration.empty()
- .resolveRequires(finder,
- ModuleFinder.of(),
- mods);
- genGraphs.genDotFile(dir, "jdk", cf);
+ // all modules
+ genGraphs.genDotFile("jdk", mods);
}
- private final Set<ModuleDescriptor> javaGroup;
- private final Set<ModuleDescriptor> jdkGroup;
-
- GenGraphs(Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
- this.javaGroup = Collections.unmodifiableSet(javaGroup);
- this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
- }
-
private static final String ORANGE = "#e76f00";
private static final String BLUE = "#437291";
private static final String GRAY = "#dddddd";
@@ -145,23 +130,70 @@
}
- private void genDotFile(Path dir, String name, Configuration cf) throws IOException {
- try (PrintStream out
- = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
+ private final Path dir;
+ private final Set<ModuleDescriptor> javaGroup;
+ private final Set<ModuleDescriptor> jdkGroup;
+
+ GenGraphs(Path dir, Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
+ this.dir = dir;
+ this.javaGroup = Collections.unmodifiableSet(javaGroup);
+ this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
+ }
+
+ /**
+ * Generates a dot file for the given module reference as the root.
+ */
+ void genDotFile(ModuleReference mref) throws IOException {
+ String name = mref.descriptor().name();
+ genDotFile(name, Set.of(name));
+ }
+
+ /**
+ * Generates a dot file for the given set of root modules.
+ */
+ void genDotFile(String name, Set<String> roots) throws IOException {
+ Configuration cf =
+ Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
+ ModuleFinder.of(),
+ roots);
+
+ Set<ModuleDescriptor> mds = cf.modules().stream()
+ .map(ResolvedModule::reference)
+ .map(ModuleReference::descriptor)
+ .collect(toSet());
- Map<String, ModuleDescriptor> nameToModule;
- if (name.equals("java.se.ee")) {
- nameToModule = cf.modules().stream()
- .map(ResolvedModule::reference)
- .map(ModuleReference::descriptor)
- .filter(md -> !md.name().startsWith("jdk."))
- .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
- } else {
- nameToModule = cf.modules().stream()
- .map(ResolvedModule::reference)
- .map(ModuleReference::descriptor)
- .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
+ // generate a dot file for the resolved graph
+ try (OutputStream os = Files.newOutputStream(dir.resolve(name + ".dot"));
+ PrintStream out = new PrintStream(os)) {
+ printGraph(out, name, gengraph(cf),
+ mds.stream()
+ .collect(toMap(ModuleDescriptor::name, Function.identity()))
+ );
+ }
+
+ if (name.equals("java.se") || name.equals("java.se.ee")) {
+ // generate a dot file for Java SE module graph
+ try (OutputStream os = Files.newOutputStream(dir.resolve(name + "-spec.dot"));
+ PrintStream out = new PrintStream(os)) {
+ // transitive reduction on the graph of `requires transitive` edges
+ // filter out jdk.* modules which are implementation dependences
+ Graph<String> graph = requiresTransitiveGraph(cf, true);
+ printGraph(out, name, graph,
+ mds.stream()
+ .filter(md -> !md.name().startsWith("jdk.") &&
+ graph.nodes().contains(md.name()))
+ .collect(toMap(ModuleDescriptor::name, Function.identity()))
+ );
}
+ }
+ }
+
+ private void printGraph(PrintStream out,
+ String name,
+ Graph<String> graph,
+ Map<String, ModuleDescriptor> nameToModule)
+ throws IOException
+ {
Set<ModuleDescriptor> descriptors = new TreeSet<>(nameToModule.values());
out.format("digraph \"%s\" {%n", name);
@@ -182,13 +214,13 @@
// same ranks
ranks.stream()
- .forEach(group -> out.format("{rank=same %s}%n",
- descriptors.stream()
- .map(ModuleDescriptor::name)
- .filter(group::contains)
- .map(mn -> "\"" + mn + "\"")
- .collect(Collectors.joining(","))
- ));
+ .map(group -> descriptors.stream()
+ .map(ModuleDescriptor::name)
+ .filter(group::contains)
+ .map(mn -> "\"" + mn + "\"")
+ .collect(joining(",")))
+ .filter(group -> group.length() > 0)
+ .forEach(group -> out.format("{rank=same %s}%n", group));
descriptors.stream()
.filter(jdkGroup::contains)
@@ -196,30 +228,28 @@
.forEach(mn -> out.format(" \"%s\" [fontcolor=\"%s\", group=%s];%n",
mn, BLUE, "jdk"));
- // transitive reduction
- Graph<String> graph = gengraph(cf);
- descriptors.forEach(md -> {
- String mn = md.name();
- Set<String> requiresTransitive = md.requires().stream()
- .filter(d -> d.modifiers().contains(TRANSITIVE))
- .map(d -> d.name())
- .collect(Collectors.toSet());
+ descriptors.stream()
+ .forEach(md -> {
+ String mn = md.name();
+ Set<String> requiresTransitive = md.requires().stream()
+ .filter(d -> d.modifiers().contains(TRANSITIVE))
+ .map(d -> d.name())
+ .collect(toSet());
- graph.adjacentNodes(mn)
- .stream()
- .filter(nameToModule::containsKey)
- .forEach(dn -> {
- String attr = dn.equals("java.base") ? REQUIRES_BASE
- : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
- int w = weightOf(mn, dn);
- if (w > 1)
- attr += "weight=" + w;
- out.format(" \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
- });
- });
+ graph.adjacentNodes(mn)
+ .stream()
+ .filter(nameToModule::containsKey)
+ .forEach(dn -> {
+ String attr = dn.equals("java.base") ? REQUIRES_BASE
+ : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
+ int w = weightOf(mn, dn);
+ if (w > 1)
+ attr += "weight=" + w;
+ out.format(" \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+ });
+ });
out.println("}");
- }
}
/**
@@ -239,7 +269,7 @@
.map(ResolvedModule::name)
.forEach(target -> builder.addEdge(mn, target));
}
- Graph<String> rpg = requiresTransitiveGraph(cf);
+ Graph<String> rpg = requiresTransitiveGraph(cf, false);
return builder.build().reduce(rpg);
}
@@ -247,13 +277,14 @@
* Returns a Graph containing only requires transitive edges
* with transitive reduction.
*/
- private Graph<String> requiresTransitiveGraph(Configuration cf) {
+ private Graph<String> requiresTransitiveGraph(Configuration cf, boolean includeBase) {
Graph.Builder<String> builder = new Graph.Builder<>();
for (ResolvedModule resolvedModule : cf.modules()) {
ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
String mn = descriptor.name();
descriptor.requires().stream()
- .filter(d -> d.modifiers().contains(TRANSITIVE))
+ .filter(d -> d.modifiers().contains(TRANSITIVE)
+ || (includeBase && d.name().equals("java.base")))
.map(d -> d.name())
.forEach(d -> builder.addEdge(mn, d));
}
--- a/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c Mon Dec 19 16:05:38 2016 +0000
@@ -171,8 +171,6 @@
* Main
*/
-#define GetArch() GetArchPath(CURRENT_DATA_MODEL)
-
/* Store the name of the executable once computed */
static char *execname = NULL;
@@ -184,16 +182,6 @@
return execname;
}
-const char *
-GetArchPath(int nbits)
-{
- switch(nbits) {
- default:
- return LIBARCHNAME;
- }
-}
-
-
/*
* Exports the JNI interface from libjli
*
@@ -211,7 +199,7 @@
if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
char jrePath[PATH_MAX];
- jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE);
+ jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
if (!gotJREPath) {
JLI_ReportErrorMessage("Failed to GetJREPath()");
return NULL;
@@ -229,7 +217,7 @@
}
char jvmPath[PATH_MAX];
- jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
+ jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), CURRENT_DATA_MODEL);
if (!gotJVMPath) {
JLI_ReportErrorMessage("Failed to GetJVMPath()");
return NULL;
@@ -390,7 +378,6 @@
/* Check data model flags, and exec process, if needed */
{
- char *arch = (char *)GetArch(); /* like sparc or sparcv9 */
char * jvmtype = NULL;
int argc = *pargc;
char **argv = *pargv;
@@ -462,7 +449,7 @@
jvmpath does not exist */
if (wanted == running) {
/* Find out where the JRE is that we will be using. */
- if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+ if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
JLI_ReportErrorMessage(JRE_ERROR1);
exit(2);
}
@@ -481,7 +468,7 @@
exit(4);
}
- if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {
+ if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted)) {
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
exit(4);
}
@@ -502,7 +489,7 @@
#if defined(DUAL_MODE)
if (running != wanted) {
/* Find out where the JRE is that we will be using. */
- if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {
+ if (!GetJREPath(jrepath, so_jrepath, JNI_TRUE)) {
/* give up and let other code report error message */
JLI_ReportErrorMessage(JRE_ERROR2, wanted);
exit(1);
@@ -526,7 +513,7 @@
}
/* exec child can do error checking on the existence of the path */
- jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);
+ jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted);
}
#else /* ! DUAL_MODE */
JLI_ReportErrorMessage(JRE_ERROR2, wanted);
@@ -579,7 +566,7 @@
*/
static jboolean
GetJVMPath(const char *jrepath, const char *jvmtype,
- char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+ char *jvmpath, jint jvmpathsize, int bitsWanted)
{
struct stat s;
@@ -613,7 +600,7 @@
* Find path to JRE based on .exe's location or registry settings.
*/
static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
{
char libjava[MAXPATHLEN];
@@ -841,7 +828,7 @@
void* SplashProcAddress(const char* name) {
if (!hSplashLib) {
char jrePath[PATH_MAX];
- if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {
+ if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
JLI_ReportErrorMessage(JRE_ERROR1);
return NULL;
}
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Dec 19 16:05:38 2016 +0000
@@ -317,7 +317,7 @@
this(null, je);
}
boolean isClassFile() {
- if (!name.endsWith(".class")) {
+ if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
return false;
}
for (String prefix = name;;) {
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties Mon Dec 19 16:05:38 2016 +0000
@@ -14,15 +14,6 @@
pack.class.attribute.SourceID = RUH
pack.class.attribute.CompilationID = RUH
-# Module attributes, supported by the tool and not JSR-200
-pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]]
-pack.class.attribute.ModulePackages = NH[RUH]
-pack.class.attribute.ModuleVersion = RUH
-pack.class.attribute.ModuleMainClass = RCH
-pack.class.attribute.ModuleTarget = RUHRUHRUH
-pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]]
-
-
# Note: Zero-length ("marker") attributes do not need to be specified here.
# They are automatically defined to have an empty layout.
#pack.class.attribute.Deprecated =
--- a/jdk/src/java.base/share/classes/java/lang/FdLibm.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/FdLibm.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -79,7 +79,8 @@
*/
private static double __LO(double x, int low) {
long transX = Double.doubleToRawLongBits(x);
- return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+ return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+ (low & 0x0000_0000_FFFF_FFFFL));
}
/**
@@ -96,7 +97,8 @@
*/
private static double __HI(double x, int high) {
long transX = Double.doubleToRawLongBits(x);
- return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+ return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+ ( ((long)high)) << 32 );
}
/**
@@ -580,4 +582,152 @@
return s * z;
}
}
+
+ /**
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Reme algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+ static class Exp {
+ private static final double one = 1.0;
+ private static final double[] half = {0.5, -0.5,};
+ private static final double huge = 1.0e+300;
+ private static final double twom1000= 0x1.0p-1000; // 9.33263618503218878990e-302 = 2^-1000
+ private static final double o_threshold= 0x1.62e42fefa39efp9; // 7.09782712893383973096e+02
+ private static final double u_threshold= -0x1.74910d52d3051p9; // -7.45133219101941108420e+02;
+ private static final double[] ln2HI ={ 0x1.62e42feep-1, // 6.93147180369123816490e-01
+ -0x1.62e42feep-1}; // -6.93147180369123816490e-01
+ private static final double[] ln2LO ={ 0x1.a39ef35793c76p-33, // 1.90821492927058770002e-10
+ -0x1.a39ef35793c76p-33}; // -1.90821492927058770002e-10
+ private static final double invln2 = 0x1.71547652b82fep0; // 1.44269504088896338700e+00
+
+ private static final double P1 = 0x1.555555555553ep-3; // 1.66666666666666019037e-01
+ private static final double P2 = -0x1.6c16c16bebd93p-9; // -2.77777777770155933842e-03
+ private static final double P3 = 0x1.1566aaf25de2cp-14; // 6.61375632143793436117e-05
+ private static final double P4 = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
+ private static final double P5 = 0x1.6376972bea4d0p-25; // 4.13813679705723846039e-08
+
+ // should be able to forgo strictfp due to controlled over/underflow
+ public static strictfp double compute(double x) {
+ double y;
+ double hi = 0.0;
+ double lo = 0.0;
+ double c;
+ double t;
+ int k = 0;
+ int xsb;
+ /*unsigned*/ int hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = (hx >> 31) & 1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if (hx >= 0x40862E42) { /* if |x| >= 709.78... */
+ if (hx >= 0x7ff00000) {
+ if (((hx & 0xfffff) | __LO(x)) != 0)
+ return x + x; /* NaN */
+ else
+ return (xsb == 0) ? x : 0.0; /* exp(+-inf) = {inf, 0} */
+ }
+ if (x > o_threshold)
+ return huge * huge; /* overflow */
+ if (x < u_threshold) // unsigned compare needed here?
+ return twom1000 * twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x - ln2HI[xsb];
+ lo=ln2LO[xsb];
+ k = 1 - xsb - xsb;
+ } else {
+ k = (int)(invln2 * x + half[xsb]);
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ } else if (hx < 0x3e300000) { /* when |x|<2**-28 */
+ if (huge + x > one)
+ return one + x; /* trigger inexact */
+ } else {
+ k = 0;
+ }
+
+ /* x is now in primary range */
+ t = x * x;
+ c = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
+ if (k == 0)
+ return one - ((x*c)/(c - 2.0) - x);
+ else
+ y = one - ((lo - (x*c)/(2.0 - c)) - hi);
+
+ if(k >= -1021) {
+ y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
+ return y;
+ } else {
+ y = __HI(y, __HI(y) + ((k + 1000) << 20)); /* add k to y's exponent */
+ return y * twom1000;
+ }
+ }
+ }
}
--- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,10 +26,13 @@
package java.lang;
import jdk.internal.loader.BuiltinClassLoader;
-import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
import java.lang.reflect.Layer;
import java.lang.reflect.Module;
import java.util.HashSet;
@@ -477,13 +480,16 @@
static Set<String> HASHED_MODULES = hashedModules();
static Set<String> hashedModules() {
- Module javaBase = Layer.boot().findModule("java.base").get();
- Optional<ModuleHashes> ohashes =
- SharedSecrets.getJavaLangModuleAccess()
- .hashes(javaBase.getDescriptor());
- if (ohashes.isPresent()) {
- Set<String> names = new HashSet<>(ohashes.get().names());
+ Optional<ResolvedModule> resolvedModule = Layer.boot()
+ .configuration()
+ .findModule("java.base");
+ assert resolvedModule.isPresent();
+ ModuleReference mref = resolvedModule.get().reference();
+ assert mref instanceof ModuleReferenceImpl;
+ ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+ if (hashes != null) {
+ Set<String> names = new HashSet<>(hashes.names());
names.add("java.base");
return names;
}
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java Mon Dec 19 16:05:38 2016 +0000
@@ -227,7 +227,9 @@
* @return the value <i>e</i><sup>{@code a}</sup>,
* where <i>e</i> is the base of the natural logarithms.
*/
- public static native double exp(double a);
+ public static double exp(double a) {
+ return FdLibm.Exp.compute(a);
+ }
/**
* Returns the natural logarithm (base <i>e</i>) of a {@code double}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Dec 19 16:05:38 2016 +0000
@@ -172,6 +172,7 @@
* @throws IllegalAccessException if the access check specified above fails
* @throws SecurityException if denied by the security manager
* @since 9
+ * @see Lookup#dropLookupMode
*/
public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
SecurityManager sm = System.getSecurityManager();
@@ -691,10 +692,15 @@
* A lookup object on a new lookup class
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
* may have some mode bits set to zero.
+ * Mode bits can also be
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#dropLookupMode directly cleared}.
+ * Once cleared, mode bits cannot be restored from the downgraded lookup object.
* The purpose of this is to restrict access via the new lookup object,
* so that it can access only names which can be reached by the original
* lookup object, and also by the new lookup class.
* @return the lookup modes, which limit the kinds of access performed by this lookup object
+ * @see #in
+ * @see #dropLookupMode
*/
public int lookupModes() {
return allowedModes & ALL_MODES;
@@ -748,7 +754,8 @@
* which may change due to this operation.
*
* @param requestedLookupClass the desired lookup class for the new lookup object
- * @return a lookup object which reports the desired lookup class
+ * @return a lookup object which reports the desired lookup class, or the same object
+ * if there is no change
* @throws NullPointerException if the argument is null
*/
public Lookup in(Class<?> requestedLookupClass) {
@@ -788,6 +795,40 @@
return new Lookup(requestedLookupClass, newModes);
}
+
+ /**
+ * Creates a lookup on the same lookup class which this lookup object
+ * finds members, but with a lookup mode that has lost the given lookup mode.
+ * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
+ * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
+ * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
+ * mode will never have this access capability. When dropping {@code PACKAGE}
+ * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
+ * access. When dropping {@code MODULE} then the resulting lookup will not
+ * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
+ * PUBLIC} is dropped then the resulting lookup has no access.
+ * @param modeToDrop the lookup mode to drop
+ * @return a lookup object which lacks the indicated mode, or the same object if there is no change
+ * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
+ * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
+ * @since 9
+ * @see MethodHandles#privateLookupIn
+ */
+ public Lookup dropLookupMode(int modeToDrop) {
+ int oldModes = lookupModes();
+ int newModes = oldModes & ~(modeToDrop | PROTECTED);
+ switch (modeToDrop) {
+ case PUBLIC: newModes &= ~(ALL_MODES); break;
+ case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
+ case PACKAGE: newModes &= ~(PRIVATE); break;
+ case PROTECTED:
+ case PRIVATE: break;
+ default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+ }
+ if (newModes == oldModes) return this; // return self if no change
+ return new Lookup(lookupClass(), newModes);
+ }
+
// Make sure outer class is initialized first.
static { IMPL_NAMES.getClass(); }
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Mon Dec 19 16:05:38 2016 +0000
@@ -29,7 +29,6 @@
import java.io.IOException;
import java.io.PrintStream;
import java.io.UncheckedIOException;
-import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -38,7 +37,6 @@
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -52,7 +50,7 @@
import static java.util.Objects.*;
import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
/**
@@ -123,8 +121,9 @@
private final Set<Modifier> mods;
private final String name;
+ private final Version compiledVersion;
- private Requires(Set<Modifier> ms, String mn) {
+ private Requires(Set<Modifier> ms, String mn, Version v) {
if (ms.isEmpty()) {
ms = Collections.emptySet();
} else {
@@ -132,11 +131,13 @@
}
this.mods = ms;
this.name = mn;
+ this.compiledVersion = v;
}
- private Requires(Set<Modifier> ms, String mn, boolean unused) {
+ private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
this.mods = ms;
this.name = mn;
+ this.compiledVersion = v;
}
/**
@@ -158,12 +159,26 @@
}
/**
+ * Returns the version of the module if recorded at compile-time.
+ *
+ * @return The version of the module if recorded at compile-time
+ */
+ public Optional<Version> compiledVersion() {
+ return Optional.ofNullable(compiledVersion);
+ }
+
+ /**
* Compares this module dependence to another.
*
* <p> Two {@code Requires} objects are compared by comparing their
* module name lexicographically. Where the module names are equal then
* the sets of modifiers are compared based on a value computed from the
- * ordinal of each modifier. </p>
+ * ordinal of each modifier. Where the module names are equal and the
+ * set of modifiers are equal then the version of the modules recorded
+ * at compile-time are compared. When comparing the versions recorded
+ * at compile-time then a dependence that has a recorded version is
+ * considered to succeed a dependence that does not have a recorded
+ * version. </p>
*
* @return A negative integer, zero, or a positive integer if this module
* dependence is less than, equal to, or greater than the given
@@ -174,8 +189,24 @@
int c = this.name().compareTo(that.name());
if (c != 0)
return c;
- // same name, compare by modifiers
- return Long.compare(this.modsValue(), that.modsValue());
+
+ // modifiers
+ c = Long.compare(this.modsValue(), that.modsValue());
+ if (c != 0)
+ return c;
+
+ // compiledVersion
+ if (this.compiledVersion != null) {
+ if (that.compiledVersion != null)
+ c = this.compiledVersion.compareTo(that.compiledVersion);
+ else
+ c = 1;
+ } else {
+ if (that.compiledVersion != null)
+ c = -1;
+ }
+
+ return c;
}
/**
@@ -195,7 +226,9 @@
*
* <p> If the given object is not a {@code Requires} then this method
* returns {@code false}. Two module dependence objects are equal if
- * the module names are equal and set of modifiers are equal. </p>
+ * the module names are equal, set of modifiers are equal, and the
+ * compiled version of both modules is equal or not recorded for
+ * both modules. </p>
*
* <p> This method satisfies the general contract of the {@link
* java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -211,21 +244,25 @@
if (!(ob instanceof Requires))
return false;
Requires that = (Requires)ob;
- return (name.equals(that.name) && mods.equals(that.mods));
+ return name.equals(that.name) && mods.equals(that.mods)
+ && Objects.equals(compiledVersion, that.compiledVersion);
}
/**
* Computes a hash code for this module dependence.
*
- * <p> The hash code is based upon the module name and modifiers. It
- * satisfies the general contract of the {@link Object#hashCode
- * Object.hashCode} method. </p>
+ * <p> The hash code is based upon the module name, modifiers, and the
+ * module version if recorded at compile time. It satisfies the general
+ * contract of the {@link Object#hashCode Object.hashCode} method. </p>
*
* @return The hash-code value for this module dependence
*/
@Override
public int hashCode() {
- return name.hashCode() * 43 + mods.hashCode();
+ int hash = name.hashCode() * 43 + mods.hashCode();
+ if (compiledVersion != null)
+ hash = hash * 43 + compiledVersion.hashCode();
+ return hash;
}
/**
@@ -235,7 +272,13 @@
*/
@Override
public String toString() {
- return ModuleDescriptor.toString(mods, name);
+ String what;
+ if (compiledVersion != null) {
+ what = name() + " (@" + compiledVersion + ")";
+ } else {
+ what = name();
+ }
+ return ModuleDescriptor.toString(mods, what);
}
}
@@ -967,9 +1010,8 @@
}
-
- // From module declarations
private final String name;
+ private final Version version;
private final boolean open;
// Indicates if synthesised for a JAR file found on the module path
@@ -984,17 +1026,16 @@
private final Set<String> uses;
private final Set<Provides> provides;
- // "Extended" information, added post-compilation by tools
- private final Version version;
+ // Added post-compilation by tools
+ private final Set<String> packages;
private final String mainClass;
private final String osName;
private final String osArch;
private final String osVersion;
- private final Set<String> packages;
- private final ModuleHashes hashes;
private ModuleDescriptor(String name,
+ Version version,
boolean open,
boolean automatic,
boolean synthetic,
@@ -1003,16 +1044,14 @@
Set<Opens> opens,
Set<String> uses,
Set<Provides> provides,
- Version version,
+ Set<String> packages,
String mainClass,
String osName,
String osArch,
- String osVersion,
- Set<String> packages,
- ModuleHashes hashes)
+ String osVersion)
{
-
this.name = name;
+ this.version = version;
this.open = open;
this.automatic = automatic;
this.synthetic = synthetic;
@@ -1020,18 +1059,16 @@
assert (requires.stream().map(Requires::name).distinct().count()
== requires.size());
this.requires = emptyOrUnmodifiableSet(requires);
-
this.exports = emptyOrUnmodifiableSet(exports);
this.opens = emptyOrUnmodifiableSet(opens);
this.uses = emptyOrUnmodifiableSet(uses);
this.provides = emptyOrUnmodifiableSet(provides);
- this.version = version;
+
+ this.packages = emptyOrUnmodifiableSet(packages);
this.mainClass = mainClass;
this.osName = osName;
this.osArch = osArch;
this.osVersion = osVersion;
- this.hashes = hashes;
- this.packages = emptyOrUnmodifiableSet(packages);
}
/**
@@ -1039,6 +1076,7 @@
*/
ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
this.name = md.name;
+ this.version = md.version;
this.open = md.open;
this.automatic = md.automatic;
this.synthetic = md.synthetic;
@@ -1049,16 +1087,14 @@
this.uses = md.uses;
this.provides = md.provides;
- this.version = md.version;
+ Set<String> packages = new HashSet<>(md.packages);
+ packages.addAll(pkgs);
+ this.packages = emptyOrUnmodifiableSet(packages);
+
this.mainClass = md.mainClass;
this.osName = md.osName;
this.osArch = md.osArch;
this.osVersion = md.osVersion;
- this.hashes = null; // need to ignore
-
- Set<String> packages = new HashSet<>(md.packages);
- packages.addAll(pkgs);
- this.packages = emptyOrUnmodifiableSet(packages);
}
/**
@@ -1066,6 +1102,7 @@
* The arguments are pre-validated and sets are unmodifiable sets.
*/
ModuleDescriptor(String name,
+ Version version,
boolean open,
boolean automatic,
boolean synthetic,
@@ -1074,16 +1111,15 @@
Set<Opens> opens,
Set<String> uses,
Set<Provides> provides,
- Version version,
+ Set<String> packages,
String mainClass,
String osName,
String osArch,
String osVersion,
- Set<String> packages,
- ModuleHashes hashes,
int hashCode,
boolean unused) {
this.name = name;
+ this.version = version;
this.open = open;
this.automatic = automatic;
this.synthetic = synthetic;
@@ -1093,12 +1129,10 @@
this.uses = uses;
this.provides = provides;
this.packages = packages;
- this.version = version;
this.mainClass = mainClass;
this.osName = osName;
this.osArch = osArch;
this.osVersion = osVersion;
- this.hashes = hashes;
this.hash = hashCode;
}
@@ -1284,13 +1318,6 @@
return packages;
}
- /**
- * Returns the object with the hashes of other modules
- */
- Optional<ModuleHashes> hashes() {
- return Optional.ofNullable(hashes);
- }
-
/**
* A builder used for building {@link ModuleDescriptor} objects.
@@ -1317,15 +1344,13 @@
public static final class Builder {
final String name;
final boolean strict; // true if module names are checked
- boolean open;
+ final boolean open;
+ final boolean synthetic;
boolean automatic;
- boolean synthetic;
final Map<String, Requires> requires = new HashMap<>();
-
final Map<String, Exports> exports = new HashMap<>();
final Map<String, Opens> opens = new HashMap<>();
final Set<String> concealedPackages = new HashSet<>();
-
final Set<String> uses = new HashSet<>();
final Map<String, Provides> provides = new HashMap<>();
Version version;
@@ -1333,7 +1358,6 @@
String osArch;
String osVersion;
String mainClass;
- ModuleHashes hashes;
/**
* Initializes a new builder with the given module name.
@@ -1341,14 +1365,11 @@
* @param strict
* Indicates whether module names are checked or not
*/
- Builder(String name, boolean strict) {
- this.strict = strict;
+ Builder(String name, boolean strict, boolean open, boolean synthetic) {
this.name = (strict) ? requireModuleName(name) : name;
- }
-
- /* package */ Builder open(boolean open) {
+ this.strict = strict;
this.open = open;
- return this;
+ this.synthetic = synthetic;
}
/* package */ Builder automatic(boolean automatic) {
@@ -1356,10 +1377,20 @@
return this;
}
- /* package */ boolean isOpen() { return open; }
+ /**
+ * Returns the set of packages that are exported (unconditionally or
+ * unconditionally).
+ */
+ /* package */ Set<String> exportedPackages() {
+ return exports.keySet();
+ }
- /* package */ boolean isAutomatic() {
- return automatic;
+ /**
+ * Returns the set of packages that are opened (unconditionally or
+ * unconditionally).
+ */
+ /* package */Set<String> openPackages() {
+ return opens.keySet();
}
/**
@@ -1389,6 +1420,36 @@
/**
* Adds a dependence on a module with the given (and possibly empty)
+ * set of modifiers. The dependence includes the version of the
+ * module that that was recorded at compile-time.
+ *
+ * @param ms
+ * The set of modifiers
+ * @param mn
+ * The module name
+ * @param compiledVersion
+ * The version of the module recorded at compile-time
+ *
+ * @return This builder
+ *
+ * @throws IllegalArgumentException
+ * If the module name is {@code null}, is not a legal Java
+ * identifier, or is equal to the module name that this builder
+ * was initialized to build
+ * @throws IllegalStateException
+ * If the dependence on the module has already been declared
+ */
+ public Builder requires(Set<Requires.Modifier> ms,
+ String mn,
+ Version compiledVersion) {
+ Objects.requireNonNull(compiledVersion);
+ if (strict)
+ mn = requireModuleName(mn);
+ return requires(new Requires(ms, mn, compiledVersion));
+ }
+
+ /**
+ * Adds a dependence on a module with the given (and possibly empty)
* set of modifiers.
*
* @param ms
@@ -1408,7 +1469,7 @@
public Builder requires(Set<Requires.Modifier> ms, String mn) {
if (strict)
mn = requireModuleName(mn);
- return requires(new Requires(ms, mn));
+ return requires(new Requires(ms, mn, null));
}
/**
@@ -1705,17 +1766,6 @@
return opens(Collections.emptySet(), pn);
}
-
- // Used by ModuleInfo, after a packageFinder is invoked
- /* package */ Set<String> exportedAndOpenPackages() {
- if (opens.isEmpty())
- return exports.keySet();
- Set<String> result = new HashSet<>();
- result.addAll(exports.keySet());
- result.addAll(opens.keySet());
- return result;
- }
-
/**
* Adds a service dependence.
*
@@ -1789,7 +1839,6 @@
if (providerNames.isEmpty())
throw new IllegalArgumentException("Empty providers set");
providerNames.forEach(Checks::requireServiceProviderName);
-
provides.put(service, p);
return this;
}
@@ -1914,7 +1963,7 @@
* If {@code mainClass} is null or is not a legal Java identifier
*/
public Builder mainClass(String mc) {
- mainClass = requireJavaIdentifier("main class name", mc);
+ mainClass = requireBinaryName("main class name", mc);
return this;
}
@@ -1972,16 +2021,6 @@
return this;
}
- /* package */ Builder hashes(ModuleHashes hashes) {
- this.hashes = hashes;
- return this;
- }
-
- /* package */ Builder synthetic(boolean v) {
- this.synthetic = v;
- return this;
- }
-
/**
* Builds and returns a {@code ModuleDescriptor} from its components.
*
@@ -1990,7 +2029,9 @@
public ModuleDescriptor build() {
Set<Requires> requires = new HashSet<>(this.requires.values());
- Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+ Set<String> packages = new HashSet<>();
+ packages.addAll(exports.keySet());
+ packages.addAll(opens.keySet());
packages.addAll(concealedPackages);
Set<Exports> exports = new HashSet<>(this.exports.values());
@@ -1999,6 +2040,7 @@
Set<Provides> provides = new HashSet<>(this.provides.values());
return new ModuleDescriptor(name,
+ version,
open,
automatic,
synthetic,
@@ -2007,13 +2049,11 @@
opens,
uses,
provides,
- version,
+ packages,
mainClass,
osName,
osArch,
- osVersion,
- packages,
- hashes);
+ osVersion);
}
}
@@ -2088,8 +2128,7 @@
&& Objects.equals(osName, that.osName)
&& Objects.equals(osArch, that.osArch)
&& Objects.equals(osVersion, that.osVersion)
- && Objects.equals(packages, that.packages)
- && Objects.equals(hashes, that.hashes));
+ && Objects.equals(packages, that.packages));
}
private transient int hash; // cached hash code
@@ -2122,7 +2161,6 @@
hc = hc * 43 + Objects.hashCode(osArch);
hc = hc * 43 + Objects.hashCode(osVersion);
hc = hc * 43 + Objects.hashCode(packages);
- hc = hc * 43 + Objects.hashCode(hashes);
if (hc == 0)
hc = -1;
hash = hc;
@@ -2145,7 +2183,7 @@
if (!requires.isEmpty())
sb.append(", ").append(requires);
if (!uses.isEmpty())
- sb.append(", ").append(uses);
+ sb.append(", uses: ").append(uses);
if (!exports.isEmpty())
sb.append(", exports: ").append(exports);
if (!opens.isEmpty())
@@ -2171,7 +2209,7 @@
* identifier
*/
public static Builder module(String name) {
- return new Builder(name, true);
+ return new Builder(name, true, false, false);
}
/**
@@ -2199,7 +2237,7 @@
* identifier
*/
public static Builder openModule(String name) {
- return new Builder(name, true).open(true);
+ return new Builder(name, true, true, false);
}
/**
@@ -2221,7 +2259,7 @@
* @see ModuleFinder#of(Path[])
*/
public static Builder automaticModule(String name) {
- return new Builder(name, true).automatic(true);
+ return new Builder(name, true, false, false).automatic(true);
}
@@ -2263,7 +2301,7 @@
Supplier<Set<String>> packageFinder)
throws IOException
{
- return ModuleInfo.read(in, requireNonNull(packageFinder));
+ return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
}
/**
@@ -2281,7 +2319,7 @@
* If an I/O error occurs reading from the input stream
*/
public static ModuleDescriptor read(InputStream in) throws IOException {
- return ModuleInfo.read(in, null);
+ return ModuleInfo.read(in, null).descriptor();
}
/**
@@ -2320,7 +2358,7 @@
public static ModuleDescriptor read(ByteBuffer bb,
Supplier<Set<String>> packageFinder)
{
- return ModuleInfo.read(bb, requireNonNull(packageFinder));
+ return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
}
/**
@@ -2336,7 +2374,7 @@
* If an invalid module descriptor is detected
*/
public static ModuleDescriptor read(ByteBuffer bb) {
- return ModuleInfo.read(bb, null);
+ return ModuleInfo.read(bb, null).descriptor();
}
private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
@@ -2377,18 +2415,26 @@
jdk.internal.misc.SharedSecrets
.setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
@Override
- public Builder newModuleBuilder(String mn, boolean strict) {
- return new Builder(mn, strict);
+ public Builder newModuleBuilder(String mn,
+ boolean strict,
+ boolean open,
+ boolean synthetic) {
+ return new Builder(mn, strict, open, synthetic);
}
@Override
- public Builder newOpenModuleBuilder(String mn, boolean strict) {
- return new Builder(mn, strict).open(true);
+ public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
+ return builder.exportedPackages();
}
@Override
- public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
- return new Requires(ms, mn, true);
+ public Set<String> openPackages(ModuleDescriptor.Builder builder) {
+ return builder.openPackages();
+ }
+
+ @Override
+ public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
+ return new Requires(ms, mn, v, true);
}
@Override
@@ -2433,6 +2479,7 @@
@Override
public ModuleDescriptor newModuleDescriptor(String name,
+ Version version,
boolean open,
boolean automatic,
boolean synthetic,
@@ -2441,15 +2488,14 @@
Set<Opens> opens,
Set<String> uses,
Set<Provides> provides,
- Version version,
+ Set<String> packages,
String mainClass,
String osName,
String osArch,
String osVersion,
- Set<String> packages,
- ModuleHashes hashes,
int hashCode) {
return new ModuleDescriptor(name,
+ version,
open,
automatic,
synthetic,
@@ -2458,23 +2504,16 @@
opens,
uses,
provides,
- version,
+ packages,
mainClass,
osName,
osArch,
osVersion,
- packages,
- hashes,
hashCode,
false);
}
@Override
- public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
- return descriptor.hashes();
- }
-
- @Override
public Configuration resolveRequiresAndUses(ModuleFinder finder,
Collection<String> roots,
boolean check,
@@ -2482,20 +2521,6 @@
{
return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
}
-
- @Override
- public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> s) {
- return new ModuleReference(descriptor, location, s, true, null);
- }
-
- @Override
- public ModuleFinder newModulePath(Runtime.Version version,
- boolean isLinkPhase,
- Path... entries) {
- return new ModulePath(version, isLinkPhase, entries);
- }
});
}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Mon Dec 19 16:05:38 2016 +0000
@@ -42,6 +42,8 @@
import java.util.Optional;
import java.util.Set;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.SystemModuleFinder;
import sun.security.action.GetPropertyAction;
/**
@@ -137,7 +139,7 @@
/**
* Returns a module finder that locates the <em>system modules</em>. The
- * system modules are typically linked into the Java run-time image.
+ * system modules are the modules in the Java run-time image.
* The module finder will always find {@code java.base}.
*
* <p> If there is a security manager set then its {@link
@@ -166,7 +168,7 @@
Path modules = Paths.get(home, "lib", "modules");
if (Files.isRegularFile(modules)) {
- return new SystemModuleFinder();
+ return SystemModuleFinder.getInstance();
} else {
Path mlib = Paths.get(home, "modules");
if (Files.isDirectory(mlib)) {
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,899 +0,0 @@
-/*
- * Copyright (c) 2014, 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.DataInput;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Builder;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Opens;
-import java.nio.ByteBuffer;
-import java.nio.BufferUnderflowException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
-
-import static jdk.internal.module.ClassFileConstants.*;
-
-
-/**
- * Read module information from a {@code module-info} class file.
- *
- * @implNote The rationale for the hand-coded reader is startup performance
- * and fine control over the throwing of InvalidModuleDescriptorException.
- */
-
-final class ModuleInfo {
-
- // supplies the set of packages when ModulePackages attribute not present
- private final Supplier<Set<String>> packageFinder;
-
- // indicates if the ModuleHashes attribute should be parsed
- private final boolean parseHashes;
-
- private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
- packageFinder = pf;
- parseHashes = ph;
- }
-
- private ModuleInfo(Supplier<Set<String>> pf) {
- this(pf, true);
- }
-
- /**
- * Reads a {@code module-info.class} from the given input stream.
- *
- * @throws InvalidModuleDescriptorException
- * @throws IOException
- */
- public static ModuleDescriptor read(InputStream in,
- Supplier<Set<String>> pf)
- throws IOException
- {
- try {
- return new ModuleInfo(pf).doRead(new DataInputStream(in));
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw invalidModuleDescriptor(e.getMessage());
- } catch (EOFException x) {
- throw truncatedModuleDescriptor();
- }
- }
-
- /**
- * Reads a {@code module-info.class} from the given byte buffer.
- *
- * @throws InvalidModuleDescriptorException
- * @throws UncheckedIOException
- */
- public static ModuleDescriptor read(ByteBuffer bb,
- Supplier<Set<String>> pf)
- {
- try {
- return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw invalidModuleDescriptor(e.getMessage());
- } catch (EOFException x) {
- throw truncatedModuleDescriptor();
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- }
-
- /**
- * Reads a {@code module-info.class} from the given byte buffer
- * but ignore the {@code ModuleHashes} attribute.
- *
- * @throws InvalidModuleDescriptorException
- * @throws UncheckedIOException
- */
- static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
- Supplier<Set<String>> pf)
- {
- try {
- return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw invalidModuleDescriptor(e.getMessage());
- } catch (EOFException x) {
- throw truncatedModuleDescriptor();
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- }
-
- /**
- * Reads the input as a module-info class file.
- *
- * @throws IOException
- * @throws InvalidModuleDescriptorException
- * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
- * because an identifier is not a legal Java identifier, duplicate
- * exports, and many other reasons
- */
- private ModuleDescriptor doRead(DataInput in) throws IOException {
-
- int magic = in.readInt();
- if (magic != 0xCAFEBABE)
- throw invalidModuleDescriptor("Bad magic number");
-
- int minor_version = in.readUnsignedShort();
- int major_version = in.readUnsignedShort();
- if (major_version < 53) {
- throw invalidModuleDescriptor("Must be >= 53.0");
- }
-
- ConstantPool cpool = new ConstantPool(in);
-
- int access_flags = in.readUnsignedShort();
- if (access_flags != ACC_MODULE)
- throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
-
- int this_class = in.readUnsignedShort();
- if (this_class != 0)
- throw invalidModuleDescriptor("this_class must be 0");
-
- int super_class = in.readUnsignedShort();
- if (super_class > 0)
- throw invalidModuleDescriptor("bad #super_class");
-
- int interfaces_count = in.readUnsignedShort();
- if (interfaces_count > 0)
- throw invalidModuleDescriptor("Bad #interfaces");
-
- int fields_count = in.readUnsignedShort();
- if (fields_count > 0)
- throw invalidModuleDescriptor("Bad #fields");
-
- int methods_count = in.readUnsignedShort();
- if (methods_count > 0)
- throw invalidModuleDescriptor("Bad #methods");
-
- int attributes_count = in.readUnsignedShort();
-
- // the names of the attributes found in the class file
- Set<String> attributes = new HashSet<>();
-
- Builder builder = null;
- Set<String> packages = null;
- String version = null;
- String mainClass = null;
- String[] osValues = null;
- ModuleHashes hashes = null;
-
- for (int i = 0; i < attributes_count ; i++) {
- int name_index = in.readUnsignedShort();
- String attribute_name = cpool.getUtf8(name_index);
- int length = in.readInt();
-
- boolean added = attributes.add(attribute_name);
- if (!added && isAttributeAtMostOnce(attribute_name)) {
- throw invalidModuleDescriptor("More than one "
- + attribute_name + " attribute");
- }
-
- switch (attribute_name) {
-
- case MODULE :
- builder = readModuleAttribute(in, cpool);
- break;
-
- case MODULE_PACKAGES :
- packages = readModulePackagesAttribute(in, cpool);
- break;
-
- case MODULE_VERSION :
- version = readModuleVersionAttribute(in, cpool);
- break;
-
- case MODULE_MAIN_CLASS :
- mainClass = readModuleMainClassAttribute(in, cpool);
- break;
-
- case MODULE_TARGET :
- osValues = readModuleTargetAttribute(in, cpool);
- break;
-
- case MODULE_HASHES :
- if (parseHashes) {
- hashes = readModuleHashesAttribute(in, cpool);
- } else {
- in.skipBytes(length);
- }
- break;
-
- default:
- if (isAttributeDisallowed(attribute_name)) {
- throw invalidModuleDescriptor(attribute_name
- + " attribute not allowed");
- } else {
- in.skipBytes(length);
- }
-
- }
- }
-
- // the Module attribute is required
- if (builder == null) {
- throw invalidModuleDescriptor(MODULE + " attribute not found");
- }
-
- // If the ModulePackages attribute is not present then the packageFinder
- // is used to find the set of packages
- boolean usedPackageFinder = false;
- if (packages == null && packageFinder != null) {
- try {
- packages = new HashSet<>(packageFinder.get());
- } catch (UncheckedIOException x) {
- throw x.getCause();
- }
- usedPackageFinder = true;
- }
- if (packages != null) {
- for (String pn : builder.exportedAndOpenPackages()) {
- if (!packages.contains(pn)) {
- String tail;
- if (usedPackageFinder) {
- tail = " not found by package finder";
- } else {
- tail = " missing from ModulePackages attribute";
- }
- throw invalidModuleDescriptor("Package " + pn + tail);
- }
- packages.remove(pn);
- }
- builder.contains(packages);
- }
-
- if (version != null)
- builder.version(version);
- if (mainClass != null)
- builder.mainClass(mainClass);
- if (osValues != null) {
- if (osValues[0] != null) builder.osName(osValues[0]);
- if (osValues[1] != null) builder.osArch(osValues[1]);
- if (osValues[2] != null) builder.osVersion(osValues[2]);
- }
- if (hashes != null)
- builder.hashes(hashes);
-
- return builder.build();
- }
-
- /**
- * Reads the Module attribute, returning the ModuleDescriptor.Builder to
- * build the corresponding ModuleDescriptor.
- */
- private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- // module_name
- int module_name_index = in.readUnsignedShort();
- String mn = cpool.getUtf8AsBinaryName(module_name_index);
-
- Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
-
- int module_flags = in.readUnsignedShort();
- boolean open = ((module_flags & ACC_OPEN) != 0);
- if (open)
- builder.open(true);
- if ((module_flags & ACC_SYNTHETIC) != 0)
- builder.synthetic(true);
-
- int requires_count = in.readUnsignedShort();
- boolean requiresJavaBase = false;
- for (int i=0; i<requires_count; i++) {
- int index = in.readUnsignedShort();
- int flags = in.readUnsignedShort();
- String dn = cpool.getUtf8AsBinaryName(index);
- Set<Requires.Modifier> mods;
- if (flags == 0) {
- mods = Collections.emptySet();
- } else {
- mods = new HashSet<>();
- if ((flags & ACC_TRANSITIVE) != 0)
- mods.add(Requires.Modifier.TRANSITIVE);
- if ((flags & ACC_STATIC_PHASE) != 0)
- mods.add(Requires.Modifier.STATIC);
- if ((flags & ACC_SYNTHETIC) != 0)
- mods.add(Requires.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
- mods.add(Requires.Modifier.MANDATED);
- }
- builder.requires(mods, dn);
- if (dn.equals("java.base"))
- requiresJavaBase = true;
- }
- if (mn.equals("java.base")) {
- if (requires_count > 0) {
- throw invalidModuleDescriptor("The requires table for java.base"
- + " must be 0 length");
- }
- } else if (!requiresJavaBase) {
- throw invalidModuleDescriptor("The requires table must have"
- + " an entry for java.base");
- }
-
- int exports_count = in.readUnsignedShort();
- if (exports_count > 0) {
- for (int i=0; i<exports_count; i++) {
- int index = in.readUnsignedShort();
- String pkg = cpool.getUtf8AsBinaryName(index);
-
- Set<Exports.Modifier> mods;
- int flags = in.readUnsignedShort();
- if (flags == 0) {
- mods = Collections.emptySet();
- } else {
- mods = new HashSet<>();
- if ((flags & ACC_SYNTHETIC) != 0)
- mods.add(Exports.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
- mods.add(Exports.Modifier.MANDATED);
- }
-
- int exports_to_count = in.readUnsignedShort();
- if (exports_to_count > 0) {
- Set<String> targets = new HashSet<>(exports_to_count);
- for (int j=0; j<exports_to_count; j++) {
- int exports_to_index = in.readUnsignedShort();
- targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
- }
- builder.exports(mods, pkg, targets);
- } else {
- builder.exports(mods, pkg);
- }
- }
- }
-
- int opens_count = in.readUnsignedShort();
- if (opens_count > 0) {
- if (open) {
- throw invalidModuleDescriptor("The opens table for an open"
- + " module must be 0 length");
- }
- for (int i=0; i<opens_count; i++) {
- int index = in.readUnsignedShort();
- String pkg = cpool.getUtf8AsBinaryName(index);
-
- Set<Opens.Modifier> mods;
- int flags = in.readUnsignedShort();
- if (flags == 0) {
- mods = Collections.emptySet();
- } else {
- mods = new HashSet<>();
- if ((flags & ACC_SYNTHETIC) != 0)
- mods.add(Opens.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
- mods.add(Opens.Modifier.MANDATED);
- }
-
- int open_to_count = in.readUnsignedShort();
- if (open_to_count > 0) {
- Set<String> targets = new HashSet<>(open_to_count);
- for (int j=0; j<open_to_count; j++) {
- int opens_to_index = in.readUnsignedShort();
- targets.add(cpool.getUtf8AsBinaryName(opens_to_index));
- }
- builder.opens(mods, pkg, targets);
- } else {
- builder.opens(mods, pkg);
- }
- }
- }
-
- int uses_count = in.readUnsignedShort();
- if (uses_count > 0) {
- for (int i=0; i<uses_count; i++) {
- int index = in.readUnsignedShort();
- String sn = cpool.getClassNameAsBinaryName(index);
- builder.uses(sn);
- }
- }
-
- int provides_count = in.readUnsignedShort();
- if (provides_count > 0) {
- for (int i=0; i<provides_count; i++) {
- int index = in.readUnsignedShort();
- String sn = cpool.getClassNameAsBinaryName(index);
- int with_count = in.readUnsignedShort();
- List<String> providers = new ArrayList<>(with_count);
- for (int j=0; j<with_count; j++) {
- index = in.readUnsignedShort();
- String pn = cpool.getClassNameAsBinaryName(index);
- providers.add(pn);
- }
- builder.provides(sn, providers);
- }
- }
-
- return builder;
- }
-
- /**
- * Reads the ModulePackages attribute
- */
- private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- int package_count = in.readUnsignedShort();
- Set<String> packages = new HashSet<>(package_count);
- for (int i=0; i<package_count; i++) {
- int index = in.readUnsignedShort();
- String pn = cpool.getUtf8AsBinaryName(index);
- packages.add(pn);
- }
- return packages;
- }
-
- /**
- * Reads the ModuleVersion attribute
- */
- private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- int index = in.readUnsignedShort();
- return cpool.getUtf8(index);
- }
-
- /**
- * Reads the ModuleMainClass attribute
- */
- private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- int index = in.readUnsignedShort();
- return cpool.getClassNameAsBinaryName(index);
- }
-
- /**
- * Reads the ModuleTarget attribute
- */
- private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- String[] values = new String[3];
-
- int name_index = in.readUnsignedShort();
- if (name_index != 0)
- values[0] = cpool.getUtf8(name_index);
-
- int arch_index = in.readUnsignedShort();
- if (arch_index != 0)
- values[1] = cpool.getUtf8(arch_index);
-
- int version_index = in.readUnsignedShort();
- if (version_index != 0)
- values[2] = cpool.getUtf8(version_index);
-
- return values;
- }
-
-
- /**
- * Reads the ModuleHashes attribute
- */
- private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
- throws IOException
- {
- int algorithm_index = in.readUnsignedShort();
- String algorithm = cpool.getUtf8(algorithm_index);
-
- int hash_count = in.readUnsignedShort();
- Map<String, byte[]> map = new HashMap<>(hash_count);
- for (int i=0; i<hash_count; i++) {
- int module_name_index = in.readUnsignedShort();
- String mn = cpool.getUtf8AsBinaryName(module_name_index);
- int hash_length = in.readUnsignedShort();
- if (hash_length == 0) {
- throw invalidModuleDescriptor("hash_length == 0");
- }
- byte[] hash = new byte[hash_length];
- in.readFully(hash);
- map.put(mn, hash);
- }
-
- return new ModuleHashes(algorithm, map);
- }
-
-
- /**
- * Returns true if the given attribute can be present at most once
- * in the class file. Returns false otherwise.
- */
- private static boolean isAttributeAtMostOnce(String name) {
-
- if (name.equals(MODULE) ||
- name.equals(SOURCE_FILE) ||
- name.equals(SDE) ||
- name.equals(MODULE_PACKAGES) ||
- name.equals(MODULE_VERSION) ||
- name.equals(MODULE_MAIN_CLASS) ||
- name.equals(MODULE_TARGET) ||
- name.equals(MODULE_HASHES))
- return true;
-
- return false;
- }
-
- /**
- * Return true if the given attribute name is the name of a pre-defined
- * attribute that is not allowed in the class file.
- *
- * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
- * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
- */
- private static boolean isAttributeDisallowed(String name) {
- Set<String> notAllowed = predefinedNotAllowed;
- if (notAllowed == null) {
- notAllowed = Set.of(
- "ConstantValue",
- "Code",
- "StackMapTable",
- "Exceptions",
- "EnclosingMethod",
- "Signature",
- "LineNumberTable",
- "LocalVariableTable",
- "LocalVariableTypeTable",
- "RuntimeVisibleParameterAnnotations",
- "RuntimeInvisibleParameterAnnotations",
- "RuntimeVisibleTypeAnnotations",
- "RuntimeInvisibleTypeAnnotations",
- "Synthetic",
- "AnnotationDefault",
- "BootstrapMethods",
- "MethodParameters");
- predefinedNotAllowed = notAllowed;
- }
- return notAllowed.contains(name);
- }
-
- // lazily created set the pre-defined attributes that are not allowed
- private static volatile Set<String> predefinedNotAllowed;
-
-
- /**
- * The constant pool in a class file.
- */
- private static class ConstantPool {
- static final int CONSTANT_Utf8 = 1;
- static final int CONSTANT_Integer = 3;
- static final int CONSTANT_Float = 4;
- static final int CONSTANT_Long = 5;
- static final int CONSTANT_Double = 6;
- static final int CONSTANT_Class = 7;
- static final int CONSTANT_String = 8;
- static final int CONSTANT_Fieldref = 9;
- static final int CONSTANT_Methodref = 10;
- static final int CONSTANT_InterfaceMethodref = 11;
- static final int CONSTANT_NameAndType = 12;
- static final int CONSTANT_MethodHandle = 15;
- static final int CONSTANT_MethodType = 16;
- static final int CONSTANT_InvokeDynamic = 18;
-
- private static class Entry {
- protected Entry(int tag) {
- this.tag = tag;
- }
- final int tag;
- }
-
- private static class IndexEntry extends Entry {
- IndexEntry(int tag, int index) {
- super(tag);
- this.index = index;
- }
- final int index;
- }
-
- private static class Index2Entry extends Entry {
- Index2Entry(int tag, int index1, int index2) {
- super(tag);
- this.index1 = index1;
- this.index2 = index2;
- }
- final int index1, index2;
- }
-
- private static class ValueEntry extends Entry {
- ValueEntry(int tag, Object value) {
- super(tag);
- this.value = value;
- }
- final Object value;
- }
-
- final Entry[] pool;
-
- ConstantPool(DataInput in) throws IOException {
- int count = in.readUnsignedShort();
- pool = new Entry[count];
-
- for (int i = 1; i < count; i++) {
- int tag = in.readUnsignedByte();
- switch (tag) {
-
- case CONSTANT_Utf8:
- String svalue = in.readUTF();
- pool[i] = new ValueEntry(tag, svalue);
- break;
-
- case CONSTANT_Class:
- case CONSTANT_String:
- int index = in.readUnsignedShort();
- pool[i] = new IndexEntry(tag, index);
- break;
-
- case CONSTANT_Double:
- double dvalue = in.readDouble();
- pool[i] = new ValueEntry(tag, dvalue);
- i++;
- break;
-
- case CONSTANT_Fieldref:
- case CONSTANT_InterfaceMethodref:
- case CONSTANT_Methodref:
- case CONSTANT_InvokeDynamic:
- case CONSTANT_NameAndType:
- int index1 = in.readUnsignedShort();
- int index2 = in.readUnsignedShort();
- pool[i] = new Index2Entry(tag, index1, index2);
- break;
-
- case CONSTANT_MethodHandle:
- int refKind = in.readUnsignedByte();
- index = in.readUnsignedShort();
- pool[i] = new Index2Entry(tag, refKind, index);
- break;
-
- case CONSTANT_MethodType:
- index = in.readUnsignedShort();
- pool[i] = new IndexEntry(tag, index);
- break;
-
- case CONSTANT_Float:
- float fvalue = in.readFloat();
- pool[i] = new ValueEntry(tag, fvalue);
- break;
-
- case CONSTANT_Integer:
- int ivalue = in.readInt();
- pool[i] = new ValueEntry(tag, ivalue);
- break;
-
- case CONSTANT_Long:
- long lvalue = in.readLong();
- pool[i] = new ValueEntry(tag, lvalue);
- i++;
- break;
-
- default:
- throw invalidModuleDescriptor("Bad constant pool entry: "
- + i);
- }
- }
- }
-
- String getClassName(int index) {
- checkIndex(index);
- Entry e = pool[index];
- if (e.tag != CONSTANT_Class) {
- throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
- + index);
- }
- return getUtf8(((IndexEntry) e).index);
- }
-
- String getClassNameAsBinaryName(int index) {
- String value = getClassName(index);
- return value.replace('/', '.'); // internal form -> binary name
- }
-
- String getUtf8(int index) {
- checkIndex(index);
- Entry e = pool[index];
- if (e.tag != CONSTANT_Utf8) {
- throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
- + index);
- }
- return (String) (((ValueEntry) e).value);
- }
-
- String getUtf8AsBinaryName(int index) {
- String value = getUtf8(index);
- return value.replace('/', '.'); // internal -> binary name
- }
-
- void checkIndex(int index) {
- if (index < 1 || index >= pool.length)
- throw invalidModuleDescriptor("Index into constant pool out of range");
- }
- }
-
- /**
- * A DataInput implementation that reads from a ByteBuffer.
- */
- private static class DataInputWrapper implements DataInput {
- private final ByteBuffer bb;
-
- DataInputWrapper(ByteBuffer bb) {
- this.bb = bb;
- }
-
- @Override
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- @Override
- public void readFully(byte b[], int off, int len) throws IOException {
- try {
- bb.get(b, off, len);
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public int skipBytes(int n) {
- int skip = Math.min(n, bb.remaining());
- bb.position(bb.position() + skip);
- return skip;
- }
-
- @Override
- public boolean readBoolean() throws IOException {
- try {
- int ch = bb.get();
- return (ch != 0);
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public byte readByte() throws IOException {
- try {
- return bb.get();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public int readUnsignedByte() throws IOException {
- try {
- return ((int) bb.get()) & 0xff;
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public short readShort() throws IOException {
- try {
- return bb.getShort();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public int readUnsignedShort() throws IOException {
- try {
- return ((int) bb.getShort()) & 0xffff;
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public char readChar() throws IOException {
- try {
- return bb.getChar();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public int readInt() throws IOException {
- try {
- return bb.getInt();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public long readLong() throws IOException {
- try {
- return bb.getLong();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public float readFloat() throws IOException {
- try {
- return bb.getFloat();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public double readDouble() throws IOException {
- try {
- return bb.getDouble();
- } catch (BufferUnderflowException e) {
- throw new EOFException(e.getMessage());
- }
- }
-
- @Override
- public String readLine() {
- throw new RuntimeException("not implemented");
- }
-
- @Override
- public String readUTF() throws IOException {
- // ### Need to measure the performance and feasibility of using
- // the UTF-8 decoder instead.
- return DataInputStream.readUTF(this);
- }
- }
-
- /**
- * Returns an InvalidModuleDescriptorException with the given detail
- * message
- */
- private static InvalidModuleDescriptorException
- invalidModuleDescriptor(String msg) {
- return new InvalidModuleDescriptorException(msg);
- }
-
- /**
- * Returns an InvalidModuleDescriptorException with a detail message to
- * indicate that the class file is truncated.
- */
- private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
- return invalidModuleDescriptor("Truncated module-info.class");
- }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,681 +0,0 @@
-/*
- * Copyright (c) 2014, 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.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.jmod.JmodFile.Section;
-import jdk.internal.module.Checks;
-import jdk.internal.perf.PerfCounter;
-import jdk.internal.util.jar.VersionedStream;
-
-
-/**
- * A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
- */
-
-class ModulePath implements ModuleFinder {
- private static final String MODULE_INFO = "module-info.class";
-
- // the version to use for multi-release modular JARs
- private final Runtime.Version releaseVersion;
-
- // true for the link phase (supports modules packaged in JMOD format)
- private final boolean isLinkPhase;
-
- // the entries on this module path
- private final Path[] entries;
- private int next;
-
- // map of module name to module reference map for modules already located
- private final Map<String, ModuleReference> cachedModules = new HashMap<>();
-
- ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
- this.releaseVersion = version;
- this.isLinkPhase = isLinkPhase;
- this.entries = entries.clone();
- for (Path entry : this.entries) {
- Objects.requireNonNull(entry);
- }
- }
-
- ModulePath(Path... entries) {
- this(JarFile.runtimeVersion(), false, entries);
- }
-
- @Override
- public Optional<ModuleReference> find(String name) {
- Objects.requireNonNull(name);
-
- // try cached modules
- ModuleReference m = cachedModules.get(name);
- if (m != null)
- return Optional.of(m);
-
- // the module may not have been encountered yet
- while (hasNextEntry()) {
- scanNextEntry();
- m = cachedModules.get(name);
- if (m != null)
- return Optional.of(m);
- }
- return Optional.empty();
- }
-
- @Override
- public Set<ModuleReference> findAll() {
- // need to ensure that all entries have been scanned
- while (hasNextEntry()) {
- scanNextEntry();
- }
- return cachedModules.values().stream().collect(Collectors.toSet());
- }
-
- /**
- * Returns {@code true} if there are additional entries to scan
- */
- private boolean hasNextEntry() {
- return next < entries.length;
- }
-
- /**
- * Scans the next entry on the module path. A no-op if all entries have
- * already been scanned.
- *
- * @throws FindException if an error occurs scanning the next entry
- */
- private void scanNextEntry() {
- if (hasNextEntry()) {
-
- long t0 = System.nanoTime();
-
- Path entry = entries[next];
- Map<String, ModuleReference> modules = scan(entry);
- next++;
-
- // update cache, ignoring duplicates
- int initialSize = cachedModules.size();
- for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
- cachedModules.putIfAbsent(e.getKey(), e.getValue());
- }
-
- // update counters
- int added = cachedModules.size() - initialSize;
- moduleCount.add(added);
-
- scanTime.addElapsedTimeFrom(t0);
- }
- }
-
-
- /**
- * Scan the given module path entry. If the entry is a directory then it is
- * a directory of modules or an exploded module. If the entry is a regular
- * file then it is assumed to be a packaged module.
- *
- * @throws FindException if an error occurs scanning the entry
- */
- private Map<String, ModuleReference> scan(Path entry) {
-
- BasicFileAttributes attrs;
- try {
- attrs = Files.readAttributes(entry, BasicFileAttributes.class);
- } catch (NoSuchFileException e) {
- return Collections.emptyMap();
- } catch (IOException ioe) {
- throw new FindException(ioe);
- }
-
- try {
-
- if (attrs.isDirectory()) {
- Path mi = entry.resolve(MODULE_INFO);
- if (!Files.exists(mi)) {
- // does not exist or unable to determine so assume a
- // directory of modules
- return scanDirectory(entry);
- }
- }
-
- // packaged or exploded module
- ModuleReference mref = readModule(entry, attrs);
- if (mref != null) {
- String name = mref.descriptor().name();
- return Collections.singletonMap(name, mref);
- } else {
- // skipped
- return Collections.emptyMap();
- }
-
- } catch (IOException ioe) {
- throw new FindException(ioe);
- }
- }
-
-
- /**
- * Scans the given directory for packaged or exploded modules.
- *
- * @return a map of module name to ModuleReference for the modules found
- * in the directory
- *
- * @throws IOException if an I/O error occurs
- * @throws FindException if an error occurs scanning the entry or the
- * directory contains two or more modules with the same name
- */
- private Map<String, ModuleReference> scanDirectory(Path dir)
- throws IOException
- {
- // The map of name -> mref of modules found in this directory.
- Map<String, ModuleReference> nameToReference = new HashMap<>();
-
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
- for (Path entry : stream) {
- BasicFileAttributes attrs;
- try {
- attrs = Files.readAttributes(entry, BasicFileAttributes.class);
- } catch (NoSuchFileException ignore) {
- // file has been removed or moved, ignore for now
- continue;
- }
-
- ModuleReference mref = readModule(entry, attrs);
-
- // module found
- if (mref != null) {
- // can have at most one version of a module in the directory
- String name = mref.descriptor().name();
- ModuleReference previous = nameToReference.put(name, mref);
- if (previous != null) {
- String fn1 = fileName(mref);
- String fn2 = fileName(previous);
- throw new FindException("Two versions of module "
- + name + " found in " + dir
- + " (" + fn1 + " and " + fn2 + ")");
- }
- }
- }
- }
-
- return nameToReference;
- }
-
-
- /**
- * Locates a packaged or exploded module, returning a {@code ModuleReference}
- * to the module. Returns {@code null} if the entry is skipped because it is
- * to a directory that does not contain a module-info.class or it's a hidden
- * file.
- *
- * @throws IOException if an I/O error occurs
- * @throws FindException if the file is not recognized as a module or an
- * error occurs parsing its module descriptor
- */
- private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
- throws IOException
- {
- try {
-
- if (attrs.isDirectory()) {
- return readExplodedModule(entry); // may return null
- }
-
- String fn = entry.getFileName().toString();
- if (attrs.isRegularFile()) {
- if (fn.endsWith(".jar")) {
- return readJar(entry);
- } else if (fn.endsWith(".jmod")) {
- if (isLinkPhase)
- return readJMod(entry);
- throw new FindException("JMOD files not supported: " + entry);
- }
- }
-
- // skip hidden files
- if (fn.startsWith(".") || Files.isHidden(entry)) {
- return null;
- } else {
- throw new FindException("Unrecognized module: " + entry);
- }
-
- } catch (InvalidModuleDescriptorException e) {
- throw new FindException("Error reading module: " + entry, e);
- }
- }
-
-
- /**
- * Returns a string with the file name of the module if possible.
- * If the module location is not a file URI then return the URI
- * as a string.
- */
- private String fileName(ModuleReference mref) {
- URI uri = mref.location().orElse(null);
- if (uri != null) {
- if (uri.getScheme().equalsIgnoreCase("file")) {
- Path file = Paths.get(uri);
- return file.getFileName().toString();
- } else {
- return uri.toString();
- }
- } else {
- return "<unknown>";
- }
- }
-
- // -- jmod files --
-
- private Set<String> jmodPackages(JmodFile jf) {
- return jf.stream()
- .filter(e -> e.section() == Section.CLASSES)
- .map(JmodFile.Entry::name)
- .map(this::toPackageName)
- .flatMap(Optional::stream)
- .collect(Collectors.toSet());
- }
-
- /**
- * Returns a {@code ModuleReference} to a module in jmod file on the
- * file system.
- *
- * @throws IOException
- * @throws InvalidModuleDescriptorException
- */
- private ModuleReference readJMod(Path file) throws IOException {
- try (JmodFile jf = new JmodFile(file)) {
- ModuleDescriptor md;
- try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
- md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
- }
- return ModuleReferences.newJModModule(md, file);
- }
- }
-
-
- // -- JAR files --
-
- private static final String SERVICES_PREFIX = "META-INF/services/";
-
- /**
- * Returns the service type corresponding to the name of a services
- * configuration file if it is a valid Java identifier.
- *
- * For example, if called with "META-INF/services/p.S" then this method
- * returns a container with the value "p.S".
- */
- private Optional<String> toServiceName(String cf) {
- assert cf.startsWith(SERVICES_PREFIX);
- int index = cf.lastIndexOf("/") + 1;
- if (index < cf.length()) {
- String prefix = cf.substring(0, index);
- if (prefix.equals(SERVICES_PREFIX)) {
- String sn = cf.substring(index);
- if (Checks.isJavaIdentifier(sn))
- return Optional.of(sn);
- }
- }
- return Optional.empty();
- }
-
- /**
- * Reads the next line from the given reader and trims it of comments and
- * leading/trailing white space.
- *
- * Returns null if the reader is at EOF.
- */
- private String nextLine(BufferedReader reader) throws IOException {
- String ln = reader.readLine();
- if (ln != null) {
- int ci = ln.indexOf('#');
- if (ci >= 0)
- ln = ln.substring(0, ci);
- ln = ln.trim();
- }
- return ln;
- }
-
- /**
- * Treat the given JAR file as a module as follows:
- *
- * 1. The module name (and optionally the version) is derived from the file
- * name of the JAR file
- * 2. All packages are exported and open
- * 3. It has no non-exported/non-open packages
- * 4. The contents of any META-INF/services configuration files are mapped
- * to "provides" declarations
- * 5. The Main-Class attribute in the main attributes of the JAR manifest
- * is mapped to the module descriptor mainClass
- */
- private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
- throws IOException
- {
- // Derive module name and version from JAR file name
-
- String fn = jf.getName();
- int i = fn.lastIndexOf(File.separator);
- if (i != -1)
- fn = fn.substring(i+1);
-
- // drop .jar
- String mn = fn.substring(0, fn.length()-4);
- String vs = null;
-
- // find first occurrence of -${NUMBER}. or -${NUMBER}$
- Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
- if (matcher.find()) {
- int start = matcher.start();
-
- // attempt to parse the tail as a version string
- try {
- String tail = mn.substring(start+1);
- ModuleDescriptor.Version.parse(tail);
- vs = tail;
- } catch (IllegalArgumentException ignore) { }
-
- mn = mn.substring(0, start);
- }
-
- // finally clean up the module name
- mn = cleanModuleName(mn);
-
- // Builder throws IAE if module name is empty or invalid
- ModuleDescriptor.Builder builder
- = ModuleDescriptor.automaticModule(mn)
- .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
- if (vs != null)
- builder.version(vs);
-
- // scan the names of the entries in the JAR file
- Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
- .filter(e -> !e.isDirectory())
- .map(JarEntry::getName)
- .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
- Collectors.toSet()));
-
- Set<String> resources = map.get(Boolean.FALSE);
- Set<String> configFiles = map.get(Boolean.TRUE);
- // all packages are exported and open
- resources.stream()
- .map(this::toPackageName)
- .flatMap(Optional::stream)
- .distinct()
- .forEach(pn -> builder.exports(pn).opens(pn));
-
- // map names of service configuration files to service names
- Set<String> serviceNames = configFiles.stream()
- .map(this::toServiceName)
- .flatMap(Optional::stream)
- .collect(Collectors.toSet());
-
- // parse each service configuration file
- for (String sn : serviceNames) {
- JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
- List<String> providerClasses = new ArrayList<>();
- try (InputStream in = jf.getInputStream(entry)) {
- BufferedReader reader
- = new BufferedReader(new InputStreamReader(in, "UTF-8"));
- String cn;
- while ((cn = nextLine(reader)) != null) {
- if (cn.length() > 0) {
- providerClasses.add(cn);
- }
- }
- }
- if (!providerClasses.isEmpty())
- builder.provides(sn, providerClasses);
- }
-
- // Main-Class attribute if it exists
- Manifest man = jf.getManifest();
- if (man != null) {
- Attributes attrs = man.getMainAttributes();
- String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
- if (mainClass != null)
- builder.mainClass(mainClass.replace("/", "."));
- }
-
- return builder.build();
- }
-
- /**
- * Patterns used to derive the module name from a JAR file name.
- */
- private static class Patterns {
- static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
- static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
- static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
- static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
- static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
- static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
- }
-
- /**
- * Clean up candidate module name derived from a JAR file name.
- */
- private static String cleanModuleName(String mn) {
- // drop trailing version from name
- mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
-
- // replace non-alphanumeric
- mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
-
- // collapse repeating dots
- mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
-
- // drop leading dots
- if (mn.length() > 0 && mn.charAt(0) == '.')
- mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
-
- // drop trailing dots
- int len = mn.length();
- if (len > 0 && mn.charAt(len-1) == '.')
- mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
-
- return mn;
- }
-
- private Set<String> jarPackages(JarFile jf) {
- return VersionedStream.stream(jf)
- .filter(e -> !e.isDirectory())
- .map(JarEntry::getName)
- .map(this::toPackageName)
- .flatMap(Optional::stream)
- .collect(Collectors.toSet());
- }
-
- /**
- * Returns a {@code ModuleReference} to a module in modular JAR file on
- * the file system.
- *
- * @throws IOException
- * @throws FindException
- * @throws InvalidModuleDescriptorException
- */
- private ModuleReference readJar(Path file) throws IOException {
- try (JarFile jf = new JarFile(file.toFile(),
- true, // verify
- ZipFile.OPEN_READ,
- releaseVersion))
- {
- ModuleDescriptor md;
- JarEntry entry = jf.getJarEntry(MODULE_INFO);
- if (entry == null) {
-
- // no module-info.class so treat it as automatic module
- try {
- md = deriveModuleDescriptor(jf);
- } catch (IllegalArgumentException iae) {
- throw new FindException(
- "Unable to derive module descriptor for: "
- + jf.getName(), iae);
- }
-
- } else {
- md = ModuleDescriptor.read(jf.getInputStream(entry),
- () -> jarPackages(jf));
- }
-
- return ModuleReferences.newJarModule(md, file);
- }
- }
-
-
- // -- exploded directories --
-
- private Set<String> explodedPackages(Path dir) {
- try {
- return Files.find(dir, Integer.MAX_VALUE,
- ((path, attrs) -> attrs.isRegularFile()))
- .map(path -> dir.relativize(path))
- .map(this::toPackageName)
- .flatMap(Optional::stream)
- .collect(Collectors.toSet());
- } catch (IOException x) {
- throw new UncheckedIOException(x);
- }
- }
-
- /**
- * Returns a {@code ModuleReference} to an exploded module on the file
- * system or {@code null} if {@code module-info.class} not found.
- *
- * @throws IOException
- * @throws InvalidModuleDescriptorException
- */
- private ModuleReference readExplodedModule(Path dir) throws IOException {
- Path mi = dir.resolve(MODULE_INFO);
- ModuleDescriptor md;
- try (InputStream in = Files.newInputStream(mi)) {
- md = ModuleDescriptor.read(new BufferedInputStream(in),
- () -> explodedPackages(dir));
- } catch (NoSuchFileException e) {
- // for now
- return null;
- }
- return ModuleReferences.newExplodedModule(md, dir);
- }
-
- /**
- * Maps the name of an entry in a JAR or ZIP file to a package name.
- *
- * @throws IllegalArgumentException if the name is a class file in
- * the top-level directory of the JAR/ZIP file (and it's
- * not module-info.class)
- */
- private Optional<String> toPackageName(String name) {
- assert !name.endsWith("/");
-
- int index = name.lastIndexOf("/");
- if (index == -1) {
- if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
- throw new IllegalArgumentException(name
- + " found in top-level directory:"
- + " (unnamed package not allowed in module)");
- }
- return Optional.empty();
- }
-
- String pn = name.substring(0, index).replace('/', '.');
- if (Checks.isJavaIdentifier(pn)) {
- return Optional.of(pn);
- } else {
- // not a valid package name
- return Optional.empty();
- }
- }
-
- /**
- * Maps the relative path of an entry in an exploded module to a package
- * name.
- *
- * @throws IllegalArgumentException if the name is a class file in
- * the top-level directory (and it's not module-info.class)
- */
- private Optional<String> toPackageName(Path file) {
- assert file.getRoot() == null;
-
- Path parent = file.getParent();
- if (parent == null) {
- String name = file.toString();
- if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
- throw new IllegalArgumentException(name
- + " found in in top-level directory"
- + " (unnamed package not allowed in module)");
- }
- return Optional.empty();
- }
-
- String pn = parent.toString().replace(File.separatorChar, '.');
- if (Checks.isJavaIdentifier(pn)) {
- return Optional.of(pn);
- } else {
- // not a valid package name
- return Optional.empty();
- }
- }
-
- private static final PerfCounter scanTime
- = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
- private static final PerfCounter moduleCount
- = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,96 +26,42 @@
package java.lang.module;
import java.io.IOException;
-import java.io.UncheckedIOException;
import java.net.URI;
import java.util.Objects;
import java.util.Optional;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes.HashSupplier;
/**
* A reference to a module's content.
*
- * <p> A module reference contains the module's descriptor and its location, if
- * known. It also has the ability to create a {@link ModuleReader} in order to
- * access the module's content, which may be inside the Java run-time system
- * itself or in an artifact such as a modular JAR file.
+ * <p> A module reference is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. It contains the
+ * module's descriptor and its location, if known. It also has the ability to
+ * create a {@link ModuleReader} in order to access the module's content, which
+ * may be inside the Java run-time system itself or in an artifact such as a
+ * modular JAR file.
*
* @see ModuleFinder
* @see ModuleReader
* @since 9
*/
-public final class ModuleReference {
+public abstract class ModuleReference {
private final ModuleDescriptor descriptor;
private final URI location;
- private final Supplier<ModuleReader> readerSupplier;
-
- // true if this is a reference to a patched module
- private boolean patched;
-
- // the function that computes the hash of this module reference
- private final HashSupplier hasher;
-
- // cached hash to avoid needing to compute it many times
- private byte[] cachedHash;
-
/**
* Constructs a new instance of this class.
- */
- ModuleReference(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> readerSupplier,
- boolean patched,
- HashSupplier hasher)
-
- {
- this.descriptor = Objects.requireNonNull(descriptor);
- this.location = location;
- this.readerSupplier = Objects.requireNonNull(readerSupplier);
- this.patched = patched;
- this.hasher = hasher;
- }
-
- /**
- * Constructs a new instance of this class.
- */
- ModuleReference(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> readerSupplier,
- HashSupplier hasher)
-
- {
- this(descriptor, location, readerSupplier, false, hasher);
- }
-
-
- /**
- * Constructs a new instance of this class.
- *
- * <p> The {@code readSupplier} parameter is the supplier of the {@link
- * ModuleReader} that may be used to read the module content. Its {@link
- * Supplier#get() get()} method throws {@link UncheckedIOException} if an
- * I/O error occurs opening the module content. The {@code get()} method
- * throws {@link SecurityException} if opening the module is denied by the
- * security manager.
*
* @param descriptor
* The module descriptor
* @param location
* The module location or {@code null} if not known
- * @param readerSupplier
- * The {@code Supplier} of the {@code ModuleReader}
*/
- public ModuleReference(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> readerSupplier)
- {
- this(descriptor, location, readerSupplier, false, null);
+ protected ModuleReference(ModuleDescriptor descriptor, URI location) {
+ this.descriptor = Objects.requireNonNull(descriptor);
+ this.location = location;
}
/**
@@ -123,11 +69,10 @@
*
* @return The module descriptor
*/
- public ModuleDescriptor descriptor() {
+ public final ModuleDescriptor descriptor() {
return descriptor;
}
-
/**
* Returns the location of this module's content, if known.
*
@@ -139,18 +84,13 @@
*
* @return The location or an empty {@code Optional} if not known
*/
- public Optional<URI> location() {
+ public final Optional<URI> location() {
return Optional.ofNullable(location);
}
-
/**
* Opens the module content for reading.
*
- * <p> This method opens the module content by invoking the {@link
- * Supplier#get() get()} method of the {@code readSupplier} specified at
- * construction time. </p>
- *
* @return A {@code ModuleReader} to read the module
*
* @throws IOException
@@ -158,113 +98,5 @@
* @throws SecurityException
* If denied by the security manager
*/
- public ModuleReader open() throws IOException {
- try {
- return readerSupplier.get();
- } catch (UncheckedIOException e) {
- throw e.getCause();
- }
-
- }
-
-
- /**
- * Returns {@code true} if this module has been patched via --patch-module.
- */
- boolean isPatched() {
- return patched;
- }
-
- /**
- * Returns the hash supplier for this module.
- */
- HashSupplier hasher() {
- return hasher;
- }
-
- /**
- * Computes the hash of this module. Returns {@code null} if the hash
- * cannot be computed.
- *
- * @throws java.io.UncheckedIOException if an I/O error occurs
- */
- byte[] computeHash(String algorithm) {
- byte[] result = cachedHash;
- if (result != null)
- return result;
- if (hasher == null)
- return null;
- cachedHash = result = hasher.generate(algorithm);
- return result;
- }
-
- /**
- * Computes a hash code for this module reference.
- *
- * <p> The hash code is based upon the components of the reference, and
- * satisfies the general contract of the {@link Object#hashCode
- * Object.hashCode} method. </p>
- *
- * @return The hash-code value for this module reference
- */
- @Override
- public int hashCode() {
- int hc = hash;
- if (hc == 0) {
- hc = descriptor.hashCode();
- hc = 43 * hc + readerSupplier.hashCode();
- hc = 43 * hc + Objects.hashCode(location);
- hc = 43 * hc + Objects.hashCode(hasher);
- hc = 43 * hc + Boolean.hashCode(patched);
- if (hc == 0)
- hc = -1;
- hash = hc;
- }
- return hc;
- }
-
- private int hash;
-
- /**
- * Tests this module reference for equality with the given object.
- *
- * <p> If the given object is not a {@code ModuleReference} then this
- * method returns {@code false}. Two module references are equal if their
- * module descriptors are equal, their locations are equal or both unknown,
- * and were created with equal supplier objects to access the module
- * content. </p>
- *
- * <p> This method satisfies the general contract of the {@link
- * java.lang.Object#equals(Object) Object.equals} method. </p>
- *
- * @param ob
- * the object to which this object is to be compared
- *
- * @return {@code true} if, and only if, the given object is a module
- * reference that is equal to this module reference
- */
- @Override
- public boolean equals(Object ob) {
- if (!(ob instanceof ModuleReference))
- return false;
- ModuleReference that = (ModuleReference)ob;
-
- return Objects.equals(this.descriptor, that.descriptor)
- && Objects.equals(this.location, that.location)
- && Objects.equals(this.readerSupplier, that.readerSupplier)
- && Objects.equals(this.hasher, that.hasher)
- && this.patched == that.patched;
- }
-
- /**
- * Returns a string describing this module reference.
- *
- * @return A string describing this module reference
- */
- @Override
- public String toString() {
- return ("[module " + descriptor().name()
- + ", location=" + location + "]");
- }
-
+ public abstract ModuleReader open() throws IOException;
}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +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.File;
-import java.io.IOError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Supplier;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.misc.JavaLangAccess;
-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.ModulePatcher;
-import jdk.internal.util.jar.VersionedStream;
-import sun.net.www.ParseUtil;
-
-
-/**
- * A factory for creating ModuleReference implementations where the modules are
- * packaged as modular JAR file, JMOD files or where the modules are exploded
- * on the file system.
- */
-
-class ModuleReferences {
-
- private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
- private ModuleReferences() { }
-
- /**
- * Creates a ModuleReference to a module or to patched module when
- * creating modules for the boot Layer and --patch-module is specified.
- */
- private static ModuleReference newModule(ModuleDescriptor md,
- URI uri,
- Supplier<ModuleReader> supplier,
- HashSupplier hasher) {
-
- ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
- if (JLA.getBootLayer() == null)
- mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
- return mref;
- }
-
- /**
- * Creates a ModuleReference to a module packaged as a modular JAR.
- */
- static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
- URI uri = file.toUri();
- Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
- HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
- return newModule(md, uri, supplier, hasher);
- }
-
- /**
- * Creates a ModuleReference to a module packaged as a JMOD.
- */
- static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
- URI uri = file.toUri();
- Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
- HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
- return newModule(md, file.toUri(), supplier, hasher);
- }
-
- /**
- * Creates a ModuleReference to an exploded module.
- */
- static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
- Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
- return newModule(md, dir.toUri(), supplier, null);
- }
-
-
- /**
- * A base module reader that encapsulates machinery required to close the
- * module reader safely.
- */
- static abstract class SafeCloseModuleReader implements ModuleReader {
-
- // RW lock to support safe close
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
- private final Lock readLock = lock.readLock();
- private final Lock writeLock = lock.writeLock();
- private boolean closed;
-
- SafeCloseModuleReader() { }
-
- /**
- * Returns a URL to resource. This method is invoked by the find
- * method to do the actual work of finding the resource.
- */
- abstract Optional<URI> implFind(String name) throws IOException;
-
- /**
- * Returns an input stream for reading a resource. This method is
- * invoked by the open method to do the actual work of opening
- * an input stream to the resource.
- */
- abstract Optional<InputStream> implOpen(String name) throws IOException;
-
- /**
- * Returns a stream of the names of resources in the module. This
- * method is invoked by the list method to do the actual work of
- * creating the stream.
- */
- abstract Stream<String> implList() throws IOException;
-
- /**
- * Closes the module reader. This method is invoked by close to do the
- * actual work of closing the module reader.
- */
- abstract void implClose() throws IOException;
-
- @Override
- public final Optional<URI> find(String name) throws IOException {
- readLock.lock();
- try {
- if (!closed) {
- return implFind(name);
- } else {
- throw new IOException("ModuleReader is closed");
- }
- } finally {
- readLock.unlock();
- }
- }
-
-
- @Override
- public final Optional<InputStream> open(String name) throws IOException {
- readLock.lock();
- try {
- if (!closed) {
- return implOpen(name);
- } else {
- throw new IOException("ModuleReader is closed");
- }
- } finally {
- readLock.unlock();
- }
- }
-
- @Override
- public final Stream<String> list() throws IOException {
- readLock.lock();
- try {
- if (!closed) {
- return implList();
- } else {
- throw new IOException("ModuleReader is closed");
- }
- } finally {
- readLock.unlock();
- }
- }
-
- @Override
- public final void close() throws IOException {
- writeLock.lock();
- try {
- if (!closed) {
- closed = true;
- implClose();
- }
- } finally {
- writeLock.unlock();
- }
- }
- }
-
-
- /**
- * A ModuleReader for a modular JAR file.
- */
- static class JarModuleReader extends SafeCloseModuleReader {
- private final JarFile jf;
- private final URI uri;
-
- static JarFile newJarFile(Path path) {
- try {
- return new JarFile(path.toFile(),
- true, // verify
- ZipFile.OPEN_READ,
- JarFile.runtimeVersion());
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- }
-
- JarModuleReader(Path path, URI uri) {
- this.jf = newJarFile(path);
- this.uri = uri;
- }
-
- private JarEntry getEntry(String name) {
- return jf.getJarEntry(Objects.requireNonNull(name));
- }
-
- @Override
- Optional<URI> implFind(String name) throws IOException {
- JarEntry je = getEntry(name);
- if (je != null) {
- if (jf.isMultiRelease())
- name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
- String encodedPath = ParseUtil.encodePath(name, false);
- String uris = "jar:" + uri + "!/" + encodedPath;
- return Optional.of(URI.create(uris));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- Optional<InputStream> implOpen(String name) throws IOException {
- JarEntry je = getEntry(name);
- if (je != null) {
- return Optional.of(jf.getInputStream(je));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- Stream<String> implList() throws IOException {
- // take snapshot to avoid async close
- List<String> names = VersionedStream.stream(jf)
- .filter(e -> !e.isDirectory())
- .map(JarEntry::getName)
- .collect(Collectors.toList());
- return names.stream();
- }
-
- @Override
- void implClose() throws IOException {
- jf.close();
- }
- }
-
-
- /**
- * A ModuleReader for a JMOD file.
- */
- static class JModModuleReader extends SafeCloseModuleReader {
- private final JmodFile jf;
- private final URI uri;
-
- static JmodFile newJmodFile(Path path) {
- try {
- return new JmodFile(path);
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- }
-
- JModModuleReader(Path path, URI uri) {
- this.jf = newJmodFile(path);
- this.uri = uri;
- }
-
- private JmodFile.Entry getEntry(String name) {
- Objects.requireNonNull(name);
- return jf.getEntry(JmodFile.Section.CLASSES, name);
- }
-
- @Override
- Optional<URI> implFind(String name) {
- JmodFile.Entry je = getEntry(name);
- if (je != null) {
- String encodedPath = ParseUtil.encodePath(name, false);
- String uris = "jmod:" + uri + "!/" + encodedPath;
- return Optional.of(URI.create(uris));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- Optional<InputStream> implOpen(String name) throws IOException {
- JmodFile.Entry je = getEntry(name);
- if (je != null) {
- return Optional.of(jf.getInputStream(je));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- Stream<String> implList() throws IOException {
- // take snapshot to avoid async close
- List<String> names = jf.stream()
- .filter(e -> e.section() == JmodFile.Section.CLASSES)
- .map(JmodFile.Entry::name)
- .collect(Collectors.toList());
- return names.stream();
- }
-
- @Override
- void implClose() throws IOException {
- jf.close();
- }
- }
-
-
- /**
- * A ModuleReader for an exploded module.
- */
- static class ExplodedModuleReader implements ModuleReader {
- private final Path dir;
- private volatile boolean closed;
-
- ExplodedModuleReader(Path dir) {
- this.dir = dir;
-
- // when running with a security manager then check that the caller
- // has access to the directory.
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- boolean unused = Files.isDirectory(dir);
- }
- }
-
- /**
- * Returns a Path to access to the given resource.
- */
- private Path toPath(String name) {
- Path path = Paths.get(name.replace('/', File.separatorChar));
- if (path.getRoot() == null) {
- return dir.resolve(path);
- } else {
- // drop the root component so that the resource is
- // located relative to the module directory
- int n = path.getNameCount();
- return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
- }
- }
-
- /**
- * Throws IOException if the module reader is closed;
- */
- private void ensureOpen() throws IOException {
- if (closed) throw new IOException("ModuleReader is closed");
- }
-
- @Override
- public Optional<URI> find(String name) throws IOException {
- ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
- try {
- return Optional.of(path.toUri());
- } catch (IOError e) {
- throw (IOException) e.getCause();
- }
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public Optional<InputStream> open(String name) throws IOException {
- ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
- return Optional.of(Files.newInputStream(path));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public Optional<ByteBuffer> read(String name) throws IOException {
- ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
- return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public Stream<String> list() throws IOException {
- ensureOpen();
- // sym links not followed
- return Files.find(dir, Integer.MAX_VALUE,
- (path, attrs) -> attrs.isRegularFile())
- .map(f -> dir.relativize(f)
- .toString()
- .replace(File.separatorChar, '/'));
- }
-
- @Override
- public void close() {
- closed = true;
- }
- }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Mon Dec 19 16:05:38 2016 +0000
@@ -46,6 +46,7 @@
import java.util.stream.Collectors;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
/**
* The resolver used by {@link Configuration#resolveRequires} and
@@ -438,24 +439,32 @@
*/
private void checkHashes() {
for (ModuleReference mref : nameToReference.values()) {
- ModuleDescriptor descriptor = mref.descriptor();
- // get map of module hashes
- Optional<ModuleHashes> ohashes = descriptor.hashes();
- if (!ohashes.isPresent())
+ // get the recorded hashes, if any
+ if (!(mref instanceof ModuleReferenceImpl))
continue;
- ModuleHashes hashes = ohashes.get();
+ ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+ if (hashes == null)
+ continue;
+ ModuleDescriptor descriptor = mref.descriptor();
String algorithm = hashes.algorithm();
for (String dn : hashes.names()) {
- ModuleReference other = nameToReference.get(dn);
- if (other == null) {
+ ModuleReference mref2 = nameToReference.get(dn);
+ if (mref2 == null) {
ResolvedModule resolvedModule = findInParent(dn);
if (resolvedModule != null)
- other = resolvedModule.reference();
+ mref2 = resolvedModule.reference();
+ }
+ if (mref2 == null)
+ continue;
+
+ if (!(mref2 instanceof ModuleReferenceImpl)) {
+ fail("Unable to compute the hash of module %s", dn);
}
// skip checking the hash if the module has been patched
+ ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
if (other != null && !other.isPatched()) {
byte[] recordedHash = hashes.hashFor(dn);
byte[] actualHash = other.computeHash(algorithm);
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +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<ModuleReference> modules;
-
- // maps module name to module reference
- private static final Map<String, ModuleReference> 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<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, 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<ModuleReader> 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<String, byte[]> hashes = new HashMap<>();
-
- static void add(ModuleDescriptor descriptor) {
- Optional<ModuleHashes> 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<ModuleReference> find(String name) {
- Objects.requireNonNull(name);
- return Optional.ofNullable(nameToModule.get(name));
- }
-
- @Override
- public Set<ModuleReference> 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<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(imageReader.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 = 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<? 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/java/lang/reflect/AccessibleObject.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java Mon Dec 19 16:05:38 2016 +0000
@@ -28,9 +28,11 @@
import java.lang.annotation.Annotation;
import java.security.AccessController;
+import jdk.internal.misc.VM;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
+import sun.security.action.GetPropertyAction;
/**
* The AccessibleObject class is the base class for Field, Method and
@@ -172,8 +174,10 @@
// package is open to caller
String pn = packageName(declaringClass);
- if (declaringModule.isOpen(pn, callerModule))
+ if (declaringModule.isOpen(pn, callerModule)) {
+ printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
return;
+ }
// package is exported to caller and class/member is public
boolean isExported = declaringModule.isExported(pn, callerModule);
@@ -185,8 +189,10 @@
modifiers = ((Field) this).getModifiers();
}
boolean isMemberPublic = Modifier.isPublic(modifiers);
- if (isExported && isClassPublic && isMemberPublic)
+ if (isExported && isClassPublic && isMemberPublic) {
+ printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
return;
+ }
// not accessible
String msg = "Unable to make ";
@@ -198,7 +204,44 @@
else
msg += "opens";
msg += " " + pn + "\" to " + callerModule;
- Reflection.throwInaccessibleObjectException(msg);
+ InaccessibleObjectException e = new InaccessibleObjectException(msg);
+ if (Reflection.printStackTraceWhenAccessFails()) {
+ e.printStackTrace(System.err);
+ }
+ throw e;
+ }
+
+ private void printStackTraceIfOpenedReflectively(Module module,
+ String pn,
+ Module other) {
+ printStackTraceIfExposedReflectively(module, pn, other, true);
+ }
+
+ private void printStackTraceIfExportedReflectively(Module module,
+ String pn,
+ Module other) {
+ printStackTraceIfExposedReflectively(module, pn, other, false);
+ }
+
+ private void printStackTraceIfExposedReflectively(Module module,
+ String pn,
+ Module other,
+ boolean open)
+ {
+ if (Reflection.printStackTraceWhenAccessSucceeds()
+ && !module.isStaticallyExportedOrOpen(pn, other, open))
+ {
+ String msg = other + " allowed to invoke setAccessible on ";
+ if (this instanceof Field)
+ msg += "field ";
+ msg += this;
+ new Exception(msg) {
+ private static final long serialVersionUID = 42L;
+ public String toString() {
+ return "WARNING: " + getMessage();
+ }
+ }.printStackTrace(System.err);
+ }
}
/**
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Mon Dec 19 16:05:38 2016 +0000
@@ -246,7 +246,6 @@
*/
public Controller addOpens(Module source, String pn, Module target) {
Objects.requireNonNull(source);
- Objects.requireNonNull(source);
Objects.requireNonNull(target);
ensureInLayer(source);
Modules.addOpens(source, pn, target);
@@ -541,7 +540,7 @@
* {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
* avoid deadlocks during class loading. In addition, the entity creating
* a new layer with this method should arrange that the class loaders are
- * ready to load from these module before there are any attempts to load
+ * ready to load from these modules before there are any attempts to load
* classes or resources.
*
* <p> Creating a {@code Layer} can fail for the following reasons: </p>
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java Mon Dec 19 16:05:38 2016 +0000
@@ -559,7 +559,7 @@
* Returns {@code true} if this module exports or opens a package to
* the given module via its module declaration.
*/
- private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+ boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
// package is open to everyone or <other>
Map<String, Set<Module>> openPackages = this.openPackages;
if (openPackages != null) {
@@ -643,6 +643,12 @@
* <em>open</em>) to the given module. It also has no effect if
* invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
*
+ * @apiNote As specified in section 5.4.3 of the <cite>The Java™
+ * Virtual Machine Specification </cite>, if an attempt to resolve a
+ * symbolic reference fails because of a linkage error, then subsequent
+ * attempts to resolve the reference always fail with the same error that
+ * was thrown as a result of the initial resolution attempt.
+ *
* @param pn
* The package name
* @param other
@@ -656,6 +662,7 @@
* @throws IllegalStateException
* If this is a named module and the caller is not this module
*
+ * @jvms 5.4.3 Resolution
* @see #isExported(String,Module)
*/
@CallerSensitive
@@ -676,8 +683,8 @@
}
/**
- * If the caller's module is this module then update this module to
- * <em>open</em> the given package to the given module.
+ * If this module has <em>opened</em> a package to at least the caller
+ * module then update this module to open the package to the given module.
* Opening a package with this method allows all types in the package,
* and all their members, not just public types and their public members,
* to be reflected on by the given module when using APIs that support
@@ -699,7 +706,8 @@
* If {@code pn} is {@code null}, or this is a named module and the
* package {@code pn} is not a package in this module
* @throws IllegalStateException
- * If this is a named module and the caller is not this module
+ * If this is a named module and this module has not opened the
+ * package to at least the caller
*
* @see #isOpen(String,Module)
* @see AccessibleObject#setAccessible(boolean)
@@ -713,9 +721,8 @@
if (isNamed() && !descriptor.isOpen()) {
Module caller = Reflection.getCallerClass().getModule();
- if (caller != this) {
- throw new IllegalStateException(caller + " != " + this);
- }
+ if (caller != this && !isOpen(pn, caller))
+ throw new IllegalStateException(pn + " is not open to " + caller);
implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
}
@@ -1568,6 +1575,10 @@
public Stream<Layer> layers(ClassLoader loader) {
return Layer.layers(loader);
}
+ @Override
+ public boolean isStaticallyExported(Module module, String pn, Module other) {
+ return module.isStaticallyExportedOrOpen(pn, other, false);
+ }
});
}
}
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java Mon Dec 19 16:05:38 2016 +0000
@@ -27,6 +27,8 @@
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
/**
@@ -1332,4 +1334,89 @@
public String getHandshakeApplicationProtocol() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Registers a callback function that selects an application protocol
+ * value for a SSL/TLS/DTLS handshake.
+ * The function overrides any values set using
+ * {@link SSLParameters#setApplicationProtocols
+ * SSLParameters.setApplicationProtocols} and it supports the following
+ * type parameters:
+ * <blockquote>
+ * <dl>
+ * <dt> {@code SSLEngine}
+ * <dd> The function's first argument allows the current {@code SSLEngine}
+ * to be inspected, including the handshake session and configuration
+ * settings.
+ * <dt> {@code List<String>}
+ * <dd> The function's second argument lists the application protocol names
+ * advertised by the TLS peer.
+ * <dt> {@code String}
+ * <dd> The function's result is an application protocol name, or null to
+ * indicate that none of the advertised names are acceptable.
+ * If the return value is null (no value chosen) or is a value that
+ * was not advertised by the peer, the underlying protocol will
+ * determine what action to take. (For example, ALPN will send a
+ * "no_application_protocol" alert and terminate the connection.)
+ * </dl>
+ * </blockquote>
+ *
+ * For example, the following call registers a callback function that
+ * examines the TLS handshake parameters and selects an application protocol
+ * name:
+ * <pre>{@code
+ * serverEngine.setHandshakeApplicationProtocolSelector(
+ * (serverEngine, clientProtocols) -> {
+ * SSLSession session = serverEngine.getHandshakeSession();
+ * return chooseApplicationProtocol(
+ * serverEngine,
+ * clientProtocols,
+ * session.getProtocol(),
+ * session.getCipherSuite());
+ * });
+ * }</pre>
+ *
+ * @apiNote
+ * This method should be called by TLS server applications before the TLS
+ * handshake begins. Also, this {@code SSLEngine} should be configured with
+ * parameters that are compatible with the application protocol selected by
+ * the callback function. For example, enabling a poor choice of cipher
+ * suites could result in no suitable application protocol.
+ * See {@link SSLParameters}.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @param selector the callback function, or null to disable the callback
+ * functionality.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLEngine, List<String>, String> selector) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Retrieves the callback function that selects an application protocol
+ * value during a SSL/TLS/DTLS handshake.
+ * See {@link #setHandshakeApplicationProtocolSelector
+ * setHandshakeApplicationProtocolSelector}
+ * for the function's type parameters.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @return the callback function, or null if none has been set.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public BiFunction<SSLEngine, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ throw new UnsupportedOperationException();
+ }
}
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java Mon Dec 19 16:05:38 2016 +0000
@@ -28,6 +28,8 @@
import java.io.IOException;
import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
/**
* This class extends <code>Socket</code>s and provides secure
@@ -742,4 +744,89 @@
public String getHandshakeApplicationProtocol() {
throw new UnsupportedOperationException();
}
+
+
+ /**
+ * Registers a callback function that selects an application protocol
+ * value for a SSL/TLS/DTLS handshake.
+ * The function overrides any values set using
+ * {@link SSLParameters#setApplicationProtocols
+ * SSLParameters.setApplicationProtocols} and it supports the following
+ * type parameters:
+ * <blockquote>
+ * <dl>
+ * <dt> {@code SSLSocket}
+ * <dd> The function's first argument allows the current {@code SSLSocket}
+ * to be inspected, including the handshake session and configuration
+ * settings.
+ * <dt> {@code List<String>}
+ * <dd> The function's second argument lists the application protocol names
+ * advertised by the TLS peer.
+ * <dt> {@code String}
+ * <dd> The function's result is an application protocol name, or null to
+ * indicate that none of the advertised names are acceptable.
+ * If the return value is null (no value chosen) or is a value that
+ * was not advertised by the peer, the underlying protocol will
+ * determine what action to take. (For example, ALPN will send a
+ * "no_application_protocol" alert and terminate the connection.)
+ * </dl>
+ * </blockquote>
+ *
+ * For example, the following call registers a callback function that
+ * examines the TLS handshake parameters and selects an application protocol
+ * name:
+ * <pre>{@code
+ * serverSocket.setHandshakeApplicationProtocolSelector(
+ * (serverSocket, clientProtocols) -> {
+ * SSLSession session = serverSocket.getHandshakeSession();
+ * return chooseApplicationProtocol(
+ * serverSocket,
+ * clientProtocols,
+ * session.getProtocol(),
+ * session.getCipherSuite());
+ * });
+ * }</pre>
+ *
+ * @apiNote
+ * This method should be called by TLS server applications before the TLS
+ * handshake begins. Also, this {@code SSLSocket} should be configured with
+ * parameters that are compatible with the application protocol selected by
+ * the callback function. For example, enabling a poor choice of cipher
+ * suites could result in no suitable application protocol.
+ * See {@link SSLParameters}.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @param selector the callback function, or null to de-register.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLSocket, List<String>, String> selector) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Retrieves the callback function that selects an application protocol
+ * value during a SSL/TLS/DTLS handshake.
+ * See {@link #setHandshakeApplicationProtocolSelector
+ * setHandshakeApplicationProtocolSelector}
+ * for the function's type parameters.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @return the callback function, or null if none has been set.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public BiFunction<SSLSocket, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ throw new UnsupportedOperationException();
+ }
}
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java Mon Dec 19 16:05:38 2016 +0000
@@ -64,8 +64,10 @@
private static final int CONSTANT_MethodHandle = 15;
private static final int CONSTANT_MethodType = 16;
private static final int CONSTANT_InvokeDynamic = 18;
+ private static final int CONSTANT_Module = 19;
+ private static final int CONSTANT_Package = 20;
- private static final int[] SIZES = new int[20];
+ private static final int[] SIZES = new int[21];
static {
@@ -83,6 +85,8 @@
SIZES[CONSTANT_MethodHandle] = 3;
SIZES[CONSTANT_MethodType] = 2;
SIZES[CONSTANT_InvokeDynamic] = 4;
+ SIZES[CONSTANT_Module] = 2;
+ SIZES[CONSTANT_Package] = 2;
}
public static int[] getSizes() {
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Mon Dec 19 16:05:38 2016 +0000
@@ -38,10 +38,8 @@
import java.lang.module.ModuleReference;
import java.net.URI;
import java.nio.file.Path;
-import java.util.Map;
import java.util.Collection;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
@@ -59,21 +57,28 @@
* @param strict
* Indicates whether module names are checked or not
*/
- ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+ ModuleDescriptor.Builder newModuleBuilder(String mn,
+ boolean strict,
+ boolean open,
+ boolean synthetic);
/**
- * Creates a builder for building an open module with the given module name.
- *
- * @param strict
- * Indicates whether module names are checked or not
+ * Returns the set of packages that are exported (unconditionally or
+ * unconditionally).
*/
- ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+ Set<String> exportedPackages(ModuleDescriptor.Builder builder);
+
+ /**
+ * Returns the set of packages that are opened (unconditionally or
+ * unconditionally).
+ */
+ Set<String> openPackages(ModuleDescriptor.Builder builder);
/**
* Returns a {@code ModuleDescriptor.Requires} of the given modifiers
* and module name.
*/
- Requires newRequires(Set<Requires.Modifier> ms, String mn);
+ Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v);
/**
* Returns an unqualified {@code ModuleDescriptor.Exports}
@@ -122,6 +127,7 @@
* Returns a new {@code ModuleDescriptor} instance.
*/
ModuleDescriptor newModuleDescriptor(String name,
+ Version version,
boolean open,
boolean automatic,
boolean synthetic,
@@ -130,21 +136,14 @@
Set<Opens> opens,
Set<String> uses,
Set<Provides> provides,
- Version version,
+ Set<String> packages,
String mainClass,
String osName,
String osArch,
String osVersion,
- Set<String> packages,
- ModuleHashes hashes,
int hashCode);
/**
- * Returns the object with the hashes of other modules
- */
- Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
-
- /**
* Resolves a collection of root modules, with service binding
* and the empty configuration as the parent. The post resolution
* checks are optionally run.
@@ -154,18 +153,4 @@
boolean check,
PrintStream traceOutput);
- /**
- * Creates a ModuleReference to a "patched" module.
- */
- ModuleReference newPatchedModule(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> readerSupplier);
-
- /**
- * Creates a ModuleFinder for a module path.
- */
- ModuleFinder newModulePath(Runtime.Version version,
- boolean isLinkPhase,
- Path... entries);
-
}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java Mon Dec 19 16:05:38 2016 +0000
@@ -123,4 +123,12 @@
* given class loader.
*/
Stream<Layer> layers(ClassLoader loader);
+
+ /**
+ * Tests if a module exports a package at least {@code other} via its
+ * module declaration.
+ *
+ * @apiNote This is a temporary method for debugging features.
+ */
+ boolean isStaticallyExported(Module module, String pn, Module other);
}
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java Mon Dec 19 16:05:38 2016 +0000
@@ -30,11 +30,8 @@
import java.lang.module.ModuleDescriptor.Provides;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Version;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import jdk.internal.misc.JavaLangModuleAccess;
@@ -52,7 +49,7 @@
* SystemModules should contain modules for the boot layer.
*/
final class Builder {
- private static final JavaLangModuleAccess jlma =
+ private static final JavaLangModuleAccess JLMA =
SharedSecrets.getJavaLangModuleAccess();
// Static cache of the most recently seen Version to cheaply deduplicate
@@ -60,13 +57,36 @@
static Version cachedVersion;
/**
- * Returns a {@link Requires} for a dependence on a module
- * with the given (and possibly empty) set of modifiers.
+ * Returns a {@link Requires} for a dependence on a module with the given
+ * (and possibly empty) set of modifiers, and optionally the version
+ * recorded at compile time.
+ */
+ public static Requires newRequires(Set<Requires.Modifier> mods,
+ String mn,
+ String compiledVersion)
+ {
+ Version version = null;
+ if (compiledVersion != null) {
+ // use the cached version if the same version string
+ Version ver = cachedVersion;
+ if (ver != null && compiledVersion.equals(ver.toString())) {
+ version = ver;
+ } else {
+ version = Version.parse(compiledVersion);
+ }
+ }
+ return JLMA.newRequires(mods, mn, version);
+ }
+
+ /**
+ * Returns a {@link Requires} for a dependence on a module with the given
+ * (and possibly empty) set of modifiers, and optionally the version
+ * recorded at compile time.
*/
public static Requires newRequires(Set<Requires.Modifier> mods,
String mn)
{
- return jlma.newRequires(mods, mn);
+ return newRequires(mods, mn, null);
}
/**
@@ -77,7 +97,7 @@
public static Exports newExports(Set<Exports.Modifier> ms,
String pn,
Set<String> targets) {
- return jlma.newExports(ms, pn, targets);
+ return JLMA.newExports(ms, pn, targets);
}
/**
@@ -85,7 +105,7 @@
* modifiers.
*/
public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
- return jlma.newOpens(ms, pn);
+ return JLMA.newOpens(ms, pn);
}
/**
@@ -96,7 +116,7 @@
public static Opens newOpens(Set<Opens.Modifier> ms,
String pn,
Set<String> targets) {
- return jlma.newOpens(ms, pn, targets);
+ return JLMA.newOpens(ms, pn, targets);
}
/**
@@ -104,7 +124,7 @@
* of modifiers.
*/
public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
- return jlma.newExports(ms, pn);
+ return JLMA.newExports(ms, pn);
}
/**
@@ -112,7 +132,7 @@
* implementation classes.
*/
public static Provides newProvides(String st, List<String> pcs) {
- return jlma.newProvides(st, pcs);
+ return JLMA.newProvides(st, pcs);
}
final String name;
@@ -130,8 +150,6 @@
String osName;
String osArch;
String osVersion;
- String algorithm;
- Map<String, byte[]> hashes;
Builder(String name) {
this.name = name;
@@ -275,34 +293,13 @@
}
/**
- * Sets the algorithm of the module hashes
- */
- public Builder algorithm(String algorithm) {
- this.algorithm = algorithm;
- return this;
- }
-
- /**
- * Sets the module hash for the given module name
- */
- public Builder moduleHash(String mn, byte[] hash) {
- if (hashes == null)
- hashes = new HashMap<>();
-
- hashes.put(mn, hash);
- return this;
- }
-
- /**
* Builds a {@code ModuleDescriptor} from the components.
*/
public ModuleDescriptor build(int hashCode) {
assert name != null;
- ModuleHashes moduleHashes =
- hashes != null ? new ModuleHashes(algorithm, hashes) : null;
-
- return jlma.newModuleDescriptor(name,
+ return JLMA.newModuleDescriptor(name,
+ version,
open,
automatic,
synthetic,
@@ -311,13 +308,11 @@
opens,
uses,
provides,
- version,
+ packages,
mainClass,
osName,
osArch,
osVersion,
- packages,
- moduleHashes,
hashCode);
}
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java Mon Dec 19 16:05:38 2016 +0000
@@ -25,79 +25,200 @@
package jdk.internal.module;
+/**
+ * Utility class for checking module name and binary names.
+ */
+
public final class Checks {
private Checks() { }
- private static void fail(String what, String id, int i) {
- throw new IllegalArgumentException(id
- + ": Invalid " + what + ": "
- + " Illegal character"
- + " at index " + i);
+ /**
+ * Checks a name to ensure that it's a legal module name.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * module name
+ */
+ public static String requireModuleName(String name) {
+ if (name == null)
+ throw new IllegalArgumentException("Null module name");
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('.', off)) != -1) {
+ if (isJavaIdentifier(name, off, (next - off)) == -1) {
+ String id = name.substring(off, next);
+ throw new IllegalArgumentException(name + ": Invalid module name"
+ + ": '" + id + "' is not a Java identifier");
+ }
+ off = next+1;
+ }
+ int last = isJavaIdentifier(name, off, name.length() - off);
+ if (last == -1) {
+ String id = name.substring(off);
+ throw new IllegalArgumentException(name + ": Invalid module name"
+ + ": '" + id + "' is not a Java identifier");
+ }
+ //if (!Character.isJavaIdentifierStart(last))
+ // throw new IllegalArgumentException(name + ": Module name ends in digit");
+ return name;
}
/**
- * Returns {@code true} if the given identifier is a legal Java identifier.
+ * Returns {@code true} if the given name is a legal module name.
*/
- public static boolean isJavaIdentifier(String id) {
- int n = id.length();
- if (n == 0)
- return false;
- if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
+ public static boolean isModuleName(String name) {
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('.', off)) != -1) {
+ if (isJavaIdentifier(name, off, (next - off)) == -1)
+ return false;
+ off = next+1;
+ }
+ int last = isJavaIdentifier(name, off, name.length() - off);
+ if (last == -1)
return false;
- int cp = id.codePointAt(0);
- int i = Character.charCount(cp);
- for (; i < n; i += Character.charCount(cp)) {
- cp = id.codePointAt(i);
- if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
- return false;
- }
- if (cp == '.')
- return false;
-
+ //if (!Character.isJavaIdentifierStart(last))
+ // return false;
return true;
}
/**
- * Checks if a given identifier is a legal Java identifier.
+ * Checks a name to ensure that it's a legal package name.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * package name
+ */
+ public static String requirePackageName(String name) {
+ return requireBinaryName("package name", name);
+ }
+
+ /**
+ * Checks a name to ensure that it's a legal type name.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * type name
+ */
+ public static String requireServiceTypeName(String name) {
+ return requireBinaryName("service type name", name);
+ }
+
+ /**
+ * Checks a name to ensure that it's a legal type name.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * type name
*/
- public static String requireJavaIdentifier(String what, String id) {
- if (id == null)
- throw new IllegalArgumentException("Null " + what);
- int n = id.length();
- if (n == 0)
- throw new IllegalArgumentException("Empty " + what);
- if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
- fail(what, id, 0);
- int cp = id.codePointAt(0);
- int i = Character.charCount(cp);
- int last = 0;
- for (; i < n; i += Character.charCount(cp)) {
- cp = id.codePointAt(i);
- if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
- fail(what, id, i);
- last = i;
+ public static String requireServiceProviderName(String name) {
+ return requireBinaryName("service provider name", name);
+ }
+
+ /**
+ * Returns {@code true} if the given name is a legal binary name.
+ */
+ public static boolean isJavaIdentifier(String name) {
+ return isBinaryName(name);
+ }
+
+ /**
+ * Returns {@code true} if the given name is a legal binary name.
+ */
+ public static boolean isBinaryName(String name) {
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('.', off)) != -1) {
+ if (isJavaIdentifier(name, off, (next - off)) == -1)
+ return false;
+ off = next+1;
}
- if (cp == '.')
- fail(what, id, last);
-
- return id;
+ int count = name.length() - off;
+ return (isJavaIdentifier(name, off, count) != -1);
}
- public static String requireModuleName(String id) {
- return requireJavaIdentifier("module name", id);
- }
-
- public static String requirePackageName(String id) {
- return requireJavaIdentifier("package name", id);
+ /**
+ * Checks if the given name is a legal binary name.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * binary name
+ */
+ public static String requireBinaryName(String what, String name) {
+ if (name == null)
+ throw new IllegalArgumentException("Null " + what);
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('.', off)) != -1) {
+ if (isJavaIdentifier(name, off, (next - off)) == -1) {
+ String id = name.substring(off, next);
+ throw new IllegalArgumentException(name + ": Invalid " + what
+ + ": '" + id + "' is not a Java identifier");
+ }
+ off = next + 1;
+ }
+ if (isJavaIdentifier(name, off, name.length() - off) == -1) {
+ String id = name.substring(off, name.length());
+ throw new IllegalArgumentException(name + ": Invalid " + what
+ + ": '" + id + "' is not a Java identifier");
+ }
+ return name;
}
- public static String requireServiceTypeName(String id) {
- return requireJavaIdentifier("service type name", id);
+ /**
+ * Returns {@code true} if the last character of the given name is legal
+ * as the last character of a module name.
+ *
+ * @throws IllegalArgumentException if name is empty
+ */
+ public static boolean hasLegalModuleNameLastCharacter(String name) {
+ if (name.isEmpty())
+ throw new IllegalArgumentException("name is empty");
+ int len = name.length();
+ if (isASCIIString(name)) {
+ char c = name.charAt(len-1);
+ return Character.isJavaIdentifierStart(c);
+ } else {
+ int i = 0;
+ int cp = -1;
+ while (i < len) {
+ cp = name.codePointAt(i);
+ i += Character.charCount(cp);
+ }
+ return Character.isJavaIdentifierStart(cp);
+ }
}
- public static String requireServiceProviderName(String id) {
- return requireJavaIdentifier("service provider name", id);
+ /**
+ * Returns true if the given string only contains ASCII characters.
+ */
+ private static boolean isASCIIString(String s) {
+ int i = 0;
+ while (i < s.length()) {
+ int c = s.charAt(i);
+ if (c > 0x7F)
+ return false;
+ i++;
+ }
+ return true;
}
+ /**
+ * Checks if a char sequence is a legal Java identifier, returning the code
+ * point of the last character if legal or {@code -1} if not legal.
+ */
+ private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
+ if (count == 0)
+ return -1;
+ int first = Character.codePointAt(cs, offset);
+ if (!Character.isJavaIdentifierStart(first))
+ return -1;
+
+ int cp = first;
+ int i = Character.charCount(first);
+ while (i < count) {
+ cp = Character.codePointAt(cs, offset+i);
+ if (!Character.isJavaIdentifierPart(cp))
+ return -1;
+ i += Character.charCount(cp);
+ }
+
+ return cp;
+ }
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java Mon Dec 19 16:05:38 2016 +0000
@@ -68,12 +68,18 @@
= SharedSecrets.getJavaLangModuleAccess();
private ModuleDescriptor descriptor;
+ private Version replacementVersion;
public ModuleAttribute(ModuleDescriptor descriptor) {
super(MODULE);
this.descriptor = descriptor;
}
+ public ModuleAttribute(Version v) {
+ super(MODULE);
+ this.replacementVersion = v;
+ }
+
public ModuleAttribute() {
super(MODULE);
}
@@ -86,46 +92,70 @@
int codeOff,
Label[] labels)
{
- ModuleAttribute attr = new ModuleAttribute();
-
- // module_name
- String mn = cr.readUTF8(off, buf).replace('/', '.');
+ // module_name (CONSTANT_Module_info)
+ String mn = cr.readModule(off, buf);
off += 2;
// module_flags
int module_flags = cr.readUnsignedShort(off);
boolean open = ((module_flags & ACC_OPEN) != 0);
+ boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
off += 2;
- ModuleDescriptor.Builder builder;
- if (open) {
- builder = JLMA.newOpenModuleBuilder(mn, false);
- } else {
- builder = JLMA.newModuleBuilder(mn, false);
+ ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
+ false,
+ open,
+ synthetic);
+
+ // module_version
+ String module_version = cr.readUTF8(off, buf);
+ off += 2;
+ if (replacementVersion != null) {
+ builder.version(replacementVersion);
+ } else if (module_version != null) {
+ builder.version(module_version);
}
// requires_count and requires[requires_count]
int requires_count = cr.readUnsignedShort(off);
off += 2;
for (int i=0; i<requires_count; i++) {
- String dn = cr.readUTF8(off, buf).replace('/', '.');
- int flags = cr.readUnsignedShort(off + 2);
+ // CONSTANT_Module_info
+ String dn = cr.readModule(off, buf);
+ off += 2;
+
+ // requires_flags
+ int requires_flags = cr.readUnsignedShort(off);
+ off += 2;
Set<Requires.Modifier> mods;
- if (flags == 0) {
+ if (requires_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
- if ((flags & ACC_TRANSITIVE) != 0)
+ if ((requires_flags & ACC_TRANSITIVE) != 0)
mods.add(Requires.Modifier.TRANSITIVE);
- if ((flags & ACC_STATIC_PHASE) != 0)
+ if ((requires_flags & ACC_STATIC_PHASE) != 0)
mods.add(Requires.Modifier.STATIC);
- if ((flags & ACC_SYNTHETIC) != 0)
+ if ((requires_flags & ACC_SYNTHETIC) != 0)
mods.add(Requires.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
+ if ((requires_flags & ACC_MANDATED) != 0)
mods.add(Requires.Modifier.MANDATED);
}
- builder.requires(mods, dn);
- off += 4;
+
+
+ // requires_version
+ Version compiledVersion = null;
+ String requires_version = cr.readUTF8(off, buf);
+ off += 2;
+ if (requires_version != null) {
+ compiledVersion = Version.parse(requires_version);
+ }
+
+ if (compiledVersion == null) {
+ builder.requires(mods, dn);
+ } else {
+ builder.requires(mods, dn, compiledVersion);
+ }
}
// exports_count and exports[exports_count]
@@ -133,19 +163,20 @@
off += 2;
if (exports_count > 0) {
for (int i=0; i<exports_count; i++) {
- String pkg = cr.readUTF8(off, buf).replace('/', '.');
+ // CONSTANT_Package_info
+ String pkg = cr.readPackage(off, buf).replace('/', '.');
off += 2;
- int flags = cr.readUnsignedShort(off);
+ int exports_flags = cr.readUnsignedShort(off);
off += 2;
Set<Exports.Modifier> mods;
- if (flags == 0) {
+ if (exports_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
- if ((flags & ACC_SYNTHETIC) != 0)
+ if ((exports_flags & ACC_SYNTHETIC) != 0)
mods.add(Exports.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
+ if ((exports_flags & ACC_MANDATED) != 0)
mods.add(Exports.Modifier.MANDATED);
}
@@ -154,7 +185,7 @@
if (exports_to_count > 0) {
Set<String> targets = new HashSet<>();
for (int j=0; j<exports_to_count; j++) {
- String t = cr.readUTF8(off, buf).replace('/', '.');
+ String t = cr.readModule(off, buf);
off += 2;
targets.add(t);
}
@@ -170,19 +201,20 @@
off += 2;
if (open_count > 0) {
for (int i=0; i<open_count; i++) {
- String pkg = cr.readUTF8(off, buf).replace('/', '.');
+ // CONSTANT_Package_info
+ String pkg = cr.readPackage(off, buf).replace('/', '.');
off += 2;
- int flags = cr.readUnsignedShort(off);
+ int opens_flags = cr.readUnsignedShort(off);
off += 2;
Set<Opens.Modifier> mods;
- if (flags == 0) {
+ if (opens_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
- if ((flags & ACC_SYNTHETIC) != 0)
+ if ((opens_flags & ACC_SYNTHETIC) != 0)
mods.add(Opens.Modifier.SYNTHETIC);
- if ((flags & ACC_MANDATED) != 0)
+ if ((opens_flags & ACC_MANDATED) != 0)
mods.add(Opens.Modifier.MANDATED);
}
@@ -191,7 +223,7 @@
if (opens_to_count > 0) {
Set<String> targets = new HashSet<>();
for (int j=0; j<opens_to_count; j++) {
- String t = cr.readUTF8(off, buf).replace('/', '.');
+ String t = cr.readModule(off, buf);
off += 2;
targets.add(t);
}
@@ -232,8 +264,7 @@
}
}
- attr.descriptor = builder.build();
- return attr;
+ return new ModuleAttribute(builder.build());
}
@Override
@@ -248,7 +279,7 @@
// module_name
String mn = descriptor.name();
- int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+ int module_name_index = cw.newModule(mn);
attr.putShort(module_name_index);
// module_flags
@@ -259,66 +290,83 @@
module_flags |= ACC_SYNTHETIC;
attr.putShort(module_flags);
+ // module_version
+ Version v = descriptor.version().orElse(null);
+ if (v == null) {
+ attr.putShort(0);
+ } else {
+ int module_version_index = cw.newUTF8(v.toString());
+ attr.putShort(module_version_index);
+ }
+
// requires_count
attr.putShort(descriptor.requires().size());
// requires[requires_count]
- for (Requires md : descriptor.requires()) {
- String dn = md.name();
- int flags = 0;
- if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
- flags |= ACC_TRANSITIVE;
- if (md.modifiers().contains(Requires.Modifier.STATIC))
- flags |= ACC_STATIC_PHASE;
- if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
- flags |= ACC_SYNTHETIC;
- if (md.modifiers().contains(Requires.Modifier.MANDATED))
- flags |= ACC_MANDATED;
- int index = cw.newUTF8(dn.replace('.', '/'));
- attr.putShort(index);
- attr.putShort(flags);
+ for (Requires r : descriptor.requires()) {
+ int requires_index = cw.newModule(r.name());
+ attr.putShort(requires_index);
+
+ int requires_flags = 0;
+ if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
+ requires_flags |= ACC_TRANSITIVE;
+ if (r.modifiers().contains(Requires.Modifier.STATIC))
+ requires_flags |= ACC_STATIC_PHASE;
+ if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
+ requires_flags |= ACC_SYNTHETIC;
+ if (r.modifiers().contains(Requires.Modifier.MANDATED))
+ requires_flags |= ACC_MANDATED;
+ attr.putShort(requires_flags);
+
+ int requires_version_index;
+ v = r.compiledVersion().orElse(null);
+ if (v == null) {
+ requires_version_index = 0;
+ } else {
+ requires_version_index = cw.newUTF8(v.toString());
+ }
+ attr.putShort(requires_version_index);
}
// exports_count and exports[exports_count];
attr.putShort(descriptor.exports().size());
for (Exports e : descriptor.exports()) {
String pkg = e.source().replace('.', '/');
- attr.putShort(cw.newUTF8(pkg));
+ attr.putShort(cw.newPackage(pkg));
- int flags = 0;
+ int exports_flags = 0;
if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
- flags |= ACC_SYNTHETIC;
+ exports_flags |= ACC_SYNTHETIC;
if (e.modifiers().contains(Exports.Modifier.MANDATED))
- flags |= ACC_MANDATED;
- attr.putShort(flags);
+ exports_flags |= ACC_MANDATED;
+ attr.putShort(exports_flags);
if (e.isQualified()) {
Set<String> ts = e.targets();
attr.putShort(ts.size());
- ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+ ts.forEach(target -> attr.putShort(cw.newModule(target)));
} else {
attr.putShort(0);
}
}
-
// opens_counts and opens[opens_counts]
attr.putShort(descriptor.opens().size());
for (Opens obj : descriptor.opens()) {
String pkg = obj.source().replace('.', '/');
- attr.putShort(cw.newUTF8(pkg));
+ attr.putShort(cw.newPackage(pkg));
- int flags = 0;
+ int opens_flags = 0;
if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
- flags |= ACC_SYNTHETIC;
+ opens_flags |= ACC_SYNTHETIC;
if (obj.modifiers().contains(Opens.Modifier.MANDATED))
- flags |= ACC_MANDATED;
- attr.putShort(flags);
+ opens_flags |= ACC_MANDATED;
+ attr.putShort(opens_flags);
if (obj.isQualified()) {
Set<String> ts = obj.targets();
attr.putShort(ts.size());
- ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+ ts.forEach(target -> attr.putShort(cw.newModule(target)));
} else {
attr.putShort(0);
}
@@ -369,7 +417,7 @@
*
* // the number of entries in the packages table
* u2 packages_count;
- * { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
+ * { // index to CONSTANT_Package_info structure with the package name
* u2 package_index
* } packages[package_count];
*
@@ -402,7 +450,7 @@
// packages
Set<String> packages = new HashSet<>();
for (int i=0; i<package_count; i++) {
- String pkg = cr.readUTF8(off, buf).replace('/', '.');
+ String pkg = cr.readPackage(off, buf).replace('/', '.');
packages.add(pkg);
off += 2;
}
@@ -427,7 +475,7 @@
// packages
packages.stream()
.map(p -> p.replace('.', '/'))
- .forEach(p -> attr.putShort(cw.newUTF8(p)));
+ .forEach(p -> attr.putShort(cw.newPackage(p)));
return attr;
}
@@ -435,61 +483,6 @@
}
/**
- * ModuleVersion attribute.
- *
- * <pre> {@code
- *
- * ModuleVersion_attribute {
- * // index to CONSTANT_utf8_info structure in constant pool representing
- * // the string "ModuleVersion"
- * u2 attribute_name_index;
- * u4 attribute_length;
- *
- * // index to CONSTANT_CONSTANT_utf8_info structure with the version
- * u2 version_index;
- * }
- *
- * } </pre>
- */
- public static class ModuleVersionAttribute extends Attribute {
- private final Version version;
-
- public ModuleVersionAttribute(Version version) {
- super(MODULE_VERSION);
- this.version = version;
- }
-
- public ModuleVersionAttribute() {
- this(null);
- }
-
- @Override
- protected Attribute read(ClassReader cr,
- int off,
- int len,
- char[] buf,
- int codeOff,
- Label[] labels)
- {
- String value = cr.readUTF8(off, buf);
- return new ModuleVersionAttribute(Version.parse(value));
- }
-
- @Override
- protected ByteVector write(ClassWriter cw,
- byte[] code,
- int len,
- int maxStack,
- int maxLocals)
- {
- ByteVector attr = new ByteVector();
- int index = cw.newUTF8(version.toString());
- attr.putShort(index);
- return attr;
- }
- }
-
- /**
* ModuleMainClass attribute.
*
* <pre> {@code
@@ -526,7 +519,7 @@
int codeOff,
Label[] labels)
{
- String value = cr.readClass(off, buf);
+ String value = cr.readClass(off, buf).replace('/', '.');
return new ModuleMainClassAttribute(value);
}
@@ -538,7 +531,7 @@
int maxLocals)
{
ByteVector attr = new ByteVector();
- int index = cw.newClass(mainClass);
+ int index = cw.newClass(mainClass.replace('.', '/'));
attr.putShort(index);
return attr;
}
@@ -555,11 +548,11 @@
* u2 attribute_name_index;
* u4 attribute_length;
*
- * // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
+ * // index to CONSTANT_utf8_info structure with the OS name
* u2 os_name_index;
- * // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
+ * // index to CONSTANT_utf8_info structure with the OS arch
* u2 os_arch_index
- * // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
+ * // index to CONSTANT_utf8_info structure with the OS version
* u2 os_version_index;
* }
*
@@ -656,7 +649,7 @@
*
* // the number of entries in the hashes table
* u2 hashes_count;
- * { u2 module_name_index
+ * { u2 module_name_index (index to CONSTANT_Module_info structure)
* u2 hash_length;
* u1 hash[hash_length];
* } hashes[hashes_count];
@@ -691,7 +684,7 @@
Map<String, byte[]> map = new HashMap<>();
for (int i=0; i<hashes_count; i++) {
- String mn = cr.readUTF8(off, buf).replace('/', '.');
+ String mn = cr.readModule(off, buf);
off += 2;
int hash_length = cr.readUnsignedShort(off);
@@ -728,7 +721,7 @@
for (String mn : names) {
byte[] hash = hashes.hashFor(mn);
assert hash != null;
- attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+ attr.putShort(cw.newModule(mn));
attr.putShort(hash.length);
for (byte b: hash) {
@@ -740,4 +733,58 @@
}
}
+ /**
+ * ModuleResolution_attribute {
+ * u2 attribute_name_index; // "ModuleResolution"
+ * u4 attribute_length; // 2
+ * u2 resolution_flags;
+ *
+ * The value of the resolution_flags item is a mask of flags used to denote
+ * properties of module resolution. The flags are as follows:
+ *
+ * // Optional
+ * 0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
+ *
+ * // At most one of:
+ * 0x0002 (WARN_DEPRECATED)
+ * 0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
+ * 0x0008 (WARN_INCUBATING)
+ */
+ static class ModuleResolutionAttribute extends Attribute {
+ private final int value;
+
+ ModuleResolutionAttribute() {
+ super(MODULE_RESOLUTION);
+ value = 0;
+ }
+
+ ModuleResolutionAttribute(int value) {
+ super(MODULE_RESOLUTION);
+ this.value = value;
+ }
+
+ @Override
+ protected Attribute read(ClassReader cr,
+ int off,
+ int len,
+ char[] buf,
+ int codeOff,
+ Label[] labels)
+ {
+ int flags = cr.readUnsignedShort(off);
+ return new ModuleResolutionAttribute(flags);
+ }
+
+ @Override
+ protected ByteVector write(ClassWriter cw,
+ byte[] code,
+ int len,
+ int maxStack,
+ int maxLocals)
+ {
+ ByteVector attr = new ByteVector();
+ attr.putShort(value);
+ return attr;
+ }
+ }
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java Mon Dec 19 16:05:38 2016 +0000
@@ -38,10 +38,10 @@
public static final String SDE = "SourceDebugExtension";
public static final String MODULE_PACKAGES = "ModulePackages";
- public static final String MODULE_VERSION = "ModuleVersion";
public static final String MODULE_MAIN_CLASS = "ModuleMainClass";
public static final String MODULE_TARGET = "ModuleTarget";
public static final String MODULE_HASHES = "ModuleHashes";
+ public static final String MODULE_RESOLUTION = "ModuleResolution";
// access, requires, exports, and opens flags
public static final int ACC_MODULE = 0x8000;
@@ -51,4 +51,10 @@
public static final int ACC_SYNTHETIC = 0x1000;
public static final int ACC_MANDATED = 0x8000;
+ // ModuleResolution_attribute resolution flags
+ public static final int DO_NOT_RESOLVE_BY_DEFAULT = 0x0001;
+ public static final int WARN_DEPRECATED = 0x0002;
+ public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
+ public static final int WARN_INCUBATING = 0x0008;
+
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Mon Dec 19 16:05:38 2016 +0000
@@ -195,7 +195,9 @@
// 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 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()) {
@@ -212,6 +214,9 @@
if (hasJava && mn.startsWith("java."))
continue;
+ if (ModuleResolution.doNotResolveByDefault(mref))
+ continue;
+
// add as root if observable and exports at least one package
if ((finder == systemModules || finder.find(mn).isPresent())) {
ModuleDescriptor descriptor = mref.descriptor();
@@ -231,6 +236,7 @@
ModuleFinder f = finder; // observable modules
systemModules.findAll()
.stream()
+ .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
.map(ModuleReference::descriptor)
.map(ModuleDescriptor::name)
.filter(mn -> f.find(mn).isPresent()) // observable
@@ -277,6 +283,8 @@
// time to create configuration
PerfCounters.resolveTime.addElapsedTimeFrom(t3);
+ // check module names and incubating status
+ checkModuleNamesAndStatus(cf);
// mapping of modules to class loaders
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -508,12 +516,12 @@
String key = e.getKey();
String[] s = key.split("/");
if (s.length != 2)
- fail("Unable to parse: " + key);
+ fail("Unable to parse as <module>/<package>: " + key);
String mn = s[0];
String pn = s[1];
if (mn.isEmpty() || pn.isEmpty())
- fail("Module and package name must be specified:" + key);
+ fail("Module and package name must be specified: " + key);
// The exporting module is in the boot layer
Module m;
@@ -585,7 +593,7 @@
int pos = value.indexOf('=');
if (pos == -1)
- fail("Unable to parse: " + value);
+ fail("Unable to parse as <module>=<value>: " + value);
if (pos == 0)
fail("Missing module name in: " + value);
@@ -594,7 +602,7 @@
String rhs = value.substring(pos+1);
if (rhs.isEmpty())
- fail("Unable to parse: " + value);
+ fail("Unable to parse as <module>=<value>: " + value);
// value is <module>(,<module>)* or <file>(<pathsep><file>)*
if (!allowDuplicates && map.containsKey(key))
@@ -627,6 +635,33 @@
}
/**
+ * Checks the names and resolution bit of each module in the configuration,
+ * emitting warnings if needed.
+ */
+ private static void checkModuleNamesAndStatus(Configuration cf) {
+ String incubating = null;
+ for (ResolvedModule rm : cf.modules()) {
+ ModuleReference mref = rm.reference();
+ String mn = mref.descriptor().name();
+
+ // emit warning if module name ends with a non-Java letter
+ if (!Checks.hasLegalModuleNameLastCharacter(mn))
+ warn("Module name \"" + mn + "\" may soon be illegal");
+
+ // emit warning if the WARN_INCUBATING module resolution bit set
+ if (ModuleResolution.hasIncubatingWarning(mref)) {
+ if (incubating == null) {
+ incubating = mn;
+ } else {
+ incubating += ", " + mn;
+ }
+ }
+ }
+ if (incubating != null)
+ warn("Using incubator modules: " + incubating);
+ }
+
+ /**
* Throws a RuntimeException with the given message
*/
static void fail(String m) {
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java Mon Dec 19 16:05:38 2016 +0000
@@ -35,6 +35,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -50,7 +51,6 @@
byte[] generate(String algorithm);
}
-
private final String algorithm;
private final Map<String, byte[]> nameToHash;
@@ -142,4 +142,37 @@
}
return new ModuleHashes(algorithm, nameToHash);
}
+
+ /**
+ * This is used by jdk.internal.module.SystemModules class
+ * generated at link time.
+ */
+ public static class Builder {
+ final String algorithm;
+ final Map<String, byte[]> nameToHash;
+
+ Builder(String algorithm, int initialCapacity) {
+ this.nameToHash = new HashMap<>(initialCapacity);
+ this.algorithm = Objects.requireNonNull(algorithm);
+ }
+
+ /**
+ * Sets the module hash for the given module name
+ */
+ public Builder hashForModule(String mn, byte[] hash) {
+ nameToHash.put(mn, hash);
+ return this;
+ }
+
+ /**
+ * Builds a {@code ModuleHashes}.
+ */
+ public ModuleHashes build() {
+ if (!nameToHash.isEmpty()) {
+ return new ModuleHashes(algorithm, nameToHash);
+ } else {
+ return null;
+ }
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2014, 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.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleResolution;
+
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Read module information from a {@code module-info} class file.
+ *
+ * @implNote The rationale for the hand-coded reader is startup performance
+ * and fine control over the throwing of InvalidModuleDescriptorException.
+ */
+
+public final class ModuleInfo {
+
+ private static final JavaLangModuleAccess JLMA
+ = SharedSecrets.getJavaLangModuleAccess();
+
+ // supplies the set of packages when ModulePackages attribute not present
+ private final Supplier<Set<String>> packageFinder;
+
+ // indicates if the ModuleHashes attribute should be parsed
+ private final boolean parseHashes;
+
+ private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
+ packageFinder = pf;
+ parseHashes = ph;
+ }
+
+ private ModuleInfo(Supplier<Set<String>> pf) {
+ this(pf, true);
+ }
+
+ /**
+ * A holder class for the ModuleDescriptor that is created by reading the
+ * Module and other standard class file attributes. It also holds the objects
+ * that represent the non-standard class file attributes that are read from
+ * the class file.
+ */
+ public static final class Attributes {
+ private final ModuleDescriptor descriptor;
+ private final ModuleHashes recordedHashes;
+ private final ModuleResolution moduleResolution;
+ Attributes(ModuleDescriptor descriptor,
+ ModuleHashes recordedHashes,
+ ModuleResolution moduleResolution) {
+ this.descriptor = descriptor;
+ this.recordedHashes = recordedHashes;
+ this.moduleResolution = moduleResolution;
+ }
+ public ModuleDescriptor descriptor() {
+ return descriptor;
+ }
+ public ModuleHashes recordedHashes() {
+ return recordedHashes;
+ }
+ public ModuleResolution moduleResolution() {
+ return moduleResolution;
+ }
+ }
+
+
+ /**
+ * Reads a {@code module-info.class} from the given input stream.
+ *
+ * @throws InvalidModuleDescriptorException
+ * @throws IOException
+ */
+ public static Attributes read(InputStream in, Supplier<Set<String>> pf)
+ throws IOException
+ {
+ try {
+ return new ModuleInfo(pf).doRead(new DataInputStream(in));
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw invalidModuleDescriptor(e.getMessage());
+ } catch (EOFException x) {
+ throw truncatedModuleDescriptor();
+ }
+ }
+
+ /**
+ * Reads a {@code module-info.class} from the given byte buffer.
+ *
+ * @throws InvalidModuleDescriptorException
+ * @throws UncheckedIOException
+ */
+ public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
+ try {
+ return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw invalidModuleDescriptor(e.getMessage());
+ } catch (EOFException x) {
+ throw truncatedModuleDescriptor();
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
+ /**
+ * Reads a {@code module-info.class} from the given byte buffer
+ * but ignore the {@code ModuleHashes} attribute.
+ *
+ * @throws InvalidModuleDescriptorException
+ * @throws UncheckedIOException
+ */
+ public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
+ try {
+ return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw invalidModuleDescriptor(e.getMessage());
+ } catch (EOFException x) {
+ throw truncatedModuleDescriptor();
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
+ /**
+ * Reads the input as a module-info class file.
+ *
+ * @throws IOException
+ * @throws InvalidModuleDescriptorException
+ * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
+ * because an identifier is not a legal Java identifier, duplicate
+ * exports, and many other reasons
+ */
+ private Attributes doRead(DataInput in) throws IOException {
+
+ int magic = in.readInt();
+ if (magic != 0xCAFEBABE)
+ throw invalidModuleDescriptor("Bad magic number");
+
+ int minor_version = in.readUnsignedShort();
+ int major_version = in.readUnsignedShort();
+ if (major_version < 53) {
+ throw invalidModuleDescriptor("Must be >= 53.0");
+ }
+
+ ConstantPool cpool = new ConstantPool(in);
+
+ int access_flags = in.readUnsignedShort();
+ if (access_flags != ACC_MODULE)
+ throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
+
+ int this_class = in.readUnsignedShort();
+ String mn = cpool.getClassName(this_class);
+ if (!"module-info".equals(mn))
+ throw invalidModuleDescriptor("this_class should be module-info");
+
+ int super_class = in.readUnsignedShort();
+ if (super_class > 0)
+ throw invalidModuleDescriptor("bad #super_class");
+
+ int interfaces_count = in.readUnsignedShort();
+ if (interfaces_count > 0)
+ throw invalidModuleDescriptor("Bad #interfaces");
+
+ int fields_count = in.readUnsignedShort();
+ if (fields_count > 0)
+ throw invalidModuleDescriptor("Bad #fields");
+
+ int methods_count = in.readUnsignedShort();
+ if (methods_count > 0)
+ throw invalidModuleDescriptor("Bad #methods");
+
+ int attributes_count = in.readUnsignedShort();
+
+ // the names of the attributes found in the class file
+ Set<String> attributes = new HashSet<>();
+
+ Builder builder = null;
+ Set<String> packages = null;
+ String mainClass = null;
+ String[] osValues = null;
+ ModuleHashes hashes = null;
+ ModuleResolution moduleResolution = null;
+
+ for (int i = 0; i < attributes_count ; i++) {
+ int name_index = in.readUnsignedShort();
+ String attribute_name = cpool.getUtf8(name_index);
+ int length = in.readInt();
+
+ boolean added = attributes.add(attribute_name);
+ if (!added && isAttributeAtMostOnce(attribute_name)) {
+ throw invalidModuleDescriptor("More than one "
+ + attribute_name + " attribute");
+ }
+
+ switch (attribute_name) {
+
+ case MODULE :
+ builder = readModuleAttribute(in, cpool);
+ break;
+
+ case MODULE_PACKAGES :
+ packages = readModulePackagesAttribute(in, cpool);
+ break;
+
+ case MODULE_MAIN_CLASS :
+ mainClass = readModuleMainClassAttribute(in, cpool);
+ break;
+
+ case MODULE_TARGET :
+ osValues = readModuleTargetAttribute(in, cpool);
+ break;
+
+ case MODULE_HASHES :
+ if (parseHashes) {
+ hashes = readModuleHashesAttribute(in, cpool);
+ } else {
+ in.skipBytes(length);
+ }
+ break;
+
+ case MODULE_RESOLUTION :
+ moduleResolution = readModuleResolution(in, cpool);
+ break;
+
+ default:
+ if (isAttributeDisallowed(attribute_name)) {
+ throw invalidModuleDescriptor(attribute_name
+ + " attribute not allowed");
+ } else {
+ in.skipBytes(length);
+ }
+
+ }
+ }
+
+ // the Module attribute is required
+ if (builder == null) {
+ throw invalidModuleDescriptor(MODULE + " attribute not found");
+ }
+
+ // If the ModulePackages attribute is not present then the packageFinder
+ // is used to find the set of packages
+ boolean usedPackageFinder = false;
+ if (packages == null && packageFinder != null) {
+ try {
+ packages = new HashSet<>(packageFinder.get());
+ } catch (UncheckedIOException x) {
+ throw x.getCause();
+ }
+ usedPackageFinder = true;
+ }
+ if (packages != null) {
+ Set<String> exportedPackages = JLMA.exportedPackages(builder);
+ Set<String> openPackages = JLMA.openPackages(builder);
+ if (packages.containsAll(exportedPackages)
+ && packages.containsAll(openPackages)) {
+ packages.removeAll(exportedPackages);
+ packages.removeAll(openPackages);
+ } else {
+ // the set of packages is not complete
+ Set<String> exportedAndOpenPackages = new HashSet<>();
+ exportedAndOpenPackages.addAll(exportedPackages);
+ exportedAndOpenPackages.addAll(openPackages);
+ for (String pn : exportedAndOpenPackages) {
+ if (!packages.contains(pn)) {
+ String tail;
+ if (usedPackageFinder) {
+ tail = " not found by package finder";
+ } else {
+ tail = " missing from ModulePackages attribute";
+ }
+ throw invalidModuleDescriptor("Package " + pn + tail);
+ }
+ }
+ assert false; // should not get here
+ }
+ builder.contains(packages);
+ }
+
+ if (mainClass != null)
+ builder.mainClass(mainClass);
+ if (osValues != null) {
+ if (osValues[0] != null) builder.osName(osValues[0]);
+ if (osValues[1] != null) builder.osArch(osValues[1]);
+ if (osValues[2] != null) builder.osVersion(osValues[2]);
+ }
+
+ ModuleDescriptor descriptor = builder.build();
+ return new Attributes(descriptor, hashes, moduleResolution);
+ }
+
+ /**
+ * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+ * build the corresponding ModuleDescriptor.
+ */
+ private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
+ throws IOException
+ {
+ // module_name
+ int module_name_index = in.readUnsignedShort();
+ String mn = cpool.getModuleName(module_name_index);
+
+ int module_flags = in.readUnsignedShort();
+ boolean open = ((module_flags & ACC_OPEN) != 0);
+ boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
+
+ Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+
+ int module_version_index = in.readUnsignedShort();
+ if (module_version_index != 0) {
+ String vs = cpool.getUtf8(module_version_index);
+ builder.version(vs);
+ }
+
+ int requires_count = in.readUnsignedShort();
+ boolean requiresJavaBase = false;
+ for (int i=0; i<requires_count; i++) {
+ int requires_index = in.readUnsignedShort();
+ String dn = cpool.getModuleName(requires_index);
+
+ int requires_flags = in.readUnsignedShort();
+ Set<Requires.Modifier> mods;
+ if (requires_flags == 0) {
+ mods = Collections.emptySet();
+ } else {
+ mods = new HashSet<>();
+ if ((requires_flags & ACC_TRANSITIVE) != 0)
+ mods.add(Requires.Modifier.TRANSITIVE);
+ if ((requires_flags & ACC_STATIC_PHASE) != 0)
+ mods.add(Requires.Modifier.STATIC);
+ if ((requires_flags & ACC_SYNTHETIC) != 0)
+ mods.add(Requires.Modifier.SYNTHETIC);
+ if ((requires_flags & ACC_MANDATED) != 0)
+ mods.add(Requires.Modifier.MANDATED);
+ }
+
+ int requires_version_index = in.readUnsignedShort();
+ Version compiledVersion = null;
+ if (requires_version_index != 0) {
+ String vs = cpool.getUtf8(requires_version_index);
+ compiledVersion = Version.parse(vs);
+ }
+
+ if (compiledVersion == null) {
+ builder.requires(mods, dn);
+ } else {
+ builder.requires(mods, dn, compiledVersion);
+ }
+
+ if (dn.equals("java.base"))
+ requiresJavaBase = true;
+ }
+ if (mn.equals("java.base")) {
+ if (requires_count > 0) {
+ throw invalidModuleDescriptor("The requires table for java.base"
+ + " must be 0 length");
+ }
+ } else if (!requiresJavaBase) {
+ throw invalidModuleDescriptor("The requires table must have"
+ + " an entry for java.base");
+ }
+
+ int exports_count = in.readUnsignedShort();
+ if (exports_count > 0) {
+ for (int i=0; i<exports_count; i++) {
+ int exports_index = in.readUnsignedShort();
+ String pkg = cpool.getPackageName(exports_index);
+
+ Set<Exports.Modifier> mods;
+ int exports_flags = in.readUnsignedShort();
+ if (exports_flags == 0) {
+ mods = Collections.emptySet();
+ } else {
+ mods = new HashSet<>();
+ if ((exports_flags & ACC_SYNTHETIC) != 0)
+ mods.add(Exports.Modifier.SYNTHETIC);
+ if ((exports_flags & ACC_MANDATED) != 0)
+ mods.add(Exports.Modifier.MANDATED);
+ }
+
+ int exports_to_count = in.readUnsignedShort();
+ if (exports_to_count > 0) {
+ Set<String> targets = new HashSet<>(exports_to_count);
+ for (int j=0; j<exports_to_count; j++) {
+ int exports_to_index = in.readUnsignedShort();
+ targets.add(cpool.getModuleName(exports_to_index));
+ }
+ builder.exports(mods, pkg, targets);
+ } else {
+ builder.exports(mods, pkg);
+ }
+ }
+ }
+
+ int opens_count = in.readUnsignedShort();
+ if (opens_count > 0) {
+ if (open) {
+ throw invalidModuleDescriptor("The opens table for an open"
+ + " module must be 0 length");
+ }
+ for (int i=0; i<opens_count; i++) {
+ int opens_index = in.readUnsignedShort();
+ String pkg = cpool.getPackageName(opens_index);
+
+ Set<Opens.Modifier> mods;
+ int opens_flags = in.readUnsignedShort();
+ if (opens_flags == 0) {
+ mods = Collections.emptySet();
+ } else {
+ mods = new HashSet<>();
+ if ((opens_flags & ACC_SYNTHETIC) != 0)
+ mods.add(Opens.Modifier.SYNTHETIC);
+ if ((opens_flags & ACC_MANDATED) != 0)
+ mods.add(Opens.Modifier.MANDATED);
+ }
+
+ int open_to_count = in.readUnsignedShort();
+ if (open_to_count > 0) {
+ Set<String> targets = new HashSet<>(open_to_count);
+ for (int j=0; j<open_to_count; j++) {
+ int opens_to_index = in.readUnsignedShort();
+ targets.add(cpool.getModuleName(opens_to_index));
+ }
+ builder.opens(mods, pkg, targets);
+ } else {
+ builder.opens(mods, pkg);
+ }
+ }
+ }
+
+ int uses_count = in.readUnsignedShort();
+ if (uses_count > 0) {
+ for (int i=0; i<uses_count; i++) {
+ int index = in.readUnsignedShort();
+ String sn = cpool.getClassName(index);
+ builder.uses(sn);
+ }
+ }
+
+ int provides_count = in.readUnsignedShort();
+ if (provides_count > 0) {
+ for (int i=0; i<provides_count; i++) {
+ int index = in.readUnsignedShort();
+ String sn = cpool.getClassName(index);
+ int with_count = in.readUnsignedShort();
+ List<String> providers = new ArrayList<>(with_count);
+ for (int j=0; j<with_count; j++) {
+ index = in.readUnsignedShort();
+ String pn = cpool.getClassName(index);
+ providers.add(pn);
+ }
+ builder.provides(sn, providers);
+ }
+ }
+
+ return builder;
+ }
+
+ /**
+ * Reads the ModulePackages attribute
+ */
+ private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
+ throws IOException
+ {
+ int package_count = in.readUnsignedShort();
+ Set<String> packages = new HashSet<>(package_count);
+ for (int i=0; i<package_count; i++) {
+ int index = in.readUnsignedShort();
+ String pn = cpool.getPackageName(index);
+ boolean added = packages.add(pn);
+ if (!added) {
+ throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
+ + "attribute more than once");
+ }
+ }
+ return packages;
+ }
+
+ /**
+ * Reads the ModuleMainClass attribute
+ */
+ private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
+ throws IOException
+ {
+ int index = in.readUnsignedShort();
+ return cpool.getClassName(index);
+ }
+
+ /**
+ * Reads the ModuleTarget attribute
+ */
+ private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
+ throws IOException
+ {
+ String[] values = new String[3];
+
+ int name_index = in.readUnsignedShort();
+ if (name_index != 0)
+ values[0] = cpool.getUtf8(name_index);
+
+ int arch_index = in.readUnsignedShort();
+ if (arch_index != 0)
+ values[1] = cpool.getUtf8(arch_index);
+
+ int version_index = in.readUnsignedShort();
+ if (version_index != 0)
+ values[2] = cpool.getUtf8(version_index);
+
+ return values;
+ }
+
+
+ /**
+ * Reads the ModuleHashes attribute
+ */
+ private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
+ throws IOException
+ {
+ int algorithm_index = in.readUnsignedShort();
+ String algorithm = cpool.getUtf8(algorithm_index);
+
+ int hash_count = in.readUnsignedShort();
+ Map<String, byte[]> map = new HashMap<>(hash_count);
+ for (int i=0; i<hash_count; i++) {
+ int module_name_index = in.readUnsignedShort();
+ String mn = cpool.getModuleName(module_name_index);
+ int hash_length = in.readUnsignedShort();
+ if (hash_length == 0) {
+ throw invalidModuleDescriptor("hash_length == 0");
+ }
+ byte[] hash = new byte[hash_length];
+ in.readFully(hash);
+ map.put(mn, hash);
+ }
+
+ return new ModuleHashes(algorithm, map);
+ }
+
+ /**
+ * Reads the ModuleResolution attribute.
+ */
+ private ModuleResolution readModuleResolution(DataInput in,
+ ConstantPool cpool)
+ throws IOException
+ {
+ int flags = in.readUnsignedShort();
+
+ int reason = 0;
+ if ((flags & WARN_DEPRECATED) != 0)
+ reason = WARN_DEPRECATED;
+ if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
+ if (reason != 0)
+ throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+ reason = WARN_DEPRECATED_FOR_REMOVAL;
+ }
+ if ((flags & WARN_INCUBATING) != 0) {
+ if (reason != 0)
+ throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+ }
+
+ return new ModuleResolution(flags);
+ }
+
+
+ /**
+ * Returns true if the given attribute can be present at most once
+ * in the class file. Returns false otherwise.
+ */
+ private static boolean isAttributeAtMostOnce(String name) {
+
+ if (name.equals(MODULE) ||
+ name.equals(SOURCE_FILE) ||
+ name.equals(SDE) ||
+ name.equals(MODULE_PACKAGES) ||
+ name.equals(MODULE_MAIN_CLASS) ||
+ name.equals(MODULE_TARGET) ||
+ name.equals(MODULE_HASHES) ||
+ name.equals(MODULE_RESOLUTION))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Return true if the given attribute name is the name of a pre-defined
+ * attribute that is not allowed in the class file.
+ *
+ * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
+ * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+ */
+ private static boolean isAttributeDisallowed(String name) {
+ Set<String> notAllowed = predefinedNotAllowed;
+ if (notAllowed == null) {
+ notAllowed = Set.of(
+ "ConstantValue",
+ "Code",
+ "StackMapTable",
+ "Exceptions",
+ "EnclosingMethod",
+ "Signature",
+ "LineNumberTable",
+ "LocalVariableTable",
+ "LocalVariableTypeTable",
+ "RuntimeVisibleParameterAnnotations",
+ "RuntimeInvisibleParameterAnnotations",
+ "RuntimeVisibleTypeAnnotations",
+ "RuntimeInvisibleTypeAnnotations",
+ "Synthetic",
+ "AnnotationDefault",
+ "BootstrapMethods",
+ "MethodParameters");
+ predefinedNotAllowed = notAllowed;
+ }
+ return notAllowed.contains(name);
+ }
+
+ // lazily created set the pre-defined attributes that are not allowed
+ private static volatile Set<String> predefinedNotAllowed;
+
+
+ /**
+ * The constant pool in a class file.
+ */
+ private static class ConstantPool {
+ static final int CONSTANT_Utf8 = 1;
+ static final int CONSTANT_Integer = 3;
+ static final int CONSTANT_Float = 4;
+ static final int CONSTANT_Long = 5;
+ static final int CONSTANT_Double = 6;
+ static final int CONSTANT_Class = 7;
+ static final int CONSTANT_String = 8;
+ static final int CONSTANT_Fieldref = 9;
+ static final int CONSTANT_Methodref = 10;
+ static final int CONSTANT_InterfaceMethodref = 11;
+ static final int CONSTANT_NameAndType = 12;
+ static final int CONSTANT_MethodHandle = 15;
+ static final int CONSTANT_MethodType = 16;
+ static final int CONSTANT_InvokeDynamic = 18;
+ static final int CONSTANT_Module = 19;
+ static final int CONSTANT_Package = 20;
+
+ private static class Entry {
+ protected Entry(int tag) {
+ this.tag = tag;
+ }
+ final int tag;
+ }
+
+ private static class IndexEntry extends Entry {
+ IndexEntry(int tag, int index) {
+ super(tag);
+ this.index = index;
+ }
+ final int index;
+ }
+
+ private static class Index2Entry extends Entry {
+ Index2Entry(int tag, int index1, int index2) {
+ super(tag);
+ this.index1 = index1;
+ this.index2 = index2;
+ }
+ final int index1, index2;
+ }
+
+ private static class ValueEntry extends Entry {
+ ValueEntry(int tag, Object value) {
+ super(tag);
+ this.value = value;
+ }
+ final Object value;
+ }
+
+ final Entry[] pool;
+
+ ConstantPool(DataInput in) throws IOException {
+ int count = in.readUnsignedShort();
+ pool = new Entry[count];
+
+ for (int i = 1; i < count; i++) {
+ int tag = in.readUnsignedByte();
+ switch (tag) {
+
+ case CONSTANT_Utf8:
+ String svalue = in.readUTF();
+ pool[i] = new ValueEntry(tag, svalue);
+ break;
+
+ case CONSTANT_Class:
+ case CONSTANT_Package:
+ case CONSTANT_Module:
+ case CONSTANT_String:
+ int index = in.readUnsignedShort();
+ pool[i] = new IndexEntry(tag, index);
+ break;
+
+ case CONSTANT_Double:
+ double dvalue = in.readDouble();
+ pool[i] = new ValueEntry(tag, dvalue);
+ i++;
+ break;
+
+ case CONSTANT_Fieldref:
+ case CONSTANT_InterfaceMethodref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InvokeDynamic:
+ case CONSTANT_NameAndType:
+ int index1 = in.readUnsignedShort();
+ int index2 = in.readUnsignedShort();
+ pool[i] = new Index2Entry(tag, index1, index2);
+ break;
+
+ case CONSTANT_MethodHandle:
+ int refKind = in.readUnsignedByte();
+ index = in.readUnsignedShort();
+ pool[i] = new Index2Entry(tag, refKind, index);
+ break;
+
+ case CONSTANT_MethodType:
+ index = in.readUnsignedShort();
+ pool[i] = new IndexEntry(tag, index);
+ break;
+
+ case CONSTANT_Float:
+ float fvalue = in.readFloat();
+ pool[i] = new ValueEntry(tag, fvalue);
+ break;
+
+ case CONSTANT_Integer:
+ int ivalue = in.readInt();
+ pool[i] = new ValueEntry(tag, ivalue);
+ break;
+
+ case CONSTANT_Long:
+ long lvalue = in.readLong();
+ pool[i] = new ValueEntry(tag, lvalue);
+ i++;
+ break;
+
+ default:
+ throw invalidModuleDescriptor("Bad constant pool entry: "
+ + i);
+ }
+ }
+ }
+
+ String getClassName(int index) {
+ checkIndex(index);
+ Entry e = pool[index];
+ if (e.tag != CONSTANT_Class) {
+ throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
+ + index);
+ }
+ String value = getUtf8(((IndexEntry) e).index);
+ checkUnqualifiedName("CONSTANT_Class", index, value);
+ return value.replace('/', '.'); // internal form -> binary name
+ }
+
+ String getPackageName(int index) {
+ checkIndex(index);
+ Entry e = pool[index];
+ if (e.tag != CONSTANT_Package) {
+ throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
+ + index);
+ }
+ String value = getUtf8(((IndexEntry) e).index);
+ checkUnqualifiedName("CONSTANT_Package", index, value);
+ return value.replace('/', '.'); // internal form -> binary name
+ }
+
+ String getModuleName(int index) {
+ checkIndex(index);
+ Entry e = pool[index];
+ if (e.tag != CONSTANT_Module) {
+ throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
+ + index);
+ }
+ String value = getUtf8(((IndexEntry) e).index);
+ return decodeModuleName(index, value);
+ }
+
+ String getUtf8(int index) {
+ checkIndex(index);
+ Entry e = pool[index];
+ if (e.tag != CONSTANT_Utf8) {
+ throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
+ + index);
+ }
+ return (String) (((ValueEntry) e).value);
+ }
+
+ void checkIndex(int index) {
+ if (index < 1 || index >= pool.length)
+ throw invalidModuleDescriptor("Index into constant pool out of range");
+ }
+
+ void checkUnqualifiedName(String what, int index, String value) {
+ int len = value.length();
+ if (len == 0) {
+ throw invalidModuleDescriptor(what + " at entry " + index
+ + " has zero length");
+ }
+ for (int i=0; i<len; i++) {
+ char c = value.charAt(i);
+ if (c == '.' || c == ';' || c == '[') {
+ throw invalidModuleDescriptor(what + " at entry " + index
+ + " has illegal character: '"
+ + c + "'");
+ }
+ }
+ }
+
+ /**
+ * "Decode" a module name that has been read from the constant pool.
+ */
+ String decodeModuleName(int index, String value) {
+ int len = value.length();
+ if (len == 0) {
+ throw invalidModuleDescriptor("CONSTANT_Module at entry "
+ + index + " is zero length");
+ }
+ int i = 0;
+ while (i < len) {
+ int cp = value.codePointAt(i);
+ if (cp == ':' || cp == '@' || cp < 0x20) {
+ throw invalidModuleDescriptor("CONSTANT_Module at entry "
+ + index + " has illegal character: "
+ + Character.getName(cp));
+ }
+
+ // blackslash is the escape character
+ if (cp == '\\')
+ return decodeModuleName(index, i, value);
+
+ i += Character.charCount(cp);
+ }
+ return value;
+ }
+
+ /**
+ * "Decode" a module name that has been read from the constant pool and
+ * partly checked for illegal characters (up to position {@code i}).
+ */
+ String decodeModuleName(int index, int i, String value) {
+ StringBuilder sb = new StringBuilder();
+
+ // copy the code points that have been checked
+ int j = 0;
+ while (j < i) {
+ int cp = value.codePointAt(j);
+ sb.appendCodePoint(cp);
+ j += Character.charCount(cp);
+ }
+
+ // decode from position {@code i} to end
+ int len = value.length();
+ while (i < len) {
+ int cp = value.codePointAt(i);
+ if (cp == ':' || cp == '@' || cp < 0x20) {
+ throw invalidModuleDescriptor("CONSTANT_Module at entry "
+ + index + " has illegal character: "
+ + Character.getName(cp));
+ }
+
+ // blackslash is the escape character
+ if (cp == '\\') {
+ j = i + Character.charCount(cp);
+ if (j >= len) {
+ throw invalidModuleDescriptor("CONSTANT_Module at entry "
+ + index + " has illegal "
+ + "escape sequence");
+ }
+ int next = value.codePointAt(j);
+ if (next != '\\' && next != ':' && next != '@') {
+ throw invalidModuleDescriptor("CONSTANT_Module at entry "
+ + index + " has illegal "
+ + "escape sequence");
+ }
+ sb.appendCodePoint(next);
+ i += Character.charCount(next);
+ } else {
+ sb.appendCodePoint(cp);
+ }
+
+ i += Character.charCount(cp);
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * A DataInput implementation that reads from a ByteBuffer.
+ */
+ private static class DataInputWrapper implements DataInput {
+ private final ByteBuffer bb;
+
+ DataInputWrapper(ByteBuffer bb) {
+ this.bb = bb;
+ }
+
+ @Override
+ public void readFully(byte b[]) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ @Override
+ public void readFully(byte b[], int off, int len) throws IOException {
+ try {
+ bb.get(b, off, len);
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public int skipBytes(int n) {
+ int skip = Math.min(n, bb.remaining());
+ bb.position(bb.position() + skip);
+ return skip;
+ }
+
+ @Override
+ public boolean readBoolean() throws IOException {
+ try {
+ int ch = bb.get();
+ return (ch != 0);
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public byte readByte() throws IOException {
+ try {
+ return bb.get();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public int readUnsignedByte() throws IOException {
+ try {
+ return ((int) bb.get()) & 0xff;
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public short readShort() throws IOException {
+ try {
+ return bb.getShort();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public int readUnsignedShort() throws IOException {
+ try {
+ return ((int) bb.getShort()) & 0xffff;
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public char readChar() throws IOException {
+ try {
+ return bb.getChar();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public int readInt() throws IOException {
+ try {
+ return bb.getInt();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public long readLong() throws IOException {
+ try {
+ return bb.getLong();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public float readFloat() throws IOException {
+ try {
+ return bb.getFloat();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public double readDouble() throws IOException {
+ try {
+ return bb.getDouble();
+ } catch (BufferUnderflowException e) {
+ throw new EOFException(e.getMessage());
+ }
+ }
+
+ @Override
+ public String readLine() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public String readUTF() throws IOException {
+ // ### Need to measure the performance and feasibility of using
+ // the UTF-8 decoder instead.
+ return DataInputStream.readUTF(this);
+ }
+ }
+
+ /**
+ * Returns an InvalidModuleDescriptorException with the given detail
+ * message
+ */
+ private static InvalidModuleDescriptorException
+ invalidModuleDescriptor(String msg) {
+ return new InvalidModuleDescriptorException(msg);
+ }
+
+ /**
+ * Returns an InvalidModuleDescriptorException with a detail message to
+ * indicate that the class file is truncated.
+ */
+ private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
+ return invalidModuleDescriptor("Truncated module-info.class");
+ }
+
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Mon Dec 19 16:05:38 2016 +0000
@@ -70,6 +70,9 @@
// the hashes for the Hashes attribute
private ModuleHashes hashes;
+ // the value of the ModuleResolution attribute
+ private ModuleResolution moduleResolution;
+
private ModuleInfoExtender(InputStream in) {
this.in = in;
}
@@ -121,6 +124,14 @@
}
/**
+ * Sets the value for the ModuleResolution attribute.
+ */
+ public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
+ this.moduleResolution = mres;
+ return this;
+ }
+
+ /**
* A ClassVisitor that supports adding class file attributes. If an
* attribute already exists then the first occurence of the attribute
* is replaced.
@@ -183,21 +194,20 @@
if (packages != null)
cv.addAttribute(new ModulePackagesAttribute(packages));
- if (version != null)
- cv.addAttribute(new ModuleVersionAttribute(version));
if (mainClass != null)
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
if (osName != null || osArch != null || osVersion != null)
cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
if (hashes != null)
cv.addAttribute(new ModuleHashesAttribute(hashes));
+ if (moduleResolution != null)
+ cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
List<Attribute> attrs = new ArrayList<>();
// prototypes of attributes that should be parsed
- attrs.add(new ModuleAttribute());
+ attrs.add(new ModuleAttribute(version));
attrs.add(new ModulePackagesAttribute());
- attrs.add(new ModuleVersionAttribute());
attrs.add(new ModuleMainClassAttribute());
attrs.add(new ModuleTargetAttribute());
attrs.add(new ModuleHashesAttribute());
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Mon Dec 19 16:05:38 2016 +0000
@@ -49,13 +49,12 @@
* returning it in a byte array.
*/
private static byte[] toModuleInfo(ModuleDescriptor md) {
-
ClassWriter cw = new ClassWriter(0);
- cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
+ cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
cw.visitAttribute(new ModuleAttribute(md));
- // for tests: write the Packages attribute when there are packages that
- // aren't exported or open
+ // for tests: write the ModulePackages attribute when there are packages
+ // that aren't exported or open
Stream<String> exported = md.exports().stream()
.map(ModuleDescriptor.Exports::source);
Stream<String> open = md.opens().stream()
@@ -64,10 +63,10 @@
if (md.packages().size() > exportedOrOpen)
cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
- md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
+ // write ModuleMainClass if the module has a main class
md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
- // write the TargetPlatform attribute if have any of OS name/arch/version
+ // write ModuleTarget attribute if have any of OS name/arch/version
String osName = md.osName().orElse(null);
String osArch = md.osArch().orElse(null);
String osVersion = md.osVersion().orElse(null);
@@ -76,7 +75,6 @@
}
cw.visitEnd();
-
return cw.toByteArray();
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Mon Dec 19 16:05:38 2016 +0000
@@ -149,9 +149,22 @@
// return a module reference to the patched module
URI location = mref.location().orElse(null);
- return JLMA.newPatchedModule(descriptor,
- location,
- () -> new PatchedModuleReader(paths, mref));
+
+ ModuleHashes recordedHashes = null;
+ ModuleResolution mres = null;
+ if (mref instanceof ModuleReferenceImpl) {
+ ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
+ recordedHashes = impl.recordedHashes();
+ mres = impl.moduleResolution();
+ }
+
+ return new ModuleReferenceImpl(descriptor,
+ location,
+ () -> new PatchedModuleReader(paths, mref),
+ this,
+ recordedHashes,
+ null,
+ mres);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2014, 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.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.module.FindException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
+import jdk.internal.perf.PerfCounter;
+import jdk.internal.util.jar.VersionedStream;
+
+
+/**
+ * A {@code ModuleFinder} that locates modules on the file system by searching
+ * a sequence of directories or packaged modules.
+ *
+ * The {@code ModuleFinder} can be created to work in either the run-time
+ * or link-time phases. In both cases it locates modular JAR and exploded
+ * modules. When created for link-time then it additionally locates
+ * modules in JMOD files.
+ */
+
+public class ModulePath implements ModuleFinder {
+ private static final String MODULE_INFO = "module-info.class";
+
+ // the version to use for multi-release modular JARs
+ private final Runtime.Version releaseVersion;
+
+ // true for the link phase (supports modules packaged in JMOD format)
+ private final boolean isLinkPhase;
+
+ // the entries on this module path
+ private final Path[] entries;
+ private int next;
+
+ // map of module name to module reference map for modules already located
+ private final Map<String, ModuleReference> cachedModules = new HashMap<>();
+
+ public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
+ this.releaseVersion = version;
+ this.isLinkPhase = isLinkPhase;
+ this.entries = entries.clone();
+ for (Path entry : this.entries) {
+ Objects.requireNonNull(entry);
+ }
+ }
+
+ public ModulePath(Path... entries) {
+ this(JarFile.runtimeVersion(), false, entries);
+ }
+
+ @Override
+ public Optional<ModuleReference> find(String name) {
+ Objects.requireNonNull(name);
+
+ // try cached modules
+ ModuleReference m = cachedModules.get(name);
+ if (m != null)
+ return Optional.of(m);
+
+ // the module may not have been encountered yet
+ while (hasNextEntry()) {
+ scanNextEntry();
+ m = cachedModules.get(name);
+ if (m != null)
+ return Optional.of(m);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Set<ModuleReference> findAll() {
+ // need to ensure that all entries have been scanned
+ while (hasNextEntry()) {
+ scanNextEntry();
+ }
+ return cachedModules.values().stream().collect(Collectors.toSet());
+ }
+
+ /**
+ * Returns {@code true} if there are additional entries to scan
+ */
+ private boolean hasNextEntry() {
+ return next < entries.length;
+ }
+
+ /**
+ * Scans the next entry on the module path. A no-op if all entries have
+ * already been scanned.
+ *
+ * @throws FindException if an error occurs scanning the next entry
+ */
+ private void scanNextEntry() {
+ if (hasNextEntry()) {
+
+ long t0 = System.nanoTime();
+
+ Path entry = entries[next];
+ Map<String, ModuleReference> modules = scan(entry);
+ next++;
+
+ // update cache, ignoring duplicates
+ int initialSize = cachedModules.size();
+ for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
+ cachedModules.putIfAbsent(e.getKey(), e.getValue());
+ }
+
+ // update counters
+ int added = cachedModules.size() - initialSize;
+ moduleCount.add(added);
+
+ scanTime.addElapsedTimeFrom(t0);
+ }
+ }
+
+
+ /**
+ * Scan the given module path entry. If the entry is a directory then it is
+ * a directory of modules or an exploded module. If the entry is a regular
+ * file then it is assumed to be a packaged module.
+ *
+ * @throws FindException if an error occurs scanning the entry
+ */
+ private Map<String, ModuleReference> scan(Path entry) {
+
+ BasicFileAttributes attrs;
+ try {
+ attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+ } catch (NoSuchFileException e) {
+ return Collections.emptyMap();
+ } catch (IOException ioe) {
+ throw new FindException(ioe);
+ }
+
+ try {
+
+ if (attrs.isDirectory()) {
+ Path mi = entry.resolve(MODULE_INFO);
+ if (!Files.exists(mi)) {
+ // does not exist or unable to determine so assume a
+ // directory of modules
+ return scanDirectory(entry);
+ }
+ }
+
+ // packaged or exploded module
+ ModuleReference mref = readModule(entry, attrs);
+ if (mref != null) {
+ String name = mref.descriptor().name();
+ return Collections.singletonMap(name, mref);
+ } else {
+ // skipped
+ return Collections.emptyMap();
+ }
+
+ } catch (IOException ioe) {
+ throw new FindException(ioe);
+ }
+ }
+
+
+ /**
+ * Scans the given directory for packaged or exploded modules.
+ *
+ * @return a map of module name to ModuleReference for the modules found
+ * in the directory
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws FindException if an error occurs scanning the entry or the
+ * directory contains two or more modules with the same name
+ */
+ private Map<String, ModuleReference> scanDirectory(Path dir)
+ throws IOException
+ {
+ // The map of name -> mref of modules found in this directory.
+ Map<String, ModuleReference> nameToReference = new HashMap<>();
+
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+ for (Path entry : stream) {
+ BasicFileAttributes attrs;
+ try {
+ attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+ } catch (NoSuchFileException ignore) {
+ // file has been removed or moved, ignore for now
+ continue;
+ }
+
+ ModuleReference mref = readModule(entry, attrs);
+
+ // module found
+ if (mref != null) {
+ // can have at most one version of a module in the directory
+ String name = mref.descriptor().name();
+ ModuleReference previous = nameToReference.put(name, mref);
+ if (previous != null) {
+ String fn1 = fileName(mref);
+ String fn2 = fileName(previous);
+ throw new FindException("Two versions of module "
+ + name + " found in " + dir
+ + " (" + fn1 + " and " + fn2 + ")");
+ }
+ }
+ }
+ }
+
+ return nameToReference;
+ }
+
+
+ /**
+ * Locates a packaged or exploded module, returning a {@code ModuleReference}
+ * to the module. Returns {@code null} if the entry is skipped because it is
+ * to a directory that does not contain a module-info.class or it's a hidden
+ * file.
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws FindException if the file is not recognized as a module or an
+ * error occurs parsing its module descriptor
+ */
+ private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
+ throws IOException
+ {
+ try {
+
+ if (attrs.isDirectory()) {
+ return readExplodedModule(entry); // may return null
+ }
+
+ String fn = entry.getFileName().toString();
+ if (attrs.isRegularFile()) {
+ if (fn.endsWith(".jar")) {
+ return readJar(entry);
+ } else if (fn.endsWith(".jmod")) {
+ if (isLinkPhase)
+ return readJMod(entry);
+ throw new FindException("JMOD files not supported: " + entry);
+ }
+ }
+
+ // skip hidden files
+ if (fn.startsWith(".") || Files.isHidden(entry)) {
+ return null;
+ } else {
+ throw new FindException("Unrecognized module: " + entry);
+ }
+
+ } catch (InvalidModuleDescriptorException e) {
+ throw new FindException("Error reading module: " + entry, e);
+ }
+ }
+
+
+ /**
+ * Returns a string with the file name of the module if possible.
+ * If the module location is not a file URI then return the URI
+ * as a string.
+ */
+ private String fileName(ModuleReference mref) {
+ URI uri = mref.location().orElse(null);
+ if (uri != null) {
+ if (uri.getScheme().equalsIgnoreCase("file")) {
+ Path file = Paths.get(uri);
+ return file.getFileName().toString();
+ } else {
+ return uri.toString();
+ }
+ } else {
+ return "<unknown>";
+ }
+ }
+
+ // -- jmod files --
+
+ private Set<String> jmodPackages(JmodFile jf) {
+ return jf.stream()
+ .filter(e -> e.section() == Section.CLASSES)
+ .map(JmodFile.Entry::name)
+ .map(this::toPackageName)
+ .flatMap(Optional::stream)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Returns a {@code ModuleReference} to a module in jmod file on the
+ * file system.
+ *
+ * @throws IOException
+ * @throws InvalidModuleDescriptorException
+ */
+ private ModuleReference readJMod(Path file) throws IOException {
+ try (JmodFile jf = new JmodFile(file)) {
+ ModuleInfo.Attributes attrs;
+ try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+ attrs = ModuleInfo.read(in, () -> jmodPackages(jf));
+ }
+ return ModuleReferences.newJModModule(attrs, file);
+ }
+ }
+
+
+ // -- JAR files --
+
+ private static final String SERVICES_PREFIX = "META-INF/services/";
+
+ /**
+ * Returns the service type corresponding to the name of a services
+ * configuration file if it is a valid Java identifier.
+ *
+ * For example, if called with "META-INF/services/p.S" then this method
+ * returns a container with the value "p.S".
+ */
+ private Optional<String> toServiceName(String cf) {
+ assert cf.startsWith(SERVICES_PREFIX);
+ int index = cf.lastIndexOf("/") + 1;
+ if (index < cf.length()) {
+ String prefix = cf.substring(0, index);
+ if (prefix.equals(SERVICES_PREFIX)) {
+ String sn = cf.substring(index);
+ if (Checks.isJavaIdentifier(sn))
+ return Optional.of(sn);
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Reads the next line from the given reader and trims it of comments and
+ * leading/trailing white space.
+ *
+ * Returns null if the reader is at EOF.
+ */
+ private String nextLine(BufferedReader reader) throws IOException {
+ String ln = reader.readLine();
+ if (ln != null) {
+ int ci = ln.indexOf('#');
+ if (ci >= 0)
+ ln = ln.substring(0, ci);
+ ln = ln.trim();
+ }
+ return ln;
+ }
+
+ /**
+ * Treat the given JAR file as a module as follows:
+ *
+ * 1. The module name (and optionally the version) is derived from the file
+ * name of the JAR file
+ * 2. All packages are exported and open
+ * 3. It has no non-exported/non-open packages
+ * 4. The contents of any META-INF/services configuration files are mapped
+ * to "provides" declarations
+ * 5. The Main-Class attribute in the main attributes of the JAR manifest
+ * is mapped to the module descriptor mainClass
+ */
+ private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
+ throws IOException
+ {
+ // Derive module name and version from JAR file name
+
+ String fn = jf.getName();
+ int i = fn.lastIndexOf(File.separator);
+ if (i != -1)
+ fn = fn.substring(i+1);
+
+ // drop .jar
+ String mn = fn.substring(0, fn.length()-4);
+ String vs = null;
+
+ // find first occurrence of -${NUMBER}. or -${NUMBER}$
+ Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
+ if (matcher.find()) {
+ int start = matcher.start();
+
+ // attempt to parse the tail as a version string
+ try {
+ String tail = mn.substring(start+1);
+ ModuleDescriptor.Version.parse(tail);
+ vs = tail;
+ } catch (IllegalArgumentException ignore) { }
+
+ mn = mn.substring(0, start);
+ }
+
+ // finally clean up the module name
+ mn = cleanModuleName(mn);
+
+ // Builder throws IAE if module name is empty or invalid
+ ModuleDescriptor.Builder builder
+ = ModuleDescriptor.automaticModule(mn)
+ .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
+ if (vs != null)
+ builder.version(vs);
+
+ // scan the names of the entries in the JAR file
+ Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
+ .filter(e -> !e.isDirectory())
+ .map(JarEntry::getName)
+ .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
+ Collectors.toSet()));
+
+ Set<String> resources = map.get(Boolean.FALSE);
+ Set<String> configFiles = map.get(Boolean.TRUE);
+ // all packages are exported and open
+ resources.stream()
+ .map(this::toPackageName)
+ .flatMap(Optional::stream)
+ .distinct()
+ .forEach(pn -> builder.exports(pn).opens(pn));
+
+ // map names of service configuration files to service names
+ Set<String> serviceNames = configFiles.stream()
+ .map(this::toServiceName)
+ .flatMap(Optional::stream)
+ .collect(Collectors.toSet());
+
+ // parse each service configuration file
+ for (String sn : serviceNames) {
+ JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
+ List<String> providerClasses = new ArrayList<>();
+ try (InputStream in = jf.getInputStream(entry)) {
+ BufferedReader reader
+ = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ String cn;
+ while ((cn = nextLine(reader)) != null) {
+ if (cn.length() > 0) {
+ providerClasses.add(cn);
+ }
+ }
+ }
+ if (!providerClasses.isEmpty())
+ builder.provides(sn, providerClasses);
+ }
+
+ // Main-Class attribute if it exists
+ Manifest man = jf.getManifest();
+ if (man != null) {
+ Attributes attrs = man.getMainAttributes();
+ String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
+ if (mainClass != null)
+ builder.mainClass(mainClass.replace("/", "."));
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Patterns used to derive the module name from a JAR file name.
+ */
+ private static class Patterns {
+ static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
+ static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
+ static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
+ static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
+ static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
+ static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
+ }
+
+ /**
+ * Clean up candidate module name derived from a JAR file name.
+ */
+ private static String cleanModuleName(String mn) {
+ // drop trailing version from name
+ mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
+
+ // replace non-alphanumeric
+ mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
+
+ // collapse repeating dots
+ mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
+
+ // drop leading dots
+ if (mn.length() > 0 && mn.charAt(0) == '.')
+ mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
+
+ // drop trailing dots
+ int len = mn.length();
+ if (len > 0 && mn.charAt(len-1) == '.')
+ mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
+
+ return mn;
+ }
+
+ private Set<String> jarPackages(JarFile jf) {
+ return VersionedStream.stream(jf)
+ .filter(e -> !e.isDirectory())
+ .map(JarEntry::getName)
+ .map(this::toPackageName)
+ .flatMap(Optional::stream)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Returns a {@code ModuleReference} to a module in modular JAR file on
+ * the file system.
+ *
+ * @throws IOException
+ * @throws FindException
+ * @throws InvalidModuleDescriptorException
+ */
+ private ModuleReference readJar(Path file) throws IOException {
+ try (JarFile jf = new JarFile(file.toFile(),
+ true, // verify
+ ZipFile.OPEN_READ,
+ releaseVersion))
+ {
+ ModuleInfo.Attributes attrs;
+ JarEntry entry = jf.getJarEntry(MODULE_INFO);
+ if (entry == null) {
+
+ // no module-info.class so treat it as automatic module
+ try {
+ ModuleDescriptor md = deriveModuleDescriptor(jf);
+ attrs = new ModuleInfo.Attributes(md, null, null);
+ } catch (IllegalArgumentException iae) {
+ throw new FindException(
+ "Unable to derive module descriptor for: "
+ + jf.getName(), iae);
+ }
+
+ } else {
+ attrs = ModuleInfo.read(jf.getInputStream(entry),
+ () -> jarPackages(jf));
+ }
+
+ return ModuleReferences.newJarModule(attrs, file);
+ }
+ }
+
+
+ // -- exploded directories --
+
+ private Set<String> explodedPackages(Path dir) {
+ try {
+ return Files.find(dir, Integer.MAX_VALUE,
+ ((path, attrs) -> attrs.isRegularFile()))
+ .map(path -> dir.relativize(path))
+ .map(this::toPackageName)
+ .flatMap(Optional::stream)
+ .collect(Collectors.toSet());
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ }
+
+ /**
+ * Returns a {@code ModuleReference} to an exploded module on the file
+ * system or {@code null} if {@code module-info.class} not found.
+ *
+ * @throws IOException
+ * @throws InvalidModuleDescriptorException
+ */
+ private ModuleReference readExplodedModule(Path dir) throws IOException {
+ Path mi = dir.resolve(MODULE_INFO);
+ ModuleInfo.Attributes attrs;
+ try (InputStream in = Files.newInputStream(mi)) {
+ attrs = ModuleInfo.read(new BufferedInputStream(in),
+ () -> explodedPackages(dir));
+ } catch (NoSuchFileException e) {
+ // for now
+ return null;
+ }
+ return ModuleReferences.newExplodedModule(attrs, dir);
+ }
+
+ /**
+ * Maps the name of an entry in a JAR or ZIP file to a package name.
+ *
+ * @throws IllegalArgumentException if the name is a class file in
+ * the top-level directory of the JAR/ZIP file (and it's
+ * not module-info.class)
+ */
+ private Optional<String> toPackageName(String name) {
+ assert !name.endsWith("/");
+
+ int index = name.lastIndexOf("/");
+ if (index == -1) {
+ if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+ throw new IllegalArgumentException(name
+ + " found in top-level directory:"
+ + " (unnamed package not allowed in module)");
+ }
+ return Optional.empty();
+ }
+
+ String pn = name.substring(0, index).replace('/', '.');
+ if (Checks.isJavaIdentifier(pn)) {
+ return Optional.of(pn);
+ } else {
+ // not a valid package name
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * Maps the relative path of an entry in an exploded module to a package
+ * name.
+ *
+ * @throws IllegalArgumentException if the name is a class file in
+ * the top-level directory (and it's not module-info.class)
+ */
+ private Optional<String> toPackageName(Path file) {
+ assert file.getRoot() == null;
+
+ Path parent = file.getParent();
+ if (parent == null) {
+ String name = file.toString();
+ if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+ throw new IllegalArgumentException(name
+ + " found in in top-level directory"
+ + " (unnamed package not allowed in module)");
+ }
+ return Optional.empty();
+ }
+
+ String pn = parent.toString().replace(File.separatorChar, '.');
+ if (Checks.isJavaIdentifier(pn)) {
+ return Optional.of(pn);
+ } else {
+ // not a valid package name
+ return Optional.empty();
+ }
+ }
+
+ private static final PerfCounter scanTime
+ = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
+ private static final PerfCounter moduleCount
+ = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,169 @@
+/*
+ * 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. 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.IOException;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * A ModuleReference implementation that supports referencing a module that
+ * is patched and/or can be tied to other modules by means of hashes.
+ */
+
+public class ModuleReferenceImpl extends ModuleReference {
+
+ private final Supplier<ModuleReader> readerSupplier;
+
+ // non-null if the module is patched
+ private final ModulePatcher patcher;
+
+ // the hashes of other modules recorded in this module
+ private final ModuleHashes recordedHashes;
+
+ // the function that computes the hash of this module
+ private final ModuleHashes.HashSupplier hasher;
+
+ // ModuleResolution flags
+ private final ModuleResolution moduleResolution;
+
+ // cached hash of this module to avoid needing to compute it many times
+ private byte[] cachedHash;
+
+ /**
+ * Constructs a new instance of this class.
+ */
+ ModuleReferenceImpl(ModuleDescriptor descriptor,
+ URI location,
+ Supplier<ModuleReader> readerSupplier,
+ ModulePatcher patcher,
+ ModuleHashes recordedHashes,
+ ModuleHashes.HashSupplier hasher,
+ ModuleResolution moduleResolution)
+ {
+ super(descriptor, Objects.requireNonNull(location));
+ this.readerSupplier = readerSupplier;
+ this.patcher = patcher;
+ this.recordedHashes = recordedHashes;
+ this.hasher = hasher;
+ this.moduleResolution = moduleResolution;
+ }
+
+ @Override
+ public ModuleReader open() throws IOException {
+ try {
+ return readerSupplier.get();
+ } catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Returns {@code true} if this module has been patched via --patch-module.
+ */
+ public boolean isPatched() {
+ return (patcher != null);
+ }
+
+ /**
+ * Returns the hashes recorded in this module or {@code null} if there
+ * are no hashes recorded.
+ */
+ public ModuleHashes recordedHashes() {
+ return recordedHashes;
+ }
+
+ /**
+ * Returns the supplier that computes the hash of this module.
+ */
+ ModuleHashes.HashSupplier hasher() {
+ return hasher;
+ }
+
+ /**
+ * Returns the ModuleResolution flags.
+ */
+ public ModuleResolution moduleResolution() {
+ return moduleResolution;
+ }
+
+ /**
+ * Computes the hash of this module. Returns {@code null} if the hash
+ * cannot be computed.
+ *
+ * @throws java.io.UncheckedIOException if an I/O error occurs
+ */
+ public byte[] computeHash(String algorithm) {
+ byte[] result = cachedHash;
+ if (result != null)
+ return result;
+ if (hasher == null)
+ return null;
+ cachedHash = result = hasher.generate(algorithm);
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ int hc = hash;
+ if (hc == 0) {
+ hc = descriptor().hashCode();
+ hc = 43 * hc + Objects.hashCode(location());
+ hc = 43 * hc + Objects.hashCode(patcher);
+ if (hc == 0)
+ hc = -1;
+ hash = hc;
+ }
+ return hc;
+ }
+
+ private int hash;
+
+ @Override
+ public boolean equals(Object ob) {
+ if (!(ob instanceof ModuleReferenceImpl))
+ return false;
+ ModuleReferenceImpl that = (ModuleReferenceImpl)ob;
+
+ // assume module content, recorded hashes, etc. are the same
+ // when the modules have equal module descriptors, are at the
+ // same location, and are patched by the same patcher.
+ return Objects.equals(this.descriptor(), that.descriptor())
+ && Objects.equals(this.location(), that.location())
+ && Objects.equals(this.patcher, that.patcher);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,448 @@
+/*
+ * 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.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Supplier;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+import jdk.internal.util.jar.VersionedStream;
+import sun.net.www.ParseUtil;
+
+
+/**
+ * A factory for creating ModuleReference implementations where the modules are
+ * packaged as modular JAR file, JMOD files or where the modules are exploded
+ * on the file system.
+ */
+
+class ModuleReferences {
+
+ private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+ private ModuleReferences() { }
+
+ /**
+ * Creates a ModuleReference to a module or to patched module when
+ * creating modules for the boot Layer and --patch-module is specified.
+ */
+ private static ModuleReference newModule(ModuleInfo.Attributes attrs,
+ URI uri,
+ Supplier<ModuleReader> supplier,
+ HashSupplier hasher) {
+
+ ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
+ uri,
+ supplier,
+ null,
+ attrs.recordedHashes(),
+ hasher,
+ attrs.moduleResolution());
+ if (JLA.getBootLayer() == null)
+ mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+ return mref;
+ }
+
+ /**
+ * Creates a ModuleReference to a module packaged as a modular JAR.
+ */
+ static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
+ URI uri = file.toUri();
+ Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+ HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+ return newModule(attrs, uri, supplier, hasher);
+ }
+
+ /**
+ * Creates a ModuleReference to a module packaged as a JMOD.
+ */
+ static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
+ URI uri = file.toUri();
+ Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+ HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+ return newModule(attrs, uri, supplier, hasher);
+ }
+
+ /**
+ * Creates a ModuleReference to an exploded module.
+ */
+ static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
+ Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
+ return newModule(attrs, dir.toUri(), supplier, null);
+ }
+
+
+ /**
+ * A base module reader that encapsulates machinery required to close the
+ * module reader safely.
+ */
+ static abstract class SafeCloseModuleReader implements ModuleReader {
+
+ // RW lock to support safe close
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock readLock = lock.readLock();
+ private final Lock writeLock = lock.writeLock();
+ private boolean closed;
+
+ SafeCloseModuleReader() { }
+
+ /**
+ * Returns a URL to resource. This method is invoked by the find
+ * method to do the actual work of finding the resource.
+ */
+ abstract Optional<URI> implFind(String name) throws IOException;
+
+ /**
+ * Returns an input stream for reading a resource. This method is
+ * invoked by the open method to do the actual work of opening
+ * an input stream to the resource.
+ */
+ abstract Optional<InputStream> implOpen(String name) throws IOException;
+
+ /**
+ * Returns a stream of the names of resources in the module. This
+ * method is invoked by the list method to do the actual work of
+ * creating the stream.
+ */
+ abstract Stream<String> implList() throws IOException;
+
+ /**
+ * Closes the module reader. This method is invoked by close to do the
+ * actual work of closing the module reader.
+ */
+ abstract void implClose() throws IOException;
+
+ @Override
+ public final Optional<URI> find(String name) throws IOException {
+ readLock.lock();
+ try {
+ if (!closed) {
+ return implFind(name);
+ } else {
+ throw new IOException("ModuleReader is closed");
+ }
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+
+ @Override
+ public final Optional<InputStream> open(String name) throws IOException {
+ readLock.lock();
+ try {
+ if (!closed) {
+ return implOpen(name);
+ } else {
+ throw new IOException("ModuleReader is closed");
+ }
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public final Stream<String> list() throws IOException {
+ readLock.lock();
+ try {
+ if (!closed) {
+ return implList();
+ } else {
+ throw new IOException("ModuleReader is closed");
+ }
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public final void close() throws IOException {
+ writeLock.lock();
+ try {
+ if (!closed) {
+ closed = true;
+ implClose();
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ }
+ }
+
+
+ /**
+ * A ModuleReader for a modular JAR file.
+ */
+ static class JarModuleReader extends SafeCloseModuleReader {
+ private final JarFile jf;
+ private final URI uri;
+
+ static JarFile newJarFile(Path path) {
+ try {
+ return new JarFile(path.toFile(),
+ true, // verify
+ ZipFile.OPEN_READ,
+ JarFile.runtimeVersion());
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
+ JarModuleReader(Path path, URI uri) {
+ this.jf = newJarFile(path);
+ this.uri = uri;
+ }
+
+ private JarEntry getEntry(String name) {
+ return jf.getJarEntry(Objects.requireNonNull(name));
+ }
+
+ @Override
+ Optional<URI> implFind(String name) throws IOException {
+ JarEntry je = getEntry(name);
+ if (je != null) {
+ if (jf.isMultiRelease())
+ name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
+ String encodedPath = ParseUtil.encodePath(name, false);
+ String uris = "jar:" + uri + "!/" + encodedPath;
+ return Optional.of(URI.create(uris));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ Optional<InputStream> implOpen(String name) throws IOException {
+ JarEntry je = getEntry(name);
+ if (je != null) {
+ return Optional.of(jf.getInputStream(je));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ Stream<String> implList() throws IOException {
+ // take snapshot to avoid async close
+ List<String> names = VersionedStream.stream(jf)
+ .filter(e -> !e.isDirectory())
+ .map(JarEntry::getName)
+ .collect(Collectors.toList());
+ return names.stream();
+ }
+
+ @Override
+ void implClose() throws IOException {
+ jf.close();
+ }
+ }
+
+
+ /**
+ * A ModuleReader for a JMOD file.
+ */
+ static class JModModuleReader extends SafeCloseModuleReader {
+ private final JmodFile jf;
+ private final URI uri;
+
+ static JmodFile newJmodFile(Path path) {
+ try {
+ return new JmodFile(path);
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
+ JModModuleReader(Path path, URI uri) {
+ this.jf = newJmodFile(path);
+ this.uri = uri;
+ }
+
+ private JmodFile.Entry getEntry(String name) {
+ Objects.requireNonNull(name);
+ return jf.getEntry(JmodFile.Section.CLASSES, name);
+ }
+
+ @Override
+ Optional<URI> implFind(String name) {
+ JmodFile.Entry je = getEntry(name);
+ if (je != null) {
+ String encodedPath = ParseUtil.encodePath(name, false);
+ String uris = "jmod:" + uri + "!/" + encodedPath;
+ return Optional.of(URI.create(uris));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ Optional<InputStream> implOpen(String name) throws IOException {
+ JmodFile.Entry je = getEntry(name);
+ if (je != null) {
+ return Optional.of(jf.getInputStream(je));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ Stream<String> implList() throws IOException {
+ // take snapshot to avoid async close
+ List<String> names = jf.stream()
+ .filter(e -> e.section() == JmodFile.Section.CLASSES)
+ .map(JmodFile.Entry::name)
+ .collect(Collectors.toList());
+ return names.stream();
+ }
+
+ @Override
+ void implClose() throws IOException {
+ jf.close();
+ }
+ }
+
+
+ /**
+ * A ModuleReader for an exploded module.
+ */
+ static class ExplodedModuleReader implements ModuleReader {
+ private final Path dir;
+ private volatile boolean closed;
+
+ ExplodedModuleReader(Path dir) {
+ this.dir = dir;
+
+ // when running with a security manager then check that the caller
+ // has access to the directory.
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ boolean unused = Files.isDirectory(dir);
+ }
+ }
+
+ /**
+ * Returns a Path to access to the given resource.
+ */
+ private Path toPath(String name) {
+ Path path = Paths.get(name.replace('/', File.separatorChar));
+ if (path.getRoot() == null) {
+ return dir.resolve(path);
+ } else {
+ // drop the root component so that the resource is
+ // located relative to the module directory
+ int n = path.getNameCount();
+ return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
+ }
+ }
+
+ /**
+ * Throws IOException if the module reader is closed;
+ */
+ private void ensureOpen() throws IOException {
+ if (closed) throw new IOException("ModuleReader is closed");
+ }
+
+ @Override
+ public Optional<URI> find(String name) throws IOException {
+ ensureOpen();
+ Path path = toPath(name);
+ if (path != null && Files.isRegularFile(path)) {
+ try {
+ return Optional.of(path.toUri());
+ } catch (IOError e) {
+ throw (IOException) e.getCause();
+ }
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Optional<InputStream> open(String name) throws IOException {
+ ensureOpen();
+ Path path = toPath(name);
+ if (path != null && Files.isRegularFile(path)) {
+ return Optional.of(Files.newInputStream(path));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Optional<ByteBuffer> read(String name) throws IOException {
+ ensureOpen();
+ Path path = toPath(name);
+ if (path != null && Files.isRegularFile(path)) {
+ return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Stream<String> list() throws IOException {
+ ensureOpen();
+ // sym links not followed
+ return Files.find(dir, Integer.MAX_VALUE,
+ (path, attrs) -> attrs.isRegularFile())
+ .map(f -> dir.relativize(f)
+ .toString()
+ .replace(File.separatorChar, '/'));
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,114 @@
+/*
+ * 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. 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.ModuleReference;
+import static jdk.internal.module.ClassFileConstants.*;
+
+/**
+ * Represents the Module Resolution flags.
+ */
+public final class ModuleResolution {
+
+ final int value;
+
+ ModuleResolution(int value) {
+ this.value = value;
+ }
+
+ public static ModuleResolution empty() {
+ return new ModuleResolution(0);
+ }
+
+ public boolean doNotResolveByDefault() {
+ return (value & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
+ }
+
+ public boolean hasDeprecatedWarning() {
+ return (value & WARN_DEPRECATED) != 0;
+ }
+
+ public boolean hasDeprecatedForRemovalWarning() {
+ return (value & WARN_DEPRECATED_FOR_REMOVAL) != 0;
+ }
+
+ public boolean hasIncubatingWarning() {
+ return (value & WARN_INCUBATING) != 0;
+ }
+
+ public ModuleResolution withDoNotResolveByDefault() {
+ return new ModuleResolution(value | DO_NOT_RESOLVE_BY_DEFAULT);
+ }
+
+ public ModuleResolution withDeprecated() {
+ if ((value & (WARN_DEPRECATED_FOR_REMOVAL | WARN_INCUBATING)) != 0)
+ throw new InternalError("cannot add deprecated to " + value);
+ return new ModuleResolution(value | WARN_DEPRECATED);
+ }
+
+ public ModuleResolution withDeprecatedForRemoval() {
+ if ((value & (WARN_DEPRECATED | WARN_INCUBATING)) != 0)
+ throw new InternalError("cannot add deprecated for removal to " + value);
+ return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
+ }
+ public ModuleResolution withIncubating() {
+ if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
+ throw new InternalError("cannot add incubating to " + value);
+ return new ModuleResolution(value | WARN_INCUBATING);
+ }
+
+ public int value() {
+ return value;
+ }
+
+ public static boolean doNotResolveByDefault(ModuleReference mref) {
+ // get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
+ if (!(mref instanceof ModuleReferenceImpl))
+ return false;
+
+ ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+ if (mres != null)
+ return mres.doNotResolveByDefault();
+
+ return false;
+ }
+
+ public static boolean hasIncubatingWarning(ModuleReference mref) {
+ if (!(mref instanceof ModuleReferenceImpl))
+ return false;
+
+ ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+ if (mres != null)
+ return mres.hasIncubatingWarning();
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "[value=" + value + "]";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,443 @@
+/*
+ * 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();
+ }
+
+ // 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;
+ 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();
+ }
+ }
+
+ 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,
+ 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,
+ 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,
+ 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");
+ 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(imageReader.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 = 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<? 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 Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Mon Dec 19 16:05:38 2016 +0000
@@ -29,14 +29,14 @@
/*
* SystemModules class will be generated at link time to create
- * ModuleDescriptor for the installed modules directly to improve
+ * ModuleDescriptor for the system modules directly to improve
* the module descriptor reconstitution time.
*
* 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 jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin
+ * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
*/
public final class SystemModules {
/**
@@ -49,11 +49,6 @@
public static final String[] MODULE_NAMES = new String[0];
/**
- * Hash of system modules.
- */
- public static byte[][] MODULES_TO_HASH = new byte[0][];
-
- /**
* Number of packages in the boot layer from the installed modules.
*
* Don't make it final to avoid inlining during compile time as
@@ -66,8 +61,24 @@
*
* When running an exploded image it returns an empty array.
*/
- public static ModuleDescriptor[] modules() {
- throw new InternalError("should not reach here");
+ public static ModuleDescriptor[] descriptors() {
+ throw new InternalError("expected to be overridden at link time");
}
+ /**
+ * 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.
+ */
+ public static ModuleHashes[] hashes() {
+ throw new InternalError("expected to be overridden at link time");
+ }
+
+ /**
+ * Returns a non-empty array of ModuleResolutions in the run-time image.
+ */
+ public static ModuleResolution[] moduleResolutions() {
+ throw new InternalError("expected to be overridden at link time");
+ }
}
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Mon Dec 19 16:05:38 2016 +0000
@@ -2491,6 +2491,40 @@
}
/**
+ * Reads a CONSTANT_Module_info item in {@code b}. This method is intended
+ * for {@link Attribute} sub classes, and is normally not needed by class
+ * generators or adapters.</i>
+ *
+ * @param index
+ * the start index of an unsigned short value in {@link #b b},
+ * whose value is the index of a module constant pool item.
+ * @param buf
+ * buffer to be used to read the item. This buffer must be
+ * sufficiently large. It is not automatically resized.
+ * @return the String corresponding to the specified module item.
+ */
+ public String readModule(int index, char[] buf) {
+ return readUTF8(items[readUnsignedShort(index)], buf);
+ }
+
+ /**
+ * Reads a CONSTANT_Pakcage_info item in {@code b}. This method is
+ * intended for {@link Attribute} sub slasses, and is normally not needed
+ * by class generators or adapters.</i>
+ *
+ * @param index
+ * the start index of an unsigned short value in {@link #b b},
+ * whose value is the index of a package constant pool item.
+ * @param buf
+ * buffer to be used to read the item. This buffer must be
+ * sufficiently large. It is not automatically resized.
+ * @return the String corresponding to the specified package item.
+ */
+ public String readPackage(int index, char[] buf) {
+ return readUTF8(items[readUnsignedShort(index)], buf);
+ }
+
+ /**
* Reads a numeric or string constant pool item in {@link #b b}. <i>This
* method is intended for {@link Attribute} sub classes, and is normally not
* needed by class generators or adapters.</i>
@@ -2516,6 +2550,8 @@
case ClassWriter.DOUBLE:
return Double.longBitsToDouble(readLong(index));
case ClassWriter.CLASS:
+ case ClassWriter.MODULE:
+ case ClassWriter.PACKAGE:
return Type.getObjectType(readUTF8(index, buf));
case ClassWriter.STR:
return readUTF8(index, buf);
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Mon Dec 19 16:05:38 2016 +0000
@@ -272,6 +272,16 @@
static final int INDY = 18;
/**
+ * The type of CONSTANT_Module constant pool items.
+ */
+ static final int MODULE = 19;
+
+ /**
+ * The type of CONSTANT_Package constant pool items.
+ */
+ static final int PACKAGE = 20;
+
+ /**
* The base value for all CONSTANT_MethodHandle constant pool items.
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
* different items.
@@ -1161,6 +1171,50 @@
}
/**
+ * Adds a module name to the constant pool.
+ *
+ * Does nothing if the constant pool already contains a similar item.
+ * <i>This method is intended for {@link Attribute} sub classes, and is
+ * normally not needed by class generators or adapters.</i>
+ *
+ * @param value
+ * the module name
+ * @return the index of a new or already existing module reference item.
+ */
+ public int newModule(String value) {
+ key2.set(MODULE, value, null, null);
+ Item result = get(key2);
+ if (result == null) {
+ pool.put12(MODULE, newUTF8(value));
+ result = new Item(index++, key2);
+ put(result);
+ }
+ return result.index;
+ }
+
+ /**
+ * Adds a package name to the constant pool.
+ *
+ * Does nothing if the constant pool already contains a similar item.
+ * <i>This method is intended for {@link Attribute} sub classes, and is
+ * normally not needed by class generators or adapters.</i>
+ *
+ * @param value
+ * the internal name of the package.
+ * @return the index of a new or already existing package reference item.
+ */
+ public int newPackage(String value) {
+ key2.set(PACKAGE, value, null, null);
+ Item result = get(key2);
+ if (result == null) {
+ pool.put12(PACKAGE, newUTF8(value));
+ result = new Item(index++, key2);
+ put(result);
+ }
+ return result.index;
+ }
+
+ /**
* Adds a method type reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java Mon Dec 19 16:05:38 2016 +0000
@@ -239,6 +239,8 @@
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.CLASS:
+ case ClassWriter.MODULE:
+ case ClassWriter.PACKAGE:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
@@ -311,6 +313,8 @@
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.CLASS:
+ case ClassWriter.MODULE:
+ case ClassWriter.PACKAGE:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1);
--- a/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java Mon Dec 19 16:05:38 2016 +0000
@@ -58,7 +58,6 @@
public class Cleaner
extends PhantomReference<Object>
- implements Runnable
{
// Dummy reference queue, needed because the PhantomReference constructor
@@ -153,12 +152,4 @@
}});
}
}
-
- @Override public void run() {
- SecurityManager security = System.getSecurityManager();
- if (security != null)
- security.checkPackageAccess("jdk.internal.ref");
- this.clean();
- }
-
}
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java Mon Dec 19 16:05:38 2016 +0000
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.VM;
import sun.security.action.GetPropertyAction;
@@ -218,8 +219,16 @@
if (c.isPrimitive())
return true;
- // check that memberModule exports the package to currentModule
- return memberModule.isExported(c.getPackageName(), currentModule);
+ String pkg = c.getPackageName();
+ boolean allowed = memberModule.isExported(pkg, currentModule);
+ if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
+ if (!SharedSecrets.getJavaLangReflectModuleAccess()
+ .isStaticallyExported(memberModule, pkg, currentModule)) {
+ String msg = currentModule + " allowed access to member of " + memberClass;
+ new Exception(msg).printStackTrace(System.err);
+ }
+ }
+ return allowed;
}
/**
@@ -348,23 +357,41 @@
}
- // true to print a stack trace when IAE is thrown
+ // true to print a stack trace when access fails
private static volatile boolean printStackWhenAccessFails;
- // true if printStackWhenAccessFails has been initialized
- private static volatile boolean printStackWhenAccessFailsSet;
+ // true to print a stack trace when access succeeds
+ private static volatile boolean printStackWhenAccessSucceeds;
- private static void printStackTraceIfNeeded(Throwable e) {
- if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
+ // true if printStack* values are initialized
+ private static volatile boolean printStackPropertiesSet;
+
+ private static void ensurePrintStackPropertiesSet() {
+ if (!printStackPropertiesSet && VM.initLevel() >= 1) {
String s = GetPropertyAction.privilegedGetProperty(
"sun.reflect.debugModuleAccessChecks");
- printStackWhenAccessFails =
- (s != null && !s.equalsIgnoreCase("false"));
- printStackWhenAccessFailsSet = true;
+ if (s != null) {
+ printStackWhenAccessFails = !s.equalsIgnoreCase("false");
+ printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
+ }
+ printStackPropertiesSet = true;
}
- if (printStackWhenAccessFails) {
- e.printStackTrace();
- }
+ }
+
+ public static void enableStackTraces() {
+ printStackWhenAccessFails = true;
+ printStackWhenAccessSucceeds = true;
+ printStackPropertiesSet = true;
+ }
+
+ public static boolean printStackTraceWhenAccessFails() {
+ ensurePrintStackPropertiesSet();
+ return printStackWhenAccessFails;
+ }
+
+ public static boolean printStackTraceWhenAccessSucceeds() {
+ ensurePrintStackPropertiesSet();
+ return printStackWhenAccessSucceeds;
}
/**
@@ -416,17 +443,10 @@
throws IllegalAccessException
{
IllegalAccessException e = new IllegalAccessException(msg);
- printStackTraceIfNeeded(e);
+ ensurePrintStackPropertiesSet();
+ if (printStackWhenAccessFails) {
+ e.printStackTrace(System.err);
+ }
throw e;
}
-
- /**
- * Throws InaccessibleObjectException with the given exception message.
- */
- public static void throwInaccessibleObjectException(String msg) {
- InaccessibleObjectException e = new InaccessibleObjectException(msg);
- printStackTraceIfNeeded(e);
- throw e;
- }
-
}
--- a/jdk/src/java.base/share/classes/module-info.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/module-info.java Mon Dec 19 16:05:38 2016 +0000
@@ -180,7 +180,8 @@
java.management,
jdk.jvmstat;
exports jdk.internal.ref to
- java.desktop;
+ java.desktop,
+ jdk.unsupported;
exports jdk.internal.reflect to
java.corba,
java.logging,
@@ -219,7 +220,8 @@
exports sun.nio.ch to
java.management,
jdk.crypto.token,
- jdk.sctp;
+ jdk.sctp,
+ jdk.unsupported;
exports sun.nio.cs to
java.desktop,
jdk.charsets;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Mon Dec 19 16:05:38 2016 +0000
@@ -36,6 +36,7 @@
import java.security.AccessControlContext;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
+import java.util.function.BiFunction;
import javax.crypto.*;
import javax.crypto.spec.*;
@@ -122,6 +123,14 @@
// Negotiated ALPN value
String applicationProtocol = null;
+ // Application protocol callback function (for SSLEngine)
+ BiFunction<SSLEngine,List<String>,String>
+ appProtocolSelectorSSLEngine = null;
+
+ // Application protocol callback function (for SSLSocket)
+ BiFunction<SSLSocket,List<String>,String>
+ appProtocolSelectorSSLSocket = null;
+
// The maximum expected network packet size for SSL/TLS/DTLS records.
int maximumPacketSize = 0;
@@ -501,6 +510,22 @@
}
/**
+ * Sets the Application Protocol selector function for SSLEngine.
+ */
+ void setApplicationProtocolSelectorSSLEngine(
+ BiFunction<SSLEngine,List<String>,String> selector) {
+ this.appProtocolSelectorSSLEngine = selector;
+ }
+
+ /**
+ * Sets the Application Protocol selector function for SSLSocket.
+ */
+ void setApplicationProtocolSelectorSSLSocket(
+ BiFunction<SSLSocket,List<String>,String> selector) {
+ this.appProtocolSelectorSSLSocket = selector;
+ }
+
+ /**
* Sets the cipher suites preference.
*/
void setUseCipherSuitesOrder(boolean on) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Mon Dec 19 16:05:38 2016 +0000
@@ -27,8 +27,9 @@
import java.io.*;
import java.nio.*;
+import java.security.*;
import java.util.*;
-import java.security.*;
+import java.util.function.BiFunction;
import javax.crypto.BadPaddingException;
@@ -206,6 +207,10 @@
// The value under negotiation will be obtained from handshaker.
String applicationProtocol = null;
+ // Callback function that selects the application protocol value during
+ // the SSL/TLS handshake.
+ BiFunction<SSLEngine, List<String>, String> applicationProtocolSelector;
+
// Have we been told whether we're client or server?
private boolean serverModeSet = false;
private boolean roleIsServer;
@@ -442,6 +447,8 @@
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
+ handshaker.setApplicationProtocolSelectorSSLEngine(
+ applicationProtocolSelector);
outputRecord.initHandshaker();
}
@@ -2264,6 +2271,21 @@
return null;
}
+ @Override
+ public synchronized void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLEngine, List<String>, String> selector) {
+ applicationProtocolSelector = selector;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setApplicationProtocolSelectorSSLEngine(selector);
+ }
+ }
+
+ @Override
+ public synchronized BiFunction<SSLEngine, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ return this.applicationProtocolSelector;
+ }
+
/**
* Returns a printable representation of this end of the connection.
*/
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Mon Dec 19 16:05:38 2016 +0000
@@ -37,6 +37,7 @@
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiFunction;
import javax.crypto.BadPaddingException;
import javax.net.ssl.*;
@@ -223,6 +224,10 @@
// The value under negotiation will be obtained from handshaker.
String applicationProtocol = null;
+ // Callback function that selects the application protocol value during
+ // the SSL/TLS handshake.
+ BiFunction<SSLSocket, List<String>, String> applicationProtocolSelector;
+
/*
* READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
* IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
@@ -1370,6 +1375,8 @@
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
+ handshaker.setApplicationProtocolSelectorSSLSocket(
+ applicationProtocolSelector);
}
/**
@@ -2658,6 +2665,21 @@
return null;
}
+ @Override
+ public synchronized void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLSocket, List<String>, String> selector) {
+ applicationProtocolSelector = selector;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setApplicationProtocolSelectorSSLSocket(selector);
+ }
+ }
+
+ @Override
+ public synchronized BiFunction<SSLSocket, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ return this.applicationProtocolSelector;
+ }
+
//
// We allocate a separate thread to deliver handshake completion
// events. This ensures that the notifications don't block the
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Mon Dec 19 16:05:38 2016 +0000
@@ -34,6 +34,7 @@
import java.security.interfaces.*;
import java.security.spec.ECParameterSpec;
import java.math.BigInteger;
+import java.util.function.BiFunction;
import javax.crypto.SecretKey;
import javax.net.ssl.*;
@@ -532,31 +533,39 @@
ALPNExtension clientHelloALPN = (ALPNExtension)
mesg.extensions.get(ExtensionType.EXT_ALPN);
- if ((clientHelloALPN != null) && (localApl.length > 0)) {
+ // Use the application protocol callback when provided.
+ // Otherwise use the local list of application protocols.
+ boolean hasAPCallback =
+ ((engine != null && appProtocolSelectorSSLEngine != null) ||
+ (conn != null && appProtocolSelectorSSLSocket != null));
+
+ if (!hasAPCallback) {
+ if ((clientHelloALPN != null) && (localApl.length > 0)) {
- // Intersect the requested and the locally supported,
- // and save for later.
- String negotiatedValue = null;
- List<String> protocols = clientHelloALPN.getPeerAPs();
+ // Intersect the requested and the locally supported,
+ // and save for later.
+ String negotiatedValue = null;
+ List<String> protocols = clientHelloALPN.getPeerAPs();
- // Use server preference order
- for (String ap : localApl) {
- if (protocols.contains(ap)) {
- negotiatedValue = ap;
- break;
+ // Use server preference order
+ for (String ap : localApl) {
+ if (protocols.contains(ap)) {
+ negotiatedValue = ap;
+ break;
+ }
}
- }
- if (negotiatedValue == null) {
- fatalSE(Alerts.alert_no_application_protocol,
- new SSLHandshakeException(
- "No matching ALPN values"));
+ if (negotiatedValue == null) {
+ fatalSE(Alerts.alert_no_application_protocol,
+ new SSLHandshakeException(
+ "No matching ALPN values"));
+ }
+ applicationProtocol = negotiatedValue;
+
+ } else {
+ applicationProtocol = "";
}
- applicationProtocol = negotiatedValue;
-
- } else {
- applicationProtocol = "";
- }
+ } // Otherwise, applicationProtocol will be set by the callback.
session = null; // forget about the current session
//
@@ -892,8 +901,36 @@
}
// Prepare the ALPN response
- if (applicationProtocol != null && !applicationProtocol.isEmpty()) {
- m1.extensions.add(new ALPNExtension(applicationProtocol));
+ if (clientHelloALPN != null) {
+ List<String> peerAPs = clientHelloALPN.getPeerAPs();
+
+ // check for a callback function
+ if (hasAPCallback) {
+ if (conn != null) {
+ applicationProtocol =
+ appProtocolSelectorSSLSocket.apply(conn, peerAPs);
+ } else {
+ applicationProtocol =
+ appProtocolSelectorSSLEngine.apply(engine, peerAPs);
+ }
+ }
+
+ // check for no-match and that the selected name was also proposed
+ // by the TLS peer
+ if (applicationProtocol == null ||
+ (!applicationProtocol.isEmpty() &&
+ !peerAPs.contains(applicationProtocol))) {
+
+ fatalSE(Alerts.alert_no_application_protocol,
+ new SSLHandshakeException(
+ "No matching ALPN values"));
+
+ } else if (!applicationProtocol.isEmpty()) {
+ m1.extensions.add(new ALPNExtension(applicationProtocol));
+ }
+ } else {
+ // Nothing was negotiated, returned at end of the handshake
+ applicationProtocol = "";
}
if (debug != null && Debug.isOn("handshake")) {
--- a/jdk/src/java.base/share/native/libjava/StrictMath.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/native/libjava/StrictMath.c Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -65,12 +65,6 @@
}
JNIEXPORT jdouble JNICALL
-Java_java_lang_StrictMath_exp(JNIEnv *env, jclass unused, jdouble d)
-{
- return (jdouble) jexp((double)d);
-}
-
-JNIEXPORT jdouble JNICALL
Java_java_lang_StrictMath_log(JNIEnv *env, jclass unused, jdouble d)
{
return (jdouble) jlog((double)d);
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -109,13 +109,9 @@
private String helperPath(String javahome, String osArch) {
switch (this) {
case SOLARIS:
- if (osArch.equals("x86")) { osArch = "i386"; }
- else if (osArch.equals("x86_64")) { osArch = "amd64"; }
// fall through...
case LINUX:
case AIX:
- return javahome + "/lib/" + osArch + "/jspawnhelper";
-
case BSD:
return javahome + "/lib/jspawnhelper";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/classes/module-info.java.extra Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * 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. 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.
+ */
+
+// jdk.vm.compiler uses Unsafe and VM classes from jdk.internal.misc
+exports jdk.internal.misc to jdk.vm.compiler;
+opens jdk.internal.misc to jdk.vm.compiler;
+
+// jdk.vm.compiler uses com.sun.crypto.provider to generate crypto intrinsics
+opens com.sun.crypto.provider to jdk.vm.compiler;
+
+exports jdk.internal.module to jdk.vm.compiler;
+
+// AOT uses jdk.internal.misc.Unsafe
+exports jdk.internal.misc to jdk.aot;
--- a/jdk/src/java.base/unix/native/libjli/java_md.h Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libjli/java_md.h Mon Dec 19 16:05:38 2016 +0000
@@ -54,10 +54,8 @@
const char *SetExecname(char **argv);
const char *GetExecName();
static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
- char *jvmpath, jint jvmpathsize, const char * arch,
- int bitsWanted);
-static jboolean GetJREPath(char *path, jint pathsize, const char * arch,
- jboolean speculative);
+ char *jvmpath, jint jvmpathsize, int bitsWanted);
+static jboolean GetJREPath(char *path, jint pathsize, jboolean speculative);
#if defined(_AIX)
#include "java_md_aix.h"
--- a/jdk/src/java.base/unix/native/libjli/java_md_solinux.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libjli/java_md_solinux.c Mon Dec 19 16:05:38 2016 +0000
@@ -52,9 +52,6 @@
#endif
#ifdef __solaris__
-# ifndef LIBARCHNAME
-# error "The macro LIBARCHNAME was not defined on the compile line"
-# endif
# include <sys/systeminfo.h>
# include <sys/elf.h>
# include <stdio.h>
@@ -188,12 +185,13 @@
return JNI_FALSE;
}
/*
- * contains a lib/$LIBARCHNAME/{server,client}/libjvm.so ?
+ * contains a lib/{server,client}/libjvm.so ?
*/
static jboolean
ContainsLibJVM(const char *env) {
- char clientPattern[PATH_MAX + 1];
- char serverPattern[PATH_MAX + 1];
+ /* the usual suspects */
+ char clientPattern[] = "lib/client";
+ char serverPattern[] = "lib/server";
char *envpath;
char *path;
jboolean clientPatternFound;
@@ -204,10 +202,6 @@
return JNI_FALSE;
}
- /* the usual suspects */
- JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", LIBARCHNAME);
- JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", LIBARCHNAME);
-
/* to optimize for time, test if any of our usual suspects are present. */
clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
@@ -322,7 +316,6 @@
/* Check data model flags, and exec process, if needed */
{
- char *arch = LIBARCHNAME; /* like sparc or sparcv9 */
char * jvmtype = NULL;
int argc = *pargc;
char **argv = *pargv;
@@ -408,12 +401,12 @@
jvmpath does not exist */
if (wanted == running) {
/* Find out where the JRE is that we will be using. */
- if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+ if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
JLI_ReportErrorMessage(JRE_ERROR1);
exit(2);
}
- JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
- jrepath, FILESEP, FILESEP, arch, FILESEP);
+ JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%sjvm.cfg",
+ jrepath, FILESEP, FILESEP, FILESEP);
/* Find the specified JVM type */
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
JLI_ReportErrorMessage(CFG_ERROR7);
@@ -427,7 +420,7 @@
exit(4);
}
- if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {
+ if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, 0 )) {
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
exit(4);
}
@@ -457,8 +450,8 @@
* We will set the LD_LIBRARY_PATH as follows:
*
* o $JVMPATH (directory portion only)
- * o $JRE/lib/$LIBARCHNAME
- * o $JRE/../lib/$LIBARCHNAME
+ * o $JRE/lib
+ * o $JRE/../lib
*
* followed by the user's previous effective LD_LIBRARY_PATH, if
* any.
@@ -518,10 +511,10 @@
{ /* New scope to declare local variable */
char *new_jvmpath = JLI_StringDup(jvmpath);
new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
- 2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +
+ 2 * JLI_StrLen(jrepath) +
#ifdef AIX
/* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
- JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") +
+ JLI_StrLen(jrepath) + JLI_StrLen("/lib//jli:") +
#endif
JLI_StrLen(new_jvmpath) + 52;
new_runpath = JLI_MemAlloc(new_runpath_size);
@@ -539,17 +532,17 @@
sprintf(new_runpath, LD_LIBRARY_PATH "="
"%s:"
- "%s/lib/%s:"
+ "%s/lib:"
#ifdef AIX
- "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
+ "%s/lib/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
#endif
- "%s/../lib/%s",
+ "%s/../lib",
new_jvmpath,
- jrepath, arch,
+ jrepath,
#ifdef AIX
- jrepath, arch,
+ jrepath,
#endif
- jrepath, arch
+ jrepath
);
JLI_MemFree(new_jvmpath);
@@ -640,14 +633,14 @@
*/
static jboolean
GetJVMPath(const char *jrepath, const char *jvmtype,
- char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+ char *jvmpath, jint jvmpathsize, int bitsWanted)
{
struct stat s;
if (JLI_StrChr(jvmtype, '/')) {
JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
} else {
- JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
+ JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
}
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
@@ -665,14 +658,14 @@
* Find path to JRE based on .exe's location or registry settings.
*/
static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
{
char libjava[MAXPATHLEN];
struct stat s;
if (GetApplicationHome(path, pathsize)) {
/* Is JRE co-located with the application? */
- JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
if (access(libjava, F_OK) == 0) {
JLI_TraceLauncher("JRE path is %s\n", path);
return JNI_TRUE;
@@ -683,7 +676,7 @@
return JNI_FALSE;
}
/* Does the app ship a private JRE in <apphome>/jre directory? */
- JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);
+ JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
if (access(libjava, F_OK) == 0) {
JLI_StrCat(path, "/jre");
JLI_TraceLauncher("JRE path is %s\n", path);
@@ -692,7 +685,7 @@
}
if (GetApplicationHomeFromDll(path, pathsize)) {
- JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
if (stat(libjava, &s) == 0) {
JLI_TraceLauncher("JRE path is %s\n", path);
return JNI_TRUE;
@@ -858,12 +851,12 @@
char jrePath[MAXPATHLEN];
char splashPath[MAXPATHLEN];
- if (!GetJREPath(jrePath, sizeof(jrePath), LIBARCHNAME, JNI_FALSE)) {
+ if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
JLI_ReportErrorMessage(JRE_ERROR1);
return NULL;
}
- ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",
- jrePath, LIBARCHNAME, SPLASHSCREEN_SO);
+ ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
+ jrePath, SPLASHSCREEN_SO);
if (ret >= (int) sizeof(splashPath)) {
JLI_ReportErrorMessage(JRE_ERROR11);
--- a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c Mon Dec 19 16:05:38 2016 +0000
@@ -37,273 +37,10 @@
#include "java_net_Inet4AddressImpl.h"
-#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
-#define HAS_GLIBC_GETHOSTBY_R 1
-#endif
-
-
-#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
+#if defined(MACOSX)
extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
-
-/* Use getaddrinfo(3), which is thread safe */
-/************************************************************************
- * Inet4AddressImpl
- */
-
-/*
- * Class: java_net_Inet4AddressImpl
- * Method: getLocalHostName
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
- char hostname[NI_MAXHOST+1];
-
- hostname[0] = '\0';
- if (gethostname(hostname, NI_MAXHOST)) {
- /* Something went wrong, maybe networking is not setup? */
- strcpy(hostname, "localhost");
- } else {
- struct addrinfo hints, *res;
- int error;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
-
- error = getaddrinfo(hostname, NULL, &hints, &res);
-
- if (error == 0) {
- /* host is known to name service */
- error = getnameinfo(res->ai_addr,
- res->ai_addrlen,
- hostname,
- NI_MAXHOST,
- NULL,
- 0,
- NI_NAMEREQD);
-
- /* if getnameinfo fails hostname is still the value
- from gethostname */
-
- freeaddrinfo(res);
- }
- }
- return (*env)->NewStringUTF(env, hostname);
-}
-
-/*
- * Find an internet address for a given hostname. Note that this
- * code only works for addresses of type INET. The translation
- * of %d.%d.%d.%d to an address (int) occurs in java now, so the
- * String "host" shouldn't *ever* be a %d.%d.%d.%d string
- *
- * Class: java_net_Inet4AddressImpl
- * Method: lookupAllHostAddr
- * Signature: (Ljava/lang/String;)[[B
- */
-
-JNIEXPORT jobjectArray JNICALL
-Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
- jstring host) {
- const char *hostname;
- jobject name;
- jobjectArray ret = 0;
- int retLen = 0;
-
- int getaddrinfo_error=0;
- struct addrinfo hints, *res, *resNew = NULL;
-
- initInetAddressIDs(env);
- JNU_CHECK_EXCEPTION_RETURN(env, NULL);
-
- if (IS_NULL(host)) {
- JNU_ThrowNullPointerException(env, "host is null");
- return 0;
- }
- hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
- CHECK_NULL_RETURN(hostname, NULL);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_INET;
-
- /*
- * Workaround for Solaris bug 4160367 - if a hostname contains a
- * white space then 0.0.0.0 is returned
- */
- if (isspace((unsigned char)hostname[0])) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
- (char *)hostname);
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- }
-
-
- getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
-
-#ifdef MACOSX
- if (getaddrinfo_error) {
- // If getaddrinfo fails try getifaddrs.
- ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
- if (ret != NULL || (*env)->ExceptionCheck(env)) {
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return ret;
- }
- }
#endif
- if (getaddrinfo_error) {
- /* report error */
- NET_ThrowUnknownHostExceptionWithGaiError(
- env, hostname, getaddrinfo_error);
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- } else {
- int i = 0;
- struct addrinfo *itr, *last = NULL, *iterator = res;
- while (iterator != NULL) {
- int skip = 0;
- itr = resNew;
-
- while (itr != NULL) {
- struct sockaddr_in *addr1, *addr2;
-
- addr1 = (struct sockaddr_in *)iterator->ai_addr;
- addr2 = (struct sockaddr_in *)itr->ai_addr;
- if (addr1->sin_addr.s_addr ==
- addr2->sin_addr.s_addr) {
- skip = 1;
- break;
- }
-
- itr = itr->ai_next;
- }
-
- if (!skip) {
- struct addrinfo *next
- = (struct addrinfo*) malloc(sizeof(struct addrinfo));
- if (!next) {
- JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
- ret = NULL;
- goto cleanupAndReturn;
- }
- memcpy(next, iterator, sizeof(struct addrinfo));
- next->ai_next = NULL;
- if (resNew == NULL) {
- resNew = next;
- } else {
- last->ai_next = next;
- }
- last = next;
- i++;
- }
- iterator = iterator->ai_next;
- }
-
- retLen = i;
- iterator = resNew;
- i = 0;
-
- name = (*env)->NewStringUTF(env, hostname);
- if (IS_NULL(name)) {
- goto cleanupAndReturn;
- }
-
- ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
- if (IS_NULL(ret)) {
- /* we may have memory to free at the end of this */
- goto cleanupAndReturn;
- }
-
- while (iterator != NULL) {
- /* We need 4 bytes to store ipv4 address; */
- int len = 4;
-
- jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
- if (IS_NULL(iaObj)) {
- /* we may have memory to free at the end of this */
- ret = NULL;
- goto cleanupAndReturn;
- }
- setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
- setInetAddress_hostName(env, iaObj, name);
- (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
- i++;
- iterator = iterator->ai_next;
- }
- }
-
-cleanupAndReturn:
- {
- struct addrinfo *iterator, *tmp;
- iterator = resNew;
- while (iterator != NULL) {
- tmp = iterator;
- iterator = iterator->ai_next;
- free(tmp);
- }
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- }
-
- freeaddrinfo(res);
-
- return ret;
-
-}
-
-/*
- * Class: java_net_Inet4AddressImpl
- * Method: getHostByAddr
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
- jbyteArray addrArray) {
- jstring ret = NULL;
-
- char host[NI_MAXHOST+1];
- jfieldID fid;
- int error = 0;
- jint family;
- struct sockaddr *him ;
- int len = 0;
- jbyte caddr[4];
- jint addr;
-
- struct sockaddr_in him4;
- struct sockaddr *sa;
-
- /*
- * For IPv4 addresses construct a sockaddr_in structure.
- */
- (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
- addr |= (caddr[3] & 0xff);
- memset((char *) &him4, 0, sizeof(him4));
- him4.sin_addr.s_addr = htonl(addr);
- him4.sin_family = AF_INET;
- sa = (struct sockaddr *) &him4;
- len = sizeof(him4);
-
- error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
-
- if (!error) {
- ret = (*env)->NewStringUTF(env, host);
- }
-
- if (ret == NULL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
- }
-
- return ret;
-
-}
-
-#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
-
/* the initial size of our hostent buffers */
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
@@ -405,6 +142,17 @@
error = getaddrinfo(hostname, NULL, &hints, &res);
+#ifdef MACOSX
+ if (error) {
+ // If getaddrinfo fails try getifaddrs, see bug 8170910.
+ ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
+ if (ret != NULL || (*env)->ExceptionCheck(env)) {
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return ret;
+ }
+ }
+#endif
+
if (error) {
/* report error */
NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
@@ -475,7 +223,7 @@
}
}
- cleanupAndReturn:
+cleanupAndReturn:
{
struct addrinfo *iterator, *tmp;
iterator = resNew;
@@ -535,8 +283,6 @@
return ret;
}
-#endif /* _ALLBSD_SOURCE */
-
#define SET_NONBLOCKING(fd) { \
int flags = fcntl(fd, F_GETFL); \
flags |= O_NONBLOCK; \
--- a/jdk/src/java.base/windows/native/libjli/java_md.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c Mon Dec 19 16:05:38 2016 +0000
@@ -151,22 +151,6 @@
}
/*
- * Returns the arch path, to get the current arch use the
- * macro GetArch, nbits here is ignored for now.
- */
-const char *
-GetArchPath(int nbits)
-{
-#ifdef _M_AMD64
- return "amd64";
-#elif defined(_M_IA64)
- return "ia64";
-#else
- return "i386";
-#endif
-}
-
-/*
*
*/
void
@@ -207,8 +191,8 @@
exit(2);
}
- JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
- jrepath, FILESEP, FILESEP, (char*)GetArch(), FILESEP);
+ JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
+ jrepath, FILESEP, FILESEP);
/* Find the specified JVM type */
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java Mon Dec 19 16:05:38 2016 +0000
@@ -34,10 +34,18 @@
import sun.lwawt.macosx.LWCToolkit;
import sun.security.action.GetBooleanAction;
-import sun.security.action.GetPropertyAction;
// MenuBar implementation for Mac L&F
public class AquaMenuBarUI extends BasicMenuBarUI implements ScreenMenuBarProvider {
+
+ static {
+ java.security.AccessController.doPrivileged(
+ (java.security.PrivilegedAction<Void>) () -> {
+ System.loadLibrary("osxui");
+ return null;
+ });
+ }
+
// Utilities
public void uninstallUI(final JComponent c) {
if (fScreenMenuBar != null) {
@@ -134,7 +142,7 @@
ScreenMenuBar fScreenMenuBar;
boolean useScreenMenuBar = getScreenMenuBarProperty();
- static boolean getScreenMenuBarProperty() {
+ public static boolean getScreenMenuBarProperty() {
// Do not allow AWT to set the screen menu bar if it's embedded in another UI toolkit
if (LWCToolkit.isEmbedded()) return false;
if (AccessController.doPrivileged(
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Mon Dec 19 16:05:38 2016 +0000
@@ -141,12 +141,24 @@
}
}
- protected void registerFontsInDir(String dirName, boolean useJavaRasterizer, int fontRank, boolean defer, boolean resolveSymLinks) {
- loadNativeDirFonts(dirName);
+ protected void registerFontsInDir(final String dirName, boolean useJavaRasterizer,
+ int fontRank, boolean defer, boolean resolveSymLinks) {
+
+ String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () -> {
+ return new File(dirName).list(getTrueTypeFilter());
+ });
+
+ if (files == null) {
+ return;
+ } else {
+ for (String f : files) {
+ loadNativeDirFonts(dirName+File.separator+f);
+ }
+ }
super.registerFontsInDir(dirName, useJavaRasterizer, fontRank, defer, resolveSymLinks);
}
- private native void loadNativeDirFonts(String dirName);
+ private native void loadNativeDirFonts(String fontPath);
private native void loadNativeFonts();
void registerFont(String fontName, String fontFamilyName) {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Mon Dec 19 16:05:38 2016 +0000
@@ -33,11 +33,14 @@
import java.awt.event.*;
import java.beans.*;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
import javax.swing.*;
import sun.awt.*;
import sun.awt.AWTAccessor.ComponentAccessor;
+import sun.awt.AWTAccessor.WindowAccessor;
import sun.java2d.SurfaceData;
import sun.java2d.opengl.CGLSurfaceData;
import sun.lwawt.*;
@@ -1031,6 +1034,11 @@
return !peer.isSimpleWindow() && target.getFocusableWindowState();
}
+ private boolean isBlocked() {
+ LWWindowPeer blocker = (peer != null) ? peer.getBlocker() : null;
+ return (blocker != null);
+ }
+
/*
* An utility method for the support of the auto request focus.
* Updates the focusable state of the window under certain
@@ -1063,29 +1071,70 @@
return true;
}
+ private boolean isOneOfOwnersOrSelf(CPlatformWindow window) {
+ while (window != null) {
+ if (this == window) {
+ return true;
+ }
+ window = window.owner;
+ }
+ return false;
+ }
+
+ private CPlatformWindow getRootOwner() {
+ CPlatformWindow rootOwner = this;
+ while (rootOwner.owner != null) {
+ rootOwner = rootOwner.owner;
+ }
+ return rootOwner;
+ }
+
private void orderAboveSiblings() {
- if (owner == null) {
- return;
+ // Recursively pop up the windows from the very bottom, (i.e. root owner) so that
+ // the windows are ordered above their nearest owner; ancestors of the window,
+ // which is going to become 'main window', are placed above their siblings.
+ CPlatformWindow rootOwner = getRootOwner();
+ if (rootOwner.isVisible()) {
+ CWrapper.NSWindow.orderFront(rootOwner.getNSWindowPtr());
}
+ final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+ orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target));
+ }
- // NOTE: the logic will fail if we have a hierarchy like:
- // visible root owner
- // invisible owner
- // visible dialog
- // However, this is an unlikely scenario for real life apps
- if (owner.isVisible()) {
- // Recursively pop up the windows from the very bottom so that only
- // the very top-most one becomes the main window
- owner.orderAboveSiblings();
+ private void orderAboveSiblingsImpl(Window[] windows) {
+ ArrayList<Window> childWindows = new ArrayList<Window>();
+
+ final ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
+ final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
- // Order the window to front of the stack of child windows
- final long nsWindowSelfPtr = getNSWindowPtr();
- final long nsWindowOwnerPtr = owner.getNSWindowPtr();
- CWrapper.NSWindow.orderFront(nsWindowOwnerPtr);
- CWrapper.NSWindow.orderWindow(nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove, nsWindowOwnerPtr);
+ // Go through the list of windows and perform ordering.
+ for (Window w : windows) {
+ final Object p = componentAccessor.getPeer(w);
+ if (p instanceof LWWindowPeer) {
+ CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
+ if (pw != null && pw.isVisible()) {
+ // If the window is one of ancestors of 'main window' or is going to become main by itself,
+ // the window should be ordered above its siblings; otherwise the window is just ordered
+ // above its nearest parent.
+ if (pw.isOneOfOwnersOrSelf(this)) {
+ CWrapper.NSWindow.orderFront(pw.getNSWindowPtr());
+ } else {
+ CWrapper.NSWindow.orderWindow(pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove,
+ pw.owner.getNSWindowPtr());
+ }
+ pw.applyWindowLevel(w);
+ }
+ }
+ // Retrieve the child windows for each window from the list and store them for future use.
+ // Note: we collect data about child windows even for invisible owners, since they may have
+ // visible children.
+ childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w)));
}
-
- applyWindowLevel(target);
+ // If some windows, which have just been ordered, have any child windows, let's start new iteration
+ // and order these child windows.
+ if (!childWindows.isEmpty()) {
+ orderAboveSiblingsImpl(childWindows.toArray(new Window[0]));
+ }
}
protected void applyWindowLevel(Window target) {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Mon Dec 19 16:05:38 2016 +0000
@@ -25,6 +25,7 @@
package sun.lwawt.macosx;
+import com.apple.laf.AquaMenuBarUI;
import java.awt.peer.TaskbarPeer;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
@@ -43,6 +44,7 @@
import java.util.*;
import java.util.concurrent.Callable;
import java.net.MalformedURLException;
+import javax.swing.UIManager;
import sun.awt.*;
import sun.awt.datatransfer.DataTransferer;
@@ -935,4 +937,13 @@
protected PlatformWindow getPlatformWindowUnderMouse() {
return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse();
}
+
+ @Override
+ public void updateScreenMenuBarUI() {
+ if (AquaMenuBarUI.getScreenMenuBarProperty()) {
+ UIManager.put("MenuBarUI", "com.apple.laf.AquaMenuBarUI");
+ } else {
+ UIManager.put("MenuBarUI", null);
+ }
+ }
}
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Mon Dec 19 16:05:38 2016 +0000
@@ -430,7 +430,22 @@
[super dealloc];
}
-// Tests wheather the corresponding Java paltform window is visible or not
+// Tests whether window is blocked by modal dialog/window
+- (BOOL) isBlocked {
+ BOOL isBlocked = NO;
+
+ JNIEnv *env = [ThreadUtilities getJNIEnv];
+ jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+ if (platformWindow != NULL) {
+ static JNF_MEMBER_CACHE(jm_isBlocked, jc_CPlatformWindow, "isBlocked", "()Z");
+ isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
+ (*env)->DeleteLocalRef(env, platformWindow);
+ }
+
+ return isBlocked;
+}
+
+// Tests whether the corresponding Java platform window is visible or not
+ (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window {
BOOL isVisible = NO;
@@ -454,8 +469,9 @@
- (void) orderChildWindows:(BOOL)focus {
AWT_ASSERT_APPKIT_THREAD;
- if (self.isMinimizing) {
+ if (self.isMinimizing || [self isBlocked]) {
// Do not perform any ordering, if iconify is in progress
+ // or the window is blocked by a modal window
return;
}
@@ -809,18 +825,20 @@
- (void)sendEvent:(NSEvent *)event {
if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
- // Move parent windows to front and make sure that a child window is displayed
- // in front of its nearest parent.
- if (self.ownerWindow != nil) {
- JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
- jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
- if (platformWindow != NULL) {
- static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
- JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
- (*env)->DeleteLocalRef(env, platformWindow);
+ if ([self isBlocked]) {
+ // Move parent windows to front and make sure that a child window is displayed
+ // in front of its nearest parent.
+ if (self.ownerWindow != nil) {
+ JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
+ jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+ if (platformWindow != NULL) {
+ static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
+ JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
+ (*env)->DeleteLocalRef(env, platformWindow);
+ }
}
+ [self orderChildWindows:YES];
}
- [self orderChildWindows:YES];
NSPoint p = [NSEvent mouseLocation];
NSRect frame = [self.nsWindow frame];
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m Mon Dec 19 16:05:38 2016 +0000
@@ -115,19 +115,18 @@
if (keyWindow != nil) {
return;
}
- }
- else {
- static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
- static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
-
- NSUInteger modifiers = [currEvent modifierFlags];
- jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
-
- JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
- }
+ }
+
+ static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
+ static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
+
+ NSUInteger modifiers = [currEvent modifierFlags];
+ jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
+
+ JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
}
JNF_COCOA_EXIT(env);
-
+
}
- (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Mon Dec 19 16:05:38 2016 +0000
@@ -404,19 +404,14 @@
{
JNF_COCOA_ENTER(env);
- NSString *nsFilePath = JNFJavaToNSString(env, filename);
-
- FSRef iFile;
- OSStatus status = CreateFSRef(&iFile, nsFilePath);
-
- if (status == noErr) {
- ATSFontContainerRef oContainer;
- status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal,
- kATSFontFormatUnspecified,
- NULL, kNilOptions,
- &oContainer);
- }
-
+ NSString *path = JNFJavaToNSString(env, filename);
+ NSURL *url = [NSURL fileURLWithPath:(NSString *)path];
+ bool res = CTFontManagerRegisterFontsForURL((CFURLRef)url, kCTFontManagerScopeProcess, nil);
+#ifdef DEBUG
+ NSLog(@"path is : %@", (NSString*)path);
+ NSLog(@"url is : %@", (NSString*)url);
+ printf("res is %d\n", res);
+#endif
JNF_COCOA_EXIT(env);
}
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m Mon Dec 19 16:05:38 2016 +0000
@@ -591,7 +591,7 @@
static inline GlyphInfo *
CGGI_CreateImageForUnicode
(CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
- const CGGI_RenderingMode *mode, const UniChar uniChar)
+ const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar)
{
// save the state of the world
CGContextSaveGState(canvas->context);
@@ -668,7 +668,7 @@
const AWTStrike *strike,
const CGGI_RenderingMode *mode,
jlong glyphInfos[],
- const UniChar uniChars[],
+ const UnicodeScalarValue uniChars[],
const CGGlyph glyphs[],
const CFIndex len)
{
@@ -720,7 +720,7 @@
static inline void
CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
const CGGI_RenderingMode *mode,
- const UniChar uniChars[], const CGGlyph glyphs[],
+ const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
const size_t maxWidth, const size_t maxHeight,
const CFIndex len)
{
@@ -767,7 +767,7 @@
static inline void
CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
const CGGI_RenderingMode *mode,
- const UniChar uniChars[], const CGGlyph glyphs[],
+ const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
CGSize advances[], CGRect bboxes[], const CFIndex len)
{
AWTFont *font = strike->fAWTFont;
@@ -817,7 +817,7 @@
const AWTStrike *strike,
const CGGI_RenderingMode *mode,
jint rawGlyphCodes[],
- UniChar uniChars[], CGGlyph glyphs[],
+ UnicodeScalarValue uniChars[], CGGlyph glyphs[],
CGSize advances[], CGRect bboxes[],
const CFIndex len)
{
@@ -860,7 +860,7 @@
CGRect bboxes[len];
CGSize advances[len];
CGGlyph glyphs[len];
- UniChar uniChars[len];
+ UnicodeScalarValue uniChars[len];
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
rawGlyphCodes, uniChars, glyphs,
@@ -871,7 +871,7 @@
// just do one malloc, and carve it up for all the buffers
void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
- sizeof(CGGlyph) * sizeof(UniChar) * len);
+ sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
if (buffer == NULL) {
[[NSException exceptionWithName:NSMallocException
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
@@ -880,7 +880,7 @@
CGRect *bboxes = (CGRect *)(buffer);
CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
- UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
+ UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
rawGlyphCodes, uniChars, glyphs,
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h Mon Dec 19 16:05:38 2016 +0000
@@ -32,7 +32,9 @@
#pragma mark --- CoreText Support ---
#define HI_SURROGATE_START 0xD800
+#define HI_SURROGATE_END 0xDBFF
#define LO_SURROGATE_START 0xDC00
+#define LO_SURROGATE_END 0xDFFF
/*
* Transform Unicode characters into glyphs.
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m Mon Dec 19 16:05:38 2016 +0000
@@ -103,24 +103,34 @@
size_t i;
for (i = 0; i < count; i++) {
+ UniChar unicode = unicodes[i];
+ UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
+ bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
+ && nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
+
CGGlyph glyph = glyphs[i];
if (glyph > 0) {
glyphsAsInts[i] = glyph;
+ if (surrogatePair) i++;
continue;
}
- UniChar unicode = unicodes[i];
- const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
+ const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicodes[i],
+ surrogatePair ? 2 : 1);
if (fallback) {
- CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
+ CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
+ glyph = glyphs[i];
CFRelease(fallback);
}
if (glyph > 0) {
- glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
+ int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
+ + nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
+ glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
} else {
glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
}
+ if (surrogatePair) i++;
}
}
@@ -158,8 +168,18 @@
return (CTFontRef)font->fFont;
}
- UTF16Char character = -glyphCode;
- return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+ int codePoint = -glyphCode;
+ if (codePoint >= 0x10000) {
+ UTF16Char chars[2];
+ CGGlyph glyphs[2];
+ CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
+ CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
+ *glyphRef = glyphs[0];
+ return result;
+ } else {
+ UTF16Char character = codePoint;
+ return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+ }
}
// Breakup a 32 bit unicode value into the component surrogate pairs
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java Mon Dec 19 16:05:38 2016 +0000
@@ -541,10 +541,10 @@
}
// Stream position initially at beginning, left at end
- // if ignoreUnknownFields is true, do not load fields for which
+ // if readUnknownTags is false, do not load fields for which
// a tag cannot be found in an allowed TagSet.
public void initialize(ImageInputStream stream, boolean isPrimaryIFD,
- boolean ignoreUnknownFields) throws IOException {
+ boolean ignoreMetadata, boolean readUnknownTags) throws IOException {
removeTIFFFields();
@@ -553,10 +553,16 @@
List<TIFFTagSet> tagSetList = getTagSetList();
+ // Configure essential tag variables if this is the primary IFD and
+ // either all metadata are being ignored, or metadata are not being
+ // ignored but both unknown tags are being ignored and the tag set
+ // list does not contain the baseline tags.
boolean ensureEssentialTags = false;
TIFFTagSet baselineTagSet = null;
- if (isPrimaryIFD && ignoreUnknownFields
- && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) {
+ if (isPrimaryIFD &&
+ (ignoreMetadata ||
+ (!readUnknownTags &&
+ !tagSetList.contains(BaselineTIFFTagSet.getInstance())))) {
ensureEssentialTags = true;
initializeEssentialTags();
baselineTagSet = BaselineTIFFTagSet.getInstance();
@@ -590,9 +596,12 @@
tag = baselineTagSet.getTag(tagNumber);
}
- // Ignore unknown fields, fields with unknown type, and fields
+ // Ignore non-essential fields, unknown fields unless forcibly
+ // being read, fields with unknown type, and fields
// with count out of int range.
- if((tag == null && ignoreUnknownFields)
+ if((ignoreMetadata &&
+ (!ensureEssentialTags || !essentialTags.contains(tagNumber)))
+ || (tag == null && !readUnknownTags)
|| (tag != null && !tag.isDataTypeOK(type))
|| longCount > Integer.MAX_VALUE) {
// Skip the value/offset so as to leave the stream
@@ -701,7 +710,8 @@
tagSets.add(tag.getTagSet());
TIFFIFD subIFD = new TIFFIFD(tagSets);
- subIFD.initialize(stream, false, ignoreUnknownFields);
+ subIFD.initialize(stream, false, ignoreMetadata,
+ readUnknownTags);
TIFFField f = new TIFFField(tag, type, e.offset, subIFD);
addTIFFField(f);
} else {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java Mon Dec 19 16:05:38 2016 +0000
@@ -82,12 +82,13 @@
}
public void initializeFromStream(ImageInputStream stream,
- boolean ignoreUnknownFields)
+ boolean ignoreMetadata,
+ boolean readUnknownTags)
throws IOException {
- rootIFD.initialize(stream, true, ignoreUnknownFields);
+ rootIFD.initialize(stream, true, ignoreMetadata, readUnknownTags);
}
- public void addShortOrLongField(int tagNumber, int value) {
+ public void addShortOrLongField(int tagNumber, long value) {
TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value);
rootIFD.addTIFFField(field);
}
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Mon Dec 19 16:05:38 2016 +0000
@@ -305,16 +305,19 @@
try {
// Create an object to store the image metadata
List<TIFFTagSet> tagSets;
+ boolean readUnknownTags = false;
if (imageReadParam instanceof TIFFImageReadParam) {
- tagSets
- = ((TIFFImageReadParam) imageReadParam).getAllowedTagSets();
+ TIFFImageReadParam tp = (TIFFImageReadParam)imageReadParam;
+ tagSets = tp.getAllowedTagSets();
+ readUnknownTags = tp.getReadUnknownTags();
} else {
tagSets = new ArrayList<TIFFTagSet>(1);
tagSets.add(BaselineTIFFTagSet.getInstance());
}
this.imageMetadata = new TIFFImageMetadata(tagSets);
- imageMetadata.initializeFromStream(stream, ignoreMetadata);
+ imageMetadata.initializeFromStream(stream, ignoreMetadata,
+ readUnknownTags);
} catch (IIOException iioe) {
throw iioe;
} catch (IOException ioe) {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java Mon Dec 19 16:05:38 2016 +0000
@@ -3015,7 +3015,7 @@
List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(1);
tagSets.add(BaselineTIFFTagSet.getInstance());
TIFFIFD rootIFD = new TIFFIFD(tagSets);
- rootIFD.initialize(stream, true, true);
+ rootIFD.initialize(stream, true, false, false);
stream.reset();
return rootIFD;
--- a/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,18 +22,25 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package java.awt;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.awt.peer.CheckboxMenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
-import java.io.ObjectOutputStream;
+import java.io.IOException;
import java.io.ObjectInputStream;
-import java.io.IOException;
-import javax.accessibility.*;
+import java.io.ObjectOutputStream;
+import java.util.EventListener;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
import sun.awt.AWTAccessor;
-
/**
* This class represents a check box that can be included in a menu.
* Selecting the check box in the menu changes its state from
@@ -43,7 +50,8 @@
* of {@code CheckBoxMenuItem}:
* <p>
* <img src="doc-files/MenuBar-1.gif"
- * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
+ * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More
+ * Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
* style="float:center; margin: 7px 10px;">
* <p>
* The item labeled {@code Check} shows a check box menu item
@@ -84,9 +92,9 @@
* @see #getState()
* @see #setState(boolean)
*/
- boolean state = false;
+ private volatile boolean state;
- transient ItemListener itemListener;
+ private transient volatile ItemListener itemListener;
private static final String base = "chkmenuitem";
private static int nameCounter = 0;
--- a/jdk/src/java.desktop/share/classes/java/awt/Menu.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/Menu.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,15 +22,20 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package java.awt;
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuPeer;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.util.Enumeration;
import java.util.Vector;
-import java.util.Enumeration;
-import java.awt.peer.MenuPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
import sun.awt.AWTAccessor;
/**
@@ -78,7 +83,7 @@
* @serial
* @see #countItems()
*/
- Vector<MenuItem> items = new Vector<>();
+ private final Vector<MenuItem> items = new Vector<>();
/**
* This field indicates whether the menu has the
@@ -92,7 +97,7 @@
* @serial
* @see #isTearOff()
*/
- boolean tearOff;
+ private final boolean tearOff;
/**
* This field will be set to {@code true}
@@ -102,7 +107,7 @@
*
* @serial
*/
- boolean isHelpMenu;
+ volatile boolean isHelpMenu;
private static final String base = "menu";
private static int nameCounter = 0;
@@ -415,8 +420,8 @@
if (peer != null) {
peer.delItem(index);
mi.removeNotify();
- mi.parent = null;
}
+ mi.parent = null;
}
}
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,16 +22,21 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package java.awt;
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuBarPeer;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.util.Enumeration;
import java.util.Vector;
-import java.util.Enumeration;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
import sun.awt.AWTAccessor;
-import java.awt.peer.MenuBarPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
/**
* The {@code MenuBar} class encapsulates the platform's
@@ -94,7 +99,7 @@
* @serial
* @see #countMenus()
*/
- Vector<Menu> menus = new Vector<>();
+ private final Vector<Menu> menus = new Vector<>();
/**
* This menu is a special menu dedicated to
@@ -106,7 +111,7 @@
* @see #getHelpMenu()
* @see #setHelpMenu(Menu)
*/
- Menu helpMenu;
+ private volatile Menu helpMenu;
private static final String base = "menubar";
private static int nameCounter = 0;
@@ -252,8 +257,8 @@
if (peer != null) {
peer.delMenu(index);
m.removeNotify();
- m.parent = null;
}
+ m.parent = null;
if (helpMenu == m) {
helpMenu = null;
m.isHelpMenu = false;
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,21 +22,28 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package java.awt;
+import java.awt.event.ActionEvent;
import java.awt.peer.MenuComponentPeer;
-import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
-import sun.awt.AppContext;
-import sun.awt.AWTAccessor;
-import sun.awt.ComponentFactory;
-
-import javax.accessibility.*;
-
import java.security.AccessControlContext;
import java.security.AccessController;
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleComponent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+
+import sun.awt.AWTAccessor;
+import sun.awt.AppContext;
+import sun.awt.ComponentFactory;
+
/**
* The abstract class {@code MenuComponent} is the superclass
* of all menu-related components. In this respect, the class
@@ -60,13 +67,13 @@
}
transient volatile MenuComponentPeer peer;
- transient MenuContainer parent;
+ transient volatile MenuContainer parent;
/**
* The {@code AppContext} of the {@code MenuComponent}.
* This is set in the constructor and never changes.
*/
- transient AppContext appContext;
+ private transient volatile AppContext appContext;
/**
* The menu component's font. This value can be
@@ -77,7 +84,7 @@
* @see #setFont(Font)
* @see #getFont()
*/
- volatile Font font;
+ private volatile Font font;
/**
* The menu component's name, which defaults to {@code null}.
@@ -85,7 +92,7 @@
* @see #getName()
* @see #setName(String)
*/
- private String name;
+ private volatile String name;
/**
* A variable to indicate whether a name is explicitly set.
@@ -94,14 +101,14 @@
* @serial
* @see #setName(String)
*/
- private boolean nameExplicitlySet = false;
+ private volatile boolean nameExplicitlySet;
/**
* Defaults to {@code false}.
* @serial
* @see #dispatchEvent(AWTEvent)
*/
- boolean newEventsOnly = false;
+ volatile boolean newEventsOnly;
/*
* The menu's AccessControlContext.
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,15 +22,25 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package java.awt;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
import java.awt.peer.MenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.ObjectInputStream;
-import java.io.IOException;
-import javax.accessibility.*;
+import java.util.EventListener;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
import sun.awt.AWTAccessor;
/**
@@ -111,7 +121,7 @@
* @see #isEnabled()
* @see #setEnabled(boolean)
*/
- boolean enabled = true;
+ private volatile boolean enabled = true;
/**
* {@code label} is the label of a menu item.
@@ -121,7 +131,7 @@
* @see #getLabel()
* @see #setLabel(String)
*/
- String label;
+ volatile String label;
/**
* This field indicates the command that has been issued
@@ -134,7 +144,7 @@
* @see #setActionCommand(String)
* @see #getActionCommand()
*/
- String actionCommand;
+ private volatile String actionCommand;
/**
* The eventMask is ONLY set by subclasses via enableEvents.
@@ -144,9 +154,9 @@
*
* @serial
*/
- long eventMask;
+ volatile long eventMask;
- transient ActionListener actionListener;
+ private transient volatile ActionListener actionListener;
/**
* A sequence of key stokes that ia associated with
@@ -160,7 +170,7 @@
* @see #setShortcut(MenuShortcut)
* @see #deleteShortcut()
*/
- private MenuShortcut shortcut = null;
+ private volatile MenuShortcut shortcut;
private static final String base = "menuitem";
private static int nameCounter = 0;
--- a/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,8 +26,9 @@
package java.awt;
import java.awt.peer.PopupMenuPeer;
-import javax.accessibility.*;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
import sun.awt.AWTAccessor;
@@ -48,7 +49,7 @@
private static final String base = "popup";
static int nameCounter = 0;
- transient boolean isTrayIconPopup = false;
+ transient volatile boolean isTrayIconPopup;
static {
AWTAccessor.setPopupMenuAccessor(
--- a/jdk/src/java.desktop/share/classes/java/awt/Window.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java Mon Dec 19 16:05:38 2016 +0000
@@ -4122,6 +4122,10 @@
public void setTrayIconWindow(Window w, boolean isTrayIconWindow) {
w.isTrayIconWindow = isTrayIconWindow;
}
+
+ public Window[] getOwnedWindows(Window w) {
+ return w.getOwnedWindows_NoClientCode();
+ }
}); // WindowAccessor
} // static
--- a/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java Mon Dec 19 16:05:38 2016 +0000
@@ -279,7 +279,7 @@
}
/**
- * Sets the cursor for this drag operation to the specified
+ * Sets the custom cursor for this drag operation to the specified
* {@code Cursor}. If the specified {@code Cursor}
* is {@code null}, the default drag cursor behavior is
* activated for this drag operation, otherwise it is deactivated.
@@ -298,9 +298,11 @@
}
/**
- * Returns the current drag {@code Cursor}.
+ * Returns the current custom drag {@code Cursor}.
*
- * @return the current drag {@code Cursor}
+ * @return the current custom drag {@code Cursor}, if it was set
+ * otherwise returns {@code null}.
+ * @see #setCursor
*/
public Cursor getCursor() { return cursor; }
--- a/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java Mon Dec 19 16:05:38 2016 +0000
@@ -64,27 +64,71 @@
public abstract class AbstractMultiResolutionImage extends java.awt.Image
implements MultiResolutionImage {
+ /**
+ * This method simply delegates to the same method on the base image and
+ * it is equivalent to: {@code getBaseImage().getWidth(observer)}.
+ *
+ * @return the width of the base image, or -1 if the width is not yet known
+ * @see #getBaseImage()
+ *
+ * @since 9
+ */
@Override
public int getWidth(ImageObserver observer) {
return getBaseImage().getWidth(observer);
}
+ /**
+ * This method simply delegates to the same method on the base image and
+ * it is equivalent to: {@code getBaseImage().getHeight(observer)}.
+ *
+ * @return the height of the base image, or -1 if the height is not yet known
+ * @see #getBaseImage()
+ *
+ * @since 9
+ */
@Override
public int getHeight(ImageObserver observer) {
return getBaseImage().getHeight(observer);
}
+ /**
+ * This method simply delegates to the same method on the base image and
+ * it is equivalent to: {@code getBaseImage().getSource()}.
+ *
+ * @return the image producer that produces the pixels for the base image
+ * @see #getBaseImage()
+ *
+ * @since 9
+ */
@Override
public ImageProducer getSource() {
return getBaseImage().getSource();
}
+ /**
+ * As per the contract of the base {@code Image#getGraphics()} method,
+ * this implementation will always throw {@code UnsupportedOperationException}
+ * since only off-screen images can return a {@code Graphics} object.
+ *
+ * @return throws {@code UnsupportedOperationException}
+ * @throws UnsupportedOperationException this method is not supported
+ */
@Override
public Graphics getGraphics() {
throw new UnsupportedOperationException("getGraphics() not supported"
+ " on Multi-Resolution Images");
}
+ /**
+ * This method simply delegates to the same method on the base image and
+ * it is equivalent to: {@code getBaseImage().getProperty(name, observer)}.
+ *
+ * @return the value of the named property in the base image
+ * @see #getBaseImage()
+ *
+ * @since 9
+ */
@Override
public Object getProperty(String name, ImageObserver observer) {
return getBaseImage().getProperty(name, observer);
--- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html Mon Dec 19 16:05:38 2016 +0000
@@ -216,22 +216,27 @@
<h4><a name="MetadataIssuesRead"/>Metadata Issues</h4>
-By default all fields in the TIFF image file directory (IFD) are loaded into
-the native image metadata object. In cases where the IFD includes fields which
-contain large amounts of data this could be very inefficient. Which fields
-are loaded may be controlled by setting which TIFF tags the reader is allowed
-to recognize and whether it is ignoring metadata. The reader is informed to
-disregard metadata as usual via the <code>ignoreMetadata</code> parameter of
+By default all recognized fields in the TIFF image file directory (IFD) are
+loaded into the native image metadata object. Which fields are loaded may be
+controlled by setting which TIFF tags the reader is allowed to recognize,
+whether to read fields with unrecognized tags, and whether to ignore all
+metadata. The reader is informed to disregard all metadata as usual via the
+<code>ignoreMetadata</code> parameter of
<code>ImageReader.setInput(Object,boolean,boolean)</code>. It is
informed of which <a href="../../plugins/tiff/TIFFTag.html">TIFFTag</a>s to
recognize or not to recognize via
-<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code>
-and
+<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code> and
<code>TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet)</code>.
-If <code>ignoreMetadata</code> is <code>true</code>, then the reader will
-load into the native image metadata object only those fields which have a
-<code>TIFFTag</code> contained in the one of the allowed
-<code>TIFFTagSet</code>s.
+If <code>ignoreMetadata</code> is <code>true</code>, then only metadata
+essential to reading the image will be loaded into the native image metadata
+object. If <code>ignoreMetadata</code> is <code>false</code>, then the reader
+will by default load into the native image metadata object only those fields
+which are either essential to reading the image or have a <code>TIFFTag</code>
+contained in the one of the allowed <code>TIFFTagSet</code>s. Reading of
+fields with tags not in the allowed <code>TIFFTagSet</code>s may be forced
+by passing in a <code>TIFFImageReadParam</code> on which
+<code>TIFFImageReadParam.setReadUnknownTags(boolean)</code> has been
+invoked with parameter <code>true</code>.
<p>Use of a <a href="../../plugins/tiff/TIFFDirectory.html">TIFFDirectory</a>
object may simplify gaining access to metadata values. An instance of
@@ -534,7 +539,7 @@
<tr>
<td>ZLib</td>
<td>"Deflate/Inflate" compression (see note following this table)</td>
-<td><a href="http://partners.adobe.com/asn/developer/pdfs/tn/TIFFphotoshop.pdf">
+<td><a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf">
Adobe Photoshop® TIFF Technical Notes</a> (PDF)</td>
</tr>
<tr>
@@ -545,9 +550,9 @@
<tr>
<td>Deflate</td>
<td>"Zip-in-TIFF" compression (see note following this table)</td>
-<td><a href="http://www.isi.edu/in-notes/rfc1950.txt">
+<td><a href="https://tools.ietf.org/html/rfc1950">
ZLIB Compressed Data Format Specification</a>,
-<a href="http://www.isi.edu/in-notes/rfc1951.txt">
+<a href="https://tools.ietf.org/html/rfc1951">
DEFLATE Compressed Data Format Specification</a></td>
</tr>
<tr>
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java Mon Dec 19 16:05:38 2016 +0000
@@ -224,7 +224,7 @@
* A value to be used with the "Compression" tag.
*
* @see #TAG_COMPRESSION
- * @see <a href="http://www.isi.edu/in-notes/rfc1951.txt">DEFLATE specification</a>
+ * @see <a href="https://tools.ietf.org/html/rfc1951">DEFLATE specification</a>
* @see <a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf"> TIFF Specification Supplement 2</a>
*/
public static final int COMPRESSION_DEFLATE = 32946;
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java Mon Dec 19 16:05:38 2016 +0000
@@ -29,7 +29,7 @@
/**
* A class representing the extra tags found in a
- * <a href="http://tools.ietf.org/html/rfc2306"> TIFF-F</a> (RFC 2036) file.
+ * <a href="http://tools.ietf.org/html/rfc2306.html">TIFF-F</a> (RFC 2036) file.
*
* @since 9
*/
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java Mon Dec 19 16:05:38 2016 +0000
@@ -30,10 +30,7 @@
/**
* A class representing the tags found in a GeoTIFF IFD. GeoTIFF is a
* standard for annotating georeferenced or geocoded raster imagery.
- * The GeoTIFF specification may be found at <a
- * href="http://www.remotesensing.org/geotiff/spec/geotiffhome.html">
- * {@code http://www.remotesensing.org/geotiff/spec/geotiffhome.html}
- * </a>. This class does <i>not</i> handle the <i>GeoKey</i>s referenced
+ * This class does <i>not</i> handle the <i>GeoKey</i>s referenced
* from a <i>GeoKeyDirectoryTag</i> as those are not TIFF tags per se.
*
* <p>The definitions of the data types referenced by the field
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java Mon Dec 19 16:05:38 2016 +0000
@@ -263,14 +263,16 @@
*/
public final class TIFFField implements Cloneable {
- private static final String[] typeNames = {
+ private static final long MAX_UINT32 = 0xffffffffL;
+
+ private static final String[] TYPE_NAMES = {
null,
"Byte", "Ascii", "Short", "Long", "Rational",
"SByte", "Undefined", "SShort", "SLong", "SRational",
"Float", "Double", "IFDPointer"
};
- private static final boolean[] isIntegral = {
+ private static final boolean[] IS_INTEGRAL = {
false,
true, false, true, true, false,
true, true, true, true, false,
@@ -544,6 +546,9 @@
* @throws IllegalArgumentException if {@code data} is an instance of
* a class incompatible with the specified type.
* @throws IllegalArgumentException if the size of the data array is wrong.
+ * @throws IllegalArgumentException if the type of the data array is
+ * {@code TIFF_LONG}, {@code TIFF_RATIONAL}, or {@code TIFF_IFD_POINTER}
+ * and any of the elements is negative or greater than {@code 0xffffffff}.
*/
public TIFFField(TIFFTag tag, int type, int count, Object data) {
if(tag == null) {
@@ -587,15 +592,50 @@
case TIFFTag.TIFF_LONG:
isDataArrayCorrect = data instanceof long[]
&& ((long[])data).length == count;
+ if (isDataArrayCorrect) {
+ for (long datum : (long[])data) {
+ if (datum < 0) {
+ throw new IllegalArgumentException
+ ("Negative value supplied for TIFF_LONG");
+ }
+ if (datum > MAX_UINT32) {
+ throw new IllegalArgumentException
+ ("Too large value supplied for TIFF_LONG");
+ }
+ }
+ }
break;
case TIFFTag.TIFF_IFD_POINTER:
isDataArrayCorrect = data instanceof long[]
&& ((long[])data).length == 1;
+ if (((long[])data)[0] < 0) {
+ throw new IllegalArgumentException
+ ("Negative value supplied for TIFF_IFD_POINTER");
+ }
+ if (((long[])data)[0] > MAX_UINT32) {
+ throw new IllegalArgumentException
+ ("Too large value supplied for TIFF_IFD_POINTER");
+ }
break;
case TIFFTag.TIFF_RATIONAL:
isDataArrayCorrect = data instanceof long[][]
- && ((long[][])data).length == count
- && ((long[][])data)[0].length == 2;
+ && ((long[][])data).length == count;
+ if (isDataArrayCorrect) {
+ for (long[] datum : (long[][])data) {
+ if (datum.length != 2) {
+ isDataArrayCorrect = false;
+ break;
+ }
+ if (datum[0] < 0 || datum[1] < 0) {
+ throw new IllegalArgumentException
+ ("Negative value supplied for TIFF_RATIONAL");
+ }
+ if (datum[0] > MAX_UINT32 || datum[1] > MAX_UINT32) {
+ throw new IllegalArgumentException
+ ("Too large value supplied for TIFF_RATIONAL");
+ }
+ }
+ }
break;
case TIFFTag.TIFF_SSHORT:
isDataArrayCorrect = data instanceof short[]
@@ -607,8 +647,15 @@
break;
case TIFFTag.TIFF_SRATIONAL:
isDataArrayCorrect = data instanceof int[][]
- && ((int[][])data).length == count
- && ((int[][])data)[0].length == 2;
+ && ((int[][])data).length == count;
+ if (isDataArrayCorrect) {
+ for (int[] datum : (int[][])data) {
+ if (datum.length != 2) {
+ isDataArrayCorrect = false;
+ break;
+ }
+ }
+ }
break;
case TIFFTag.TIFF_FLOAT:
isDataArrayCorrect = data instanceof float[]
@@ -658,27 +705,32 @@
/**
* Constructs a {@code TIFFField} with a single non-negative integral
- * value.
- * The field will have type
- * {@link TIFFTag#TIFF_SHORT TIFF_SHORT} if
- * {@code val < 65536} and type
- * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise. The count
- * of the field will be unity.
+ * value. The field will have type {@link TIFFTag#TIFF_SHORT TIFF_SHORT}
+ * if {@code value} is in {@code [0,0xffff]}, and type
+ * {@link TIFFTag#TIFF_LONG TIFF_LONG} if {@code value} is in
+ * {@code [0x10000,0xffffffff]}. The count of the field will be unity.
*
* @param tag The tag to associate with this field.
* @param value The value to associate with this field.
* @throws NullPointerException if {@code tag == null}.
- * @throws IllegalArgumentException if the derived type is unacceptable
- * for the supplied {@code TIFFTag}.
- * @throws IllegalArgumentException if {@code value < 0}.
+ * @throws IllegalArgumentException if {@code value} is not in
+ * {@code [0,0xffffffff]}.
+ * @throws IllegalArgumentException if {@code value} is in
+ * {@code [0,0xffff]} and {@code TIFF_SHORT} is an unacceptable type
+ * for the {@code TIFFTag}, or if {@code value} is in
+ * {@code [0x10000,0xffffffff]} and {@code TIFF_LONG} is an unacceptable
+ * type for the {@code TIFFTag}.
*/
- public TIFFField(TIFFTag tag, int value) {
+ public TIFFField(TIFFTag tag, long value) {
if(tag == null) {
throw new NullPointerException("tag == null!");
}
if (value < 0) {
throw new IllegalArgumentException("value < 0!");
}
+ if (value > MAX_UINT32) {
+ throw new IllegalArgumentException("value > 0xffffffff!");
+ }
this.tag = tag;
this.tagNumber = tag.getNumber();
@@ -687,7 +739,8 @@
if (value < 65536) {
if (!tag.isDataTypeOK(TIFFTag.TIFF_SHORT)) {
throw new IllegalArgumentException("Illegal data type "
- + TIFFTag.TIFF_SHORT + " for " + tag.getName() + " tag");
+ + getTypeName(TIFFTag.TIFF_SHORT) + " for tag "
+ + "\"" + tag.getName() + "\"");
}
this.type = TIFFTag.TIFF_SHORT;
char[] cdata = new char[1];
@@ -696,7 +749,8 @@
} else {
if (!tag.isDataTypeOK(TIFFTag.TIFF_LONG)) {
throw new IllegalArgumentException("Illegal data type "
- + TIFFTag.TIFF_LONG + " for " + tag.getName() + " tag");
+ + getTypeName(TIFFTag.TIFF_LONG) + " for tag "
+ + "\"" + tag.getName() + "\"");
}
this.type = TIFFTag.TIFF_LONG;
long[] ldata = new long[1];
@@ -799,7 +853,7 @@
throw new IllegalArgumentException("Unknown data type "+dataType);
}
- return typeNames[dataType];
+ return TYPE_NAMES[dataType];
}
/**
@@ -812,7 +866,7 @@
*/
public static int getTypeByName(String typeName) {
for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) {
- if (typeName.equals(typeNames[i])) {
+ if (typeName.equals(TYPE_NAMES[i])) {
return i;
}
}
@@ -887,7 +941,7 @@
* @return Whether the field type is integral.
*/
public boolean isIntegral() {
- return isIntegral[type];
+ return IS_INTEGRAL[type];
}
/**
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Mon Dec 19 16:05:38 2016 +0000
@@ -46,11 +46,18 @@
* {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet}
* are included.
*
+ * <p> Forcing reading of fields corresponding to {@code TIFFTag}s
+ * not in any of the allowed {@code TIFFTagSet}s may be effected via
+ * {@link #setReadUnknownTags setReadUnknownTags}.
+ *
* @since 9
*/
public final class TIFFImageReadParam extends ImageReadParam {
- private List<TIFFTagSet> allowedTagSets = new ArrayList<TIFFTagSet>(4);
+ private final List<TIFFTagSet> allowedTagSets =
+ new ArrayList<TIFFTagSet>(4);
+
+ private boolean readUnknownTags = false;
/**
* Constructs a {@code TIFFImageReadParam}. Tags defined by
@@ -72,7 +79,8 @@
/**
* Adds a {@code TIFFTagSet} object to the list of allowed
- * tag sets.
+ * tag sets. Attempting to add a duplicate object to the list
+ * has no effect.
*
* @param tagSet a {@code TIFFTagSet}.
*
@@ -83,7 +91,9 @@
if (tagSet == null) {
throw new IllegalArgumentException("tagSet == null!");
}
- allowedTagSets.add(tagSet);
+ if (!allowedTagSets.contains(tagSet)) {
+ allowedTagSets.add(tagSet);
+ }
}
/**
@@ -113,4 +123,27 @@
public List<TIFFTagSet> getAllowedTagSets() {
return allowedTagSets;
}
+
+ /**
+ * Set whether to read fields corresponding to {@code TIFFTag}s not in
+ * the allowed {@code TIFFTagSet}s. The default setting is {@code false}.
+ * If the TIFF {@code ImageReader} is ignoring metadata, then a setting
+ * of {@code true} is overridden as all metadata are ignored except those
+ * essential to reading the image itself.
+ *
+ * @param readUnknownTags Whether to read fields of unrecognized tags
+ */
+ public void setReadUnknownTags(boolean readUnknownTags) {
+ this.readUnknownTags = readUnknownTags;
+ }
+
+ /**
+ * Retrieve the setting of whether to read fields corresponding to unknown
+ * {@code TIFFTag}s.
+ *
+ * @return Whether to read fields of unrecognized tags
+ */
+ public boolean getReadUnknownTags() {
+ return readUnknownTags;
+ }
}
--- a/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java Mon Dec 19 16:05:38 2016 +0000
@@ -182,6 +182,8 @@
*/
private int modelRowCount;
+ // Whether to print warning about JDK-8160087
+ private static boolean warning8160087 = true;
/**
* Creates an empty <code>DefaultRowSorter</code>.
@@ -489,10 +491,7 @@
*/
public int convertRowIndexToView(int index) {
if (modelToView == null) {
- if (index < 0 || index >= modelRowCount) {
- throw new IndexOutOfBoundsException("Invalid index");
- }
- return index;
+ return convertUnsortedUnfiltered(index);
}
return modelToView[index];
}
@@ -504,14 +503,30 @@
*/
public int convertRowIndexToModel(int index) {
if (viewToModel == null) {
- if (index < 0 || index >= modelRowCount) {
- throw new IndexOutOfBoundsException("Invalid index");
- }
- return index;
+ return convertUnsortedUnfiltered(index);
}
return viewToModel[index].modelIndex;
}
+ private int convertUnsortedUnfiltered(int index) {
+ if (index < 0 || index >= modelRowCount) {
+ if(index >= modelRowCount &&
+ index < getModelWrapper().getRowCount()) {
+ // 8160087
+ if(warning8160087) {
+ warning8160087 = false;
+ System.err.println("WARNING: row index is bigger than " +
+ "sorter's row count. Most likely this is a wrong " +
+ "sorter usage.");
+ }
+ } else {
+ throw new IndexOutOfBoundsException("Invalid index");
+ }
+ }
+ return index;
+ }
+
+
private boolean isUnsorted() {
List<? extends SortKey> keys = getSortKeys();
int keySize = keys.size();
--- a/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java Mon Dec 19 16:05:38 2016 +0000
@@ -27,6 +27,7 @@
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
+import java.awt.Toolkit;
import java.awt.event.*;
import java.beans.JavaBean;
import java.beans.BeanProperty;
@@ -41,6 +42,8 @@
import javax.swing.plaf.*;
import javax.accessibility.*;
+import sun.awt.SunToolkit;
+
/**
* An implementation of a menu bar. You add <code>JMenu</code> objects to the
* menu bar to construct a menu. When the user selects a <code>JMenu</code>
@@ -144,6 +147,10 @@
* @see JComponent#updateUI
*/
public void updateUI() {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ if (tk instanceof SunToolkit) {
+ ((SunToolkit)tk).updateScreenMenuBarUI();
+ }
setUI((MenuBarUI)UIManager.getUI(this));
}
--- a/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java Mon Dec 19 16:05:38 2016 +0000
@@ -47,6 +47,7 @@
import java.util.Collections;
import sun.awt.AWTAccessor;
+import sun.swing.SwingUtilities2;
/**
* The "viewport" or "porthole" through which you see the underlying
@@ -1034,9 +1035,16 @@
private boolean isBlitting() {
Component view = getView();
return (scrollMode == BLIT_SCROLL_MODE) &&
- (view instanceof JComponent) && view.isOpaque();
+ (view instanceof JComponent) && view.isOpaque() && !isFPScale();
}
+ private boolean isFPScale() {
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc != null) {
+ return SwingUtilities2.isFloatingPointScale(gc.getDefaultTransform());
+ }
+ return false;
+ }
/**
* Returns the <code>JViewport</code>'s one child or <code>null</code>.
--- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Mon Dec 19 16:05:38 2016 +0000
@@ -45,7 +45,11 @@
import sun.security.action.GetPropertyAction;
import com.sun.java.swing.SwingUtilities3;
+import java.awt.geom.AffineTransform;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.pipe.Region;
import sun.swing.SwingAccessor;
+import sun.swing.SwingUtilities2;
import sun.swing.SwingUtilities2.RepaintListener;
/**
@@ -1517,9 +1521,12 @@
// standard Image buffer.
boolean paintCompleted = false;
Image offscreen;
+ int sw = w + 1;
+ int sh = h + 1;
+
if (repaintManager.useVolatileDoubleBuffer() &&
(offscreen = getValidImage(repaintManager.
- getVolatileOffscreenBuffer(bufferComponent, w, h))) != null) {
+ getVolatileOffscreenBuffer(bufferComponent, sw, sh))) != null) {
VolatileImage vImage = (java.awt.image.VolatileImage)offscreen;
GraphicsConfiguration gc = bufferComponent.
getGraphicsConfiguration();
@@ -1529,7 +1536,7 @@
VolatileImage.IMAGE_INCOMPATIBLE) {
repaintManager.resetVolatileDoubleBuffer(gc);
offscreen = repaintManager.getVolatileOffscreenBuffer(
- bufferComponent,w, h);
+ bufferComponent, sw, sh);
vImage = (java.awt.image.VolatileImage)offscreen;
}
paintDoubleBuffered(paintingComponent, vImage, g, x, y,
@@ -1589,8 +1596,18 @@
* Paints a portion of a component to an offscreen buffer.
*/
protected void paintDoubleBuffered(JComponent c, Image image,
- Graphics g, int clipX, int clipY,
- int clipW, int clipH) {
+ Graphics g, int clipX, int clipY,
+ int clipW, int clipH) {
+ if (image instanceof VolatileImage && isPixelsCopying(c, g)) {
+ paintDoubleBufferedFPScales(c, image, g, clipX, clipY, clipW, clipH);
+ } else {
+ paintDoubleBufferedImpl(c, image, g, clipX, clipY, clipW, clipH);
+ }
+ }
+
+ private void paintDoubleBufferedImpl(JComponent c, Image image,
+ Graphics g, int clipX, int clipY,
+ int clipW, int clipH) {
Graphics osg = image.getGraphics();
int bw = Math.min(clipW, image.getWidth(null));
int bh = Math.min(clipH, image.getHeight(null));
@@ -1629,6 +1646,76 @@
}
}
+ private void paintDoubleBufferedFPScales(JComponent c, Image image,
+ Graphics g, int clipX, int clipY,
+ int clipW, int clipH) {
+ Graphics osg = image.getGraphics();
+ Graphics2D g2d = (Graphics2D) g;
+ Graphics2D osg2d = (Graphics2D) osg;
+
+ AffineTransform identity = new AffineTransform();
+ int bw = Math.min(clipW, image.getWidth(null));
+ int bh = Math.min(clipH, image.getHeight(null));
+ int x, y, maxx, maxy;
+
+ AffineTransform tx = g2d.getTransform();
+ double scaleX = tx.getScaleX();
+ double scaleY = tx.getScaleY();
+ double trX = tx.getTranslateX();
+ double trY = tx.getTranslateY();
+
+ boolean translucent = volatileBufferType != Transparency.OPAQUE;
+ Composite oldComposite = g2d.getComposite();
+
+ try {
+ for (x = clipX, maxx = clipX + clipW; x < maxx; x += bw) {
+ for (y = clipY, maxy = clipY + clipH; y < maxy; y += bh) {
+
+ // draw x, y, bw, bh
+ int pixelx1 = Region.clipRound(x * scaleX + trX);
+ int pixely1 = Region.clipRound(y * scaleY + trY);
+ int pixelx2 = Region.clipRound((x + bw) * scaleX + trX);
+ int pixely2 = Region.clipRound((y + bh) * scaleY + trY);
+ int pixelw = pixelx2 - pixelx1;
+ int pixelh = pixely2 - pixely1;
+
+ osg2d.setTransform(identity);
+ if (translucent) {
+ final Color oldBg = g2d.getBackground();
+ g2d.setBackground(c.getBackground());
+ g2d.clearRect(pixelx1, pixely1, pixelw, pixelh);
+ g2d.setBackground(oldBg);
+ }
+
+ osg2d.setClip(0, 0, pixelw, pixelh);
+ osg2d.translate(trX - pixelx1, trY - pixely1);
+ osg2d.scale(scaleX, scaleY);
+ c.paintToOffscreen(osg, x, y, bw, bh, maxx, maxy);
+
+ g2d.setTransform(identity);
+ g2d.setClip(pixelx1, pixely1, pixelw, pixelh);
+ AffineTransform stx = new AffineTransform();
+ stx.translate(pixelx1, pixely1);
+ stx.scale(scaleX, scaleY);
+ g2d.setTransform(stx);
+
+ if (translucent) {
+ g2d.setComposite(AlphaComposite.Src);
+ }
+
+ g2d.drawImage(image, 0, 0, c);
+
+ if (translucent) {
+ g2d.setComposite(oldComposite);
+ }
+ g2d.setTransform(tx);
+ }
+ }
+ } finally {
+ osg.dispose();
+ }
+ }
+
/**
* If <code>image</code> is non-null with a positive size it
* is returned, otherwise null is returned.
@@ -1671,9 +1758,33 @@
*/
protected void dispose() {
}
+
+ private boolean isPixelsCopying(JComponent c, Graphics g) {
+
+ AffineTransform tx = getTransform(g);
+ GraphicsConfiguration gc = c.getGraphicsConfiguration();
+
+ if (tx == null || gc == null
+ || !SwingUtilities2.isFloatingPointScale(tx)) {
+ return false;
+ }
+
+ AffineTransform gcTx = gc.getDefaultTransform();
+
+ return gcTx.getScaleX() == tx.getScaleX()
+ && gcTx.getScaleY() == tx.getScaleY();
+ }
+
+ private static AffineTransform getTransform(Graphics g) {
+ if (g instanceof SunGraphics2D) {
+ return ((SunGraphics2D) g).transform;
+ } else if (g instanceof Graphics2D) {
+ return ((Graphics2D) g).getTransform();
+ }
+ return null;
+ }
}
-
private class DoubleBufferInfo {
public Image image;
public Dimension size;
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java Mon Dec 19 16:05:38 2016 +0000
@@ -571,7 +571,9 @@
/**
* Obsolete class, not used in this version.
+ * @deprecated As of JDK version 9. Obsolete class.
*/
+ @Deprecated(since = "9")
protected class SingleClickListener extends MouseAdapter {
/**
* Constructs an instance of {@code SingleClickListener}.
@@ -584,7 +586,9 @@
/**
* Obsolete class, not used in this version.
+ * @deprecated As of JDK version 9. Obsolete class.
*/
+ @Deprecated(since = "9")
@SuppressWarnings("serial") // Superclass is not serializable across versions
protected class FileRenderer extends DefaultListCellRenderer {
}
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,6 +26,7 @@
import java.awt.*;
import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
import java.lang.ref.SoftReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -750,7 +751,6 @@
* valid location in the associated document
* @see View#modelToView
*/
- @SuppressWarnings("deprecation")
public Shape modelToView(int pos, Shape a, Position.Bias b)
throws BadLocationException {
Rectangle alloc = a.getBounds();
@@ -777,9 +777,11 @@
if (pos > p0) {
Segment segment = SegmentCache.getSharedSegment();
loadText(segment, p0, pos);
- alloc.x += Utilities.getTabbedTextWidth(segment, metrics,
- alloc.x, WrappedPlainView.this, p0);
+ float x = alloc.x;
+ x += Utilities.getTabbedTextWidth(segment, metrics, x,
+ WrappedPlainView.this, p0);
SegmentCache.releaseSharedSegment(segment);
+ return new Rectangle2D.Float(x, alloc.y, alloc.width, alloc.height);
}
return alloc;
}
--- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java Mon Dec 19 16:05:38 2016 +0000
@@ -360,6 +360,12 @@
* Marks the specified window as an utility window for TrayIcon.
*/
void setTrayIconWindow(Window w, boolean isTrayIconWindow);
+
+ /**
+ * Return an array containing all the windows this
+ * window currently owns.
+ */
+ Window[] getOwnedWindows(Window w);
}
/**
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Mon Dec 19 16:05:38 2016 +0000
@@ -1857,6 +1857,9 @@
return time == null ? -1 : time;
}
+ public void updateScreenMenuBarUI() {
+ }
+
// Cosntant alpha
public boolean isWindowOpacitySupported() {
return false;
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Mon Dec 19 16:05:38 2016 +0000
@@ -3101,10 +3101,10 @@
if (scaleX == 1 && scaleY == 1) {
return null;
}
- sx1 = Region.clipScale(sx1, scaleX);
- sx2 = Region.clipScale(sx2, scaleX);
- sy1 = Region.clipScale(sy1, scaleY);
- sy2 = Region.clipScale(sy2, scaleY);
+ sx1 = Region.clipRound(sx1 * scaleX);
+ sx2 = Region.clipRound(sx2 * scaleX);
+ sy1 = Region.clipRound(sy1 * scaleY);
+ sy2 = Region.clipRound(sy2 * scaleY);
AffineTransform tx = null;
if (xform != null) {
--- a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java Mon Dec 19 16:05:38 2016 +0000
@@ -305,6 +305,12 @@
int startY = (int)Math.floor(y * scaleY);
int width = (int)Math.ceil((x + w) * scaleX) - startX;
int height = (int)Math.ceil((y + h) * scaleY) - startY;
+ if (startX + width > linestride) {
+ width = linestride - startX;
+ }
+ if (startY + height > bbImage.getHeight()) {
+ height = bbImage.getHeight() - startY;
+ }
for (int i = 0; i < height; i++) {
int from = (startY + i) * linestride + startX;
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Mon Dec 19 16:05:38 2016 +0000
@@ -33,6 +33,7 @@
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import static java.awt.geom.AffineTransform.TYPE_FLIP;
+import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
import java.awt.print.PrinterGraphics;
import java.text.BreakIterator;
@@ -2162,6 +2163,19 @@
return false;
}
+ public static boolean isFloatingPointScale(AffineTransform tx) {
+ int type = tx.getType() & ~(TYPE_FLIP | TYPE_TRANSLATION);
+ if (type == 0) {
+ return false;
+ } else if ((type & ~TYPE_MASK_SCALE) == 0) {
+ double scaleX = tx.getScaleX();
+ double scaleY = tx.getScaleY();
+ return (scaleX != (int) scaleX) || (scaleY != (int) scaleY);
+ } else {
+ return false;
+ }
+ }
+
/**
* Returns the client property for the given key if it is set; otherwise
* returns the {@L&F} property.
--- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c Mon Dec 19 16:05:38 2016 +0000
@@ -140,7 +140,7 @@
indices[storei] = baseIndex + cluster;
glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);
positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;
- positions[(storei*2)+1] = startY + y + glyphPos[i].y_offset * scale;
+ positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
x += glyphPos[i].x_advance * scale;
y += glyphPos[i].y_advance * scale;
storei++;
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -123,15 +123,26 @@
// Change in the size of the content window means, well, change of the size
// Change in the location of the content window means change in insets
boolean needHandleResize = !(newBounds.equals(getBounds()));
+ boolean needPaint = width <= 0 || height <= 0;
reshape(newBounds);
if (needHandleResize) {
insLog.fine("Sending RESIZED");
handleResize(newBounds);
}
+ if (needPaint) {
+ postPaintEvent(target, 0, 0, newBounds.width, newBounds.height);
+ }
} finally {
XToolkit.awtUnlock();
}
- validateSurface();
+ }
+
+ @Override
+ public void handleExposeEvent(XEvent xev) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+ super.handleExposeEvent(xev);
}
// NOTE: This method may be called by privileged threads.
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp Mon Dec 19 16:05:38 2016 +0000
@@ -251,7 +251,8 @@
m_bPauseDestroy = FALSE;
m_MessagesProcessing = 0;
- m_wheelRotationAmount = 0;
+ m_wheelRotationAmountX = 0;
+ m_wheelRotationAmountY = 0;
if (!sm_PrimaryDynamicTableBuilt) {
// do it once.
AwtComponent::BuildPrimaryDynamicTable();
@@ -1208,6 +1209,7 @@
WIN_MSG(WM_XBUTTONDOWN)
WIN_MSG(WM_XBUTTONUP)
WIN_MSG(WM_MOUSEWHEEL)
+ WIN_MSG(WM_MOUSEHWHEEL)
WIN_MSG(WM_PARENTNOTIFY)
WIN_MSG(WM_ENTERMENULOOP)
WIN_MSG(WM_EXITMENULOOP)
@@ -1639,6 +1641,7 @@
case WM_XBUTTONUP:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
case WM_AWT_MOUSEENTER:
case WM_AWT_MOUSEEXIT:
curPos = ::GetMessagePos();
@@ -1708,10 +1711,12 @@
case WM_AWT_MOUSEEXIT:
mr = WmMouseExit(static_cast<UINT>(wParam), myPos.x, myPos.y);
break;
- case WM_MOUSEWHEEL:
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
mr = WmMouseWheel(GET_KEYSTATE_WPARAM(wParam),
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
- GET_WHEEL_DELTA_WPARAM(wParam));
+ GET_WHEEL_DELTA_WPARAM(wParam),
+ switchMessage == WM_MOUSEHWHEEL);
break;
}
break;
@@ -2078,13 +2083,15 @@
MsgRouting AwtComponent::WmSetFocus(HWND hWndLostFocus)
{
- m_wheelRotationAmount = 0;
+ m_wheelRotationAmountX = 0;
+ m_wheelRotationAmountY = 0;
return mrDoDefault;
}
MsgRouting AwtComponent::WmKillFocus(HWND hWndGotFocus)
{
- m_wheelRotationAmount = 0;
+ m_wheelRotationAmountX = 0;
+ m_wheelRotationAmountY = 0;
return mrDoDefault;
}
@@ -2461,7 +2468,7 @@
}
MsgRouting AwtComponent::WmMouseWheel(UINT flags, int x, int y,
- int wheelRotation)
+ int wheelRotation, BOOL isHorizontal)
{
// convert coordinates to be Component-relative, not screen relative
// for wheeling when outside the window, this works similar to
@@ -2475,42 +2482,54 @@
// set some defaults
jint scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
- jint scrollLines = 3;
+ jint scrollUnits = 3;
BOOL result;
- UINT platformLines;
-
- m_wheelRotationAmount += wheelRotation;
+ UINT platformUnits;
+ jint roundedWheelRotation;
+ jdouble preciseWheelRotation;
// AWT interprets wheel rotation differently than win32, so we need to
// decode wheel amount.
- jint roundedWheelRotation = m_wheelRotationAmount / (-1 * WHEEL_DELTA);
- jdouble preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+ jint modifiers = GetJavaModifiers();
+ if (isHorizontal) {
+ modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK;
+ m_wheelRotationAmountX += wheelRotation;
+ roundedWheelRotation = m_wheelRotationAmountX / (WHEEL_DELTA);
+ preciseWheelRotation = (jdouble) wheelRotation / (WHEEL_DELTA);
+ result = ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
+ &platformUnits, 0);
+ } else {
+ m_wheelRotationAmountY += wheelRotation;
+ roundedWheelRotation = m_wheelRotationAmountY / (-1 * WHEEL_DELTA);
+ preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+ result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
+ &platformUnits, 0);
+ }
MSG msg;
- result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
- &platformLines, 0);
InitMessage(&msg, lastMessage, MAKEWPARAM(flags, wheelRotation),
MAKELPARAM(x, y));
if (result) {
- if (platformLines == WHEEL_PAGESCROLL) {
+ if (platformUnits == WHEEL_PAGESCROLL) {
scrollType = java_awt_event_MouseWheelEvent_WHEEL_BLOCK_SCROLL;
- scrollLines = 1;
+ scrollUnits = 1;
}
else {
scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
- scrollLines = platformLines;
+ scrollUnits = platformUnits;
}
}
DTRACE_PRINTLN("calling SendMouseWheelEvent");
SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, ::JVM_CurrentTimeMillis(NULL, 0),
- eventPt.x, eventPt.y, GetJavaModifiers(), 0, 0, scrollType,
- scrollLines, roundedWheelRotation, preciseWheelRotation, &msg);
-
- m_wheelRotationAmount %= WHEEL_DELTA;
+ eventPt.x, eventPt.y, modifiers, 0, 0, scrollType,
+ scrollUnits, roundedWheelRotation, preciseWheelRotation, &msg);
+
+ m_wheelRotationAmountX %= WHEEL_DELTA;
+ m_wheelRotationAmountY %= WHEEL_DELTA;
// this message could be propagated up to the parent chain
// by the mouse message post processors
return mrConsume;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h Mon Dec 19 16:05:38 2016 +0000
@@ -522,7 +522,7 @@
virtual MsgRouting WmMouseMove(UINT flags, int x, int y);
virtual MsgRouting WmMouseExit(UINT flags, int x, int y);
virtual MsgRouting WmMouseWheel(UINT flags, int x, int y,
- int wheelRotation);
+ int wheelRotation, BOOL isHorizontal);
virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
@@ -824,7 +824,8 @@
int windowMoveLockPosCY;
// 6524352: support finer-resolution
- int m_wheelRotationAmount;
+ int m_wheelRotationAmountX;
+ int m_wheelRotationAmountY;
BOOL deadKeyActive;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp Mon Dec 19 16:05:38 2016 +0000
@@ -240,6 +240,7 @@
(wParam == WM_RBUTTONDOWN) ||
(wParam == WM_MOUSEACTIVATE) ||
(wParam == WM_MOUSEWHEEL) ||
+ (wParam == WM_MOUSEHWHEEL) ||
(wParam == WM_NCLBUTTONDOWN) ||
(wParam == WM_NCMBUTTONDOWN) ||
(wParam == WM_NCRBUTTONDOWN))
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp Mon Dec 19 16:05:38 2016 +0000
@@ -484,7 +484,10 @@
if (fgProcessID != ::GetCurrentProcessId()) {
AwtWindow* window = (AwtWindow*)GetComponent(GetHWnd());
- if (window != NULL && window->IsFocusableWindow() && window->IsAutoRequestFocus() &&
+ if (window != NULL &&
+ window->IsFocusableWindow() &&
+ window->IsAutoRequestFocus() &&
+ !::IsWindowVisible(GetHWnd()) && // the window is really showing
!::IsWindow(GetModalBlocker(GetHWnd())))
{
// When the Java process is not allowed to set the foreground window
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp Mon Dec 19 16:05:38 2016 +0000
@@ -1590,7 +1590,7 @@
* the mouse, not the Component with the input focus.
*/
- if (msg.message == WM_MOUSEWHEEL) {
+ if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) {
//i.e. mouse is over client area for this window
DWORD hWndForWheelProcess;
DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess);
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -45,6 +45,10 @@
#define WM_MOUSEWHEEL 0x020A
#endif //WM_MOUSEWHEEL
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL 0x020E
+#endif //WM_MOUSEHWHEEL
+
#ifndef WHEEL_DELTA
#define WHEEL_DELTA 120
#endif //WHEEL_DELTA
@@ -54,12 +58,16 @@
#endif //WHEEL_PAGESCROLL
#ifndef SPI_GETWHEELSCROLLLINES
-#define SPI_GETWHEELSCROLLLINES 104
+#define SPI_GETWHEELSCROLLLINES 0x0068
#endif //SPI_GETWHEELSCROLLLINES
+#ifndef SPI_GETWHEELSCROLLCHARS
+#define SPI_GETWHEELSCROLLCHARS 0x006C
+#endif //SPI_GETWHEELSCROLLCHARS
+
#ifndef SM_MOUSEWHEELPRESENT
#define SM_MOUSEWHEELPRESENT 75
-#endif //SPI_GETWHEELSCROLLLINES
+#endif //SM_MOUSEWHEELPRESENT
#ifndef COLOR_HOTLIGHT
#define COLOR_HOTLIGHT 26
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java Mon Dec 19 16:05:38 2016 +0000
@@ -27,7 +27,6 @@
import java.util.ArrayList; // JDK 1.2
import java.util.List;
-import java.util.Iterator;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
@@ -290,23 +289,28 @@
* @param threshold an entry idle since this time has expired.
* @return true if no more connections in list
*/
- synchronized boolean expire(long threshold) {
- Iterator<ConnectionDesc> iter = conns.iterator();
- ConnectionDesc entry;
- while (iter.hasNext()) {
- entry = iter.next();
+ boolean expire(long threshold) {
+ List<ConnectionDesc> clonedConns;
+ synchronized(this) {
+ clonedConns = new ArrayList<>(conns);
+ }
+ List<ConnectionDesc> expired = new ArrayList<>();
+
+ for (ConnectionDesc entry : clonedConns) {
+ d("expire(): ", entry);
if (entry.expire(threshold)) {
- d("expire(): removing ", entry);
- td("Expired ", entry);
-
- iter.remove(); // remove from pool
-
- // Don't need to call notify() because we're
- // removing only idle connections. If there were
- // idle connections, then there should be no waiters.
+ expired.add(entry);
+ td("expire(): Expired ", entry);
}
}
- return conns.isEmpty(); // whether whole list has 'expired'
+
+ synchronized (this) {
+ conns.removeAll(expired);
+ // Don't need to call notify() because we're
+ // removing only idle connections. If there were
+ // idle connections, then there should be no waiters.
+ return conns.isEmpty(); // whether whole list has 'expired'
+ }
}
/**
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java Mon Dec 19 16:05:38 2016 +0000
@@ -25,11 +25,11 @@
package com.sun.jndi.ldap.pool;
+import java.util.ArrayList;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.Collection;
import java.util.Collections;
-import java.util.Iterator;
import java.util.LinkedList;
import java.io.PrintStream;
@@ -166,17 +166,25 @@
* and removed.
*/
public void expire(long threshold) {
+ Collection<ConnectionsRef> copy;
synchronized (map) {
- Iterator<ConnectionsRef> iter = map.values().iterator();
- Connections conns;
- while (iter.hasNext()) {
- conns = iter.next().getConnections();
- if (conns.expire(threshold)) {
- d("expire(): removing ", conns);
- iter.remove();
- }
+ copy = new ArrayList<>(map.values());
+ }
+
+ ArrayList<ConnectionsRef> removed = new ArrayList<>();
+ Connections conns;
+ for (ConnectionsRef ref : copy) {
+ conns = ref.getConnections();
+ if (conns.expire(threshold)) {
+ d("expire(): removing ", conns);
+ removed.add(ref);
}
}
+
+ synchronized (map) {
+ map.values().removeAll(removed);
+ }
+
expungeStaleConnections();
}
--- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Mon Dec 19 16:05:38 2016 +0000
@@ -41,46 +41,41 @@
/**
- * <P>The basic service for managing a set of JDBC drivers.<br>
- * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
- * JDBC 2.0 API, provides another way to connect to a data source.
- * The use of a <code>DataSource</code> object is the preferred means of
+ * The basic service for managing a set of JDBC drivers.
+ * <p>
+ * <strong>NOTE:</strong> The {@link javax.sql.DataSource} interface, provides
+ * another way to connect to a data source.
+ * The use of a {@code DataSource} object is the preferred means of
* connecting to a data source.
+ * <P>
+ * As part of its initialization, the {@code DriverManager} class will
+ * attempt to load available JDBC drivers by using:
+ * <ul>
+ * <li>The {@code jdbc.drivers} system property which contains a
+ * colon separated list of fully qualified class names of JDBC drivers. Each
+ * driver is loaded using the {@linkplain ClassLoader#getSystemClassLoader
+ * system class loader}:
+ * <ul>
+ * <li>{@code jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver}
+ * </ul>
*
- * <P>As part of its initialization, the <code>DriverManager</code> class will
- * attempt to load the driver classes referenced in the "jdbc.drivers"
- * system property. This allows a user to customize the JDBC Drivers
- * used by their applications. For example in your
- * ~/.hotjava/properties file you might specify:
- * <pre>
- * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
- * </pre>
- *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
- * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
- * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
- * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
- * implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class,
- * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
- * <pre>
- * <code>my.sql.Driver</code>
- * </pre>
+ * <li>Service providers of the {@code java.sql.Driver} class, that are loaded
+ * via the {@linkplain ServiceLoader#load service-provider loading} mechanism.
+ *</ul>
*
- * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
- * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
- * modification.
+ *<P>
+ * @ImplNote
+ * {@code DriverManager} initialization is done lazily and looks up service
+ * providers using the thread context class loader. The drivers loaded and
+ * available to an application will depend on the thread context class loader of
+ * the thread that triggers driver initialization by {@code DriverManager}.
*
- * <P>When the method <code>getConnection</code> is called,
- * the <code>DriverManager</code> will attempt to
+ * <P>When the method {@code getConnection} is called,
+ * the {@code DriverManager} will attempt to
* locate a suitable driver from amongst those loaded at
- * initialization and those loaded explicitly using the same classloader
- * as the current applet or application.
+ * initialization and those loaded explicitly using the same class loader
+ * as the current application.
*
- * <P>
- * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
- * logging stream can be set only if the proper
- * permission has been granted. Normally this will be done with
- * the tool PolicyTool, which can be used to grant <code>permission
- * java.sql.SQLPermission "setLog"</code>.
* @see Driver
* @see Connection
*/
@@ -137,29 +132,15 @@
/**
* Sets the logging/tracing <code>PrintWriter</code> object
* that is used by the <code>DriverManager</code> and all drivers.
- * <P>
- * There is a minor versioning problem created by the introduction
- * of the method <code>setLogWriter</code>. The
- * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
- * that will be returned by <code>getLogStream</code>---the Java platform does
- * not provide a backward conversion. As a result, a new application
- * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
- * <code>getLogStream</code> will likely not see debugging information written
- * by that driver.
*<P>
- * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
- * to see that there is an <code>SQLPermission</code> object before setting
- * the logging stream. If a <code>SecurityManager</code> exists and its
- * <code>checkPermission</code> method denies setting the log writer, this
- * method throws a <code>java.lang.SecurityException</code>.
+ * If a security manager exists, its {@code checkPermission}
+ * method is first called with a {@code SQLPermission("setLog")}
+ * permission to check that the caller is allowed to call {@code setLogWriter}.
*
* @param out the new logging/tracing <code>PrintStream</code> object;
* <code>null</code> to disable logging and tracing
- * @throws SecurityException
- * if a security manager exists and its
- * <code>checkPermission</code> method denies
- * setting the log writer
- *
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies permission to set the log writer.
* @see SecurityManager#checkPermission
* @see #getLogWriter
* @since 1.2
@@ -374,8 +355,9 @@
* If a {@code null} value is specified for the driver to be removed, then no
* action is taken.
* <p>
- * If a security manager exists and its {@code checkPermission} denies
- * permission, then a {@code SecurityException} will be thrown.
+ * If a security manager exists, its {@code checkPermission}
+ * method is first called with a {@code SQLPermission("deregisterDriver")}
+ * permission to check that the caller is allowed to deregister a JDBC Driver.
* <p>
* If the specified driver is not found in the list of registered drivers,
* then no action is taken. If the driver was found, it will be removed
@@ -501,17 +483,14 @@
* by the <code>DriverManager</code>
* and all drivers.
*<P>
- * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
- * to see that there is an <code>SQLPermission</code> object before setting
- * the logging stream. If a <code>SecurityManager</code> exists and its
- * <code>checkPermission</code> method denies setting the log writer, this
- * method throws a <code>java.lang.SecurityException</code>.
+ * If a security manager exists, its {@code checkPermission}
+ * method is first called with a {@code SQLPermission("setLog")}
+ * permission to check that the caller is allowed to call {@code setLogStream}.
*
* @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
* @deprecated Use {@code setLogWriter}
* @throws SecurityException if a security manager exists and its
- * <code>checkPermission</code> method denies setting the log stream
- *
+ * {@code checkPermission} method denies permission to set the log stream.
* @see SecurityManager#checkPermission
* @see #getLogStream
*/
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -25,10 +25,8 @@
package com.sun.java.accessibility.util;
-import java.util.*;
import java.awt.*;
import java.awt.event.*;
-import javax.accessibility.*;
import javax.swing.*;
import javax.swing.event.*;
import sun.awt.AWTPermissions;
@@ -55,7 +53,7 @@
* @deprecated This field is unused; to get the component with focus use the
* getComponentWithFocus method.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected Component componentWithFocus = null;
static private Component componentWithFocus_private = null;
@@ -69,7 +67,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected ComponentListener componentListener = null;
static private ComponentListener componentListener_private = null;
@@ -82,7 +80,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected ContainerListener containerListener = null;
static private ContainerListener containerListener_private = null;
@@ -95,7 +93,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected FocusListener focusListener = null;
static private FocusListener focusListener_private = null;
@@ -108,7 +106,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected KeyListener keyListener = null;
static private KeyListener keyListener_private = null;
@@ -121,7 +119,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected MouseListener mouseListener = null;
static private MouseListener mouseListener_private = null;
@@ -134,7 +132,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected MouseMotionListener mouseMotionListener = null;
static private MouseMotionListener mouseMotionListener_private = null;
@@ -147,7 +145,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected WindowListener windowListener = null;
static private WindowListener windowListener_private = null;
@@ -162,7 +160,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected ActionListener actionListener = null;
static private ActionListener actionListener_private = null;
@@ -175,7 +173,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected AdjustmentListener adjustmentListener = null;
static private AdjustmentListener adjustmentListener_private = null;
@@ -188,7 +186,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected ItemListener itemListener = null;
static private ItemListener itemListener_private = null;
@@ -201,7 +199,7 @@
*
* @deprecated This field is unused.
*/
- @Deprecated
+ @Deprecated(since="8", forRemoval=true)
static protected TextListener textListener = null;
static private TextListener textListener_private = null;
@@ -212,13 +210,8 @@
* This listener calls the other registered listeners when an event
* occurs. By doing things this way, the actual number of listeners
* installed on a component instance is drastically reduced.
- *
- * @deprecated This field is unused.
*/
- @Deprecated
- static protected AWTEventsListener awtListener = new AWTEventsListener();
-
- static private final AWTEventsListener awtListener_private = new AWTEventsListener();
+ static private final AWTEventsListener awtListener = new AWTEventsListener();
/**
* Returns the component that currently has keyboard focus. The return
@@ -253,7 +246,7 @@
static public void addComponentListener(ComponentListener l) {
if (componentListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.COMPONENT);
+ awtListener.installListeners(EventID.COMPONENT);
}
componentListener_private = AWTEventMulticaster.add(componentListener_private, l);
}
@@ -268,7 +261,7 @@
static public void removeComponentListener(ComponentListener l) {
componentListener_private = AWTEventMulticaster.remove(componentListener_private, l);
if (componentListener_private == null) {
- awtListener_private.removeListeners(EventID.COMPONENT);
+ awtListener.removeListeners(EventID.COMPONENT);
}
}
@@ -335,7 +328,7 @@
static public void addKeyListener(KeyListener l) {
if (keyListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.KEY);
+ awtListener.installListeners(EventID.KEY);
}
keyListener_private = AWTEventMulticaster.add(keyListener_private, l);
}
@@ -350,7 +343,7 @@
static public void removeKeyListener(KeyListener l) {
keyListener_private = AWTEventMulticaster.remove(keyListener_private, l);
if (keyListener_private == null) {
- awtListener_private.removeListeners(EventID.KEY);
+ awtListener.removeListeners(EventID.KEY);
}
}
@@ -367,7 +360,7 @@
static public void addMouseListener(MouseListener l) {
if (mouseListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.MOUSE);
+ awtListener.installListeners(EventID.MOUSE);
}
mouseListener_private = AWTEventMulticaster.add(mouseListener_private, l);
}
@@ -382,7 +375,7 @@
static public void removeMouseListener(MouseListener l) {
mouseListener_private = AWTEventMulticaster.remove(mouseListener_private, l);
if (mouseListener_private == null) {
- awtListener_private.removeListeners(EventID.MOUSE);
+ awtListener.removeListeners(EventID.MOUSE);
}
}
@@ -399,7 +392,7 @@
static public void addMouseMotionListener(MouseMotionListener l) {
if (mouseMotionListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.MOTION);
+ awtListener.installListeners(EventID.MOTION);
}
mouseMotionListener_private = AWTEventMulticaster.add(mouseMotionListener_private, l);
}
@@ -414,7 +407,7 @@
static public void removeMouseMotionListener(MouseMotionListener l) {
mouseMotionListener_private = AWTEventMulticaster.remove(mouseMotionListener_private, l);
if (mouseMotionListener_private == null) {
- awtListener_private.removeListeners(EventID.MOTION);
+ awtListener.removeListeners(EventID.MOTION);
}
}
@@ -431,7 +424,7 @@
static public void addWindowListener(WindowListener l) {
if (windowListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.WINDOW);
+ awtListener.installListeners(EventID.WINDOW);
}
windowListener_private = AWTEventMulticaster.add(windowListener_private, l);
}
@@ -446,7 +439,7 @@
static public void removeWindowListener(WindowListener l) {
windowListener_private = AWTEventMulticaster.remove(windowListener_private, l);
if (windowListener_private == null) {
- awtListener_private.removeListeners(EventID.WINDOW);
+ awtListener.removeListeners(EventID.WINDOW);
}
}
@@ -463,7 +456,7 @@
static public void addActionListener(ActionListener l) {
if (actionListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.ACTION);
+ awtListener.installListeners(EventID.ACTION);
}
actionListener_private = AWTEventMulticaster.add(actionListener_private, l);
}
@@ -478,7 +471,7 @@
static public void removeActionListener(ActionListener l) {
actionListener_private = AWTEventMulticaster.remove(actionListener_private, l);
if (actionListener_private == null) {
- awtListener_private.removeListeners(EventID.ACTION);
+ awtListener.removeListeners(EventID.ACTION);
}
}
@@ -496,7 +489,7 @@
static public void addAdjustmentListener(AdjustmentListener l) {
if (adjustmentListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.ADJUSTMENT);
+ awtListener.installListeners(EventID.ADJUSTMENT);
}
adjustmentListener_private = AWTEventMulticaster.add(adjustmentListener_private, l);
}
@@ -511,7 +504,7 @@
static public void removeAdjustmentListener(AdjustmentListener l) {
adjustmentListener_private = AWTEventMulticaster.remove(adjustmentListener_private, l);
if (adjustmentListener_private == null) {
- awtListener_private.removeListeners(EventID.ADJUSTMENT);
+ awtListener.removeListeners(EventID.ADJUSTMENT);
}
}
@@ -528,7 +521,7 @@
static public void addItemListener(ItemListener l) {
if (itemListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.ITEM);
+ awtListener.installListeners(EventID.ITEM);
}
itemListener_private = AWTEventMulticaster.add(itemListener_private, l);
}
@@ -543,7 +536,7 @@
static public void removeItemListener(ItemListener l) {
itemListener_private = AWTEventMulticaster.remove(itemListener_private, l);
if (itemListener_private == null) {
- awtListener_private.removeListeners(EventID.ITEM);
+ awtListener.removeListeners(EventID.ITEM);
}
}
@@ -560,7 +553,7 @@
static public void addTextListener(TextListener l) {
if (textListener_private == null) {
checkInstallPermission();
- awtListener_private.installListeners(EventID.TEXT);
+ awtListener.installListeners(EventID.TEXT);
}
textListener_private = AWTEventMulticaster.add(textListener_private, l);
}
@@ -575,7 +568,7 @@
static public void removeTextListener(TextListener l) {
textListener_private = AWTEventMulticaster.remove(textListener_private, l);
if (textListener_private == null) {
- awtListener_private.removeListeners(EventID.TEXT);
+ awtListener.removeListeners(EventID.TEXT);
}
}
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -63,7 +63,7 @@
* occurs. By doing things this way, the actual number of listeners
* installed on a component instance is drastically reduced.
*/
- static protected final AccessibilityEventListener accessibilityListener =
+ static private final AccessibilityEventListener accessibilityListener =
new AccessibilityEventListener();
/**
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -71,7 +71,7 @@
* occurs. By doing things this way, the actual number of listeners
* installed on a component instance is drastically reduced.
*/
- static protected final SwingEventListener swingListener = new SwingEventListener();
+ static private final SwingEventListener swingListener = new SwingEventListener();
/**
* Adds the specified listener to receive all {@link EventID#ANCESTOR ANCESTOR}
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Mon Dec 19 16:05:38 2016 +0000
@@ -34,6 +34,7 @@
import java.nio.file.Paths;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import jdk.internal.module.ModuleResolution;
/**
* Parser for GNU Style Options.
@@ -158,6 +159,31 @@
ModuleFinder.of(paths));
}
},
+ new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
+ void process(Main jartool, String opt, String arg) {
+ ModuleResolution mres = jartool.moduleResolution;
+ jartool.moduleResolution = mres.withDoNotResolveByDefault();
+ }
+ boolean isExtra() { return true; }
+ },
+ new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") {
+ void process(Main jartool, String opt, String arg) throws BadArgs {
+ ModuleResolution mres = ModuleResolution.empty();
+ if (jartool.moduleResolution.doNotResolveByDefault())
+ mres.withDoNotResolveByDefault();
+
+ if (arg.equals("deprecated")) {
+ jartool.moduleResolution = mres.withDeprecated();
+ } else if (arg.equals("deprecated-for-removal")) {
+ jartool.moduleResolution = mres.withDeprecatedForRemoval();
+ } else if (arg.equals("incubating")) {
+ jartool.moduleResolution = mres.withIncubating();
+ } else {
+ throw new BadArgs("error.bad.reason", arg);
+ }
+ }
+ boolean isExtra() { return true; }
+ },
new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
void process(Main jartool, String opt, String arg) {
jartool.flag0 = true;
@@ -175,17 +201,20 @@
// Other options
new Option(true, true, OptionType.OTHER, "--help", "-h") {
void process(Main jartool, String opt, String arg) throws BadArgs {
- if (jartool.info == null) {
- if (arg == null) {
- jartool.info = Main.Info.HELP;
- return;
- }
+ if (arg == null) {
+ jartool.info = Main.Info.HELP;
+ return;
+ }
- if (!arg.equals("compat"))
- throw new BadArgs("error.illegal.option", arg).showUsage(true);
+ if (!arg.equals("compat"))
+ throw new BadArgs("error.illegal.option", arg).showUsage(true);
- jartool.info = Main.Info.COMPAT_HELP;
- }
+ jartool.info = Main.Info.COMPAT_HELP;
+ }
+ },
+ new Option(false, OptionType.OTHER, "--help-extra") {
+ void process(Main jartool, String opt, String arg) throws BadArgs {
+ jartool.info = Main.Info.HELP_EXTRA;
}
},
new Option(false, OptionType.OTHER, "--version") {
@@ -229,6 +258,8 @@
boolean isHidden() { return false; }
+ boolean isExtra() { return false; }
+
boolean matches(String opt) {
for (String a : aliases) {
if (a.equals(opt)) {
@@ -292,6 +323,14 @@
}
static void printHelp(PrintWriter out) {
+ printHelp(out, false);
+ }
+
+ static void printHelpExtra(PrintWriter out) {
+ printHelp(out, true);
+ }
+
+ private static void printHelp(PrintWriter out, boolean printExtra) {
out.format("%s%n", Main.getMsg("main.help.preopt"));
for (OptionType type : OptionType.values()) {
boolean typeHeadingWritten = false;
@@ -304,6 +343,9 @@
if (o.isHidden() || name.equals("h")) {
continue;
}
+ if (o.isExtra() && !printExtra) {
+ continue;
+ }
if (!typeHeadingWritten) {
out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
typeHeadingWritten = true;
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Mon Dec 19 16:05:38 2016 +0000
@@ -47,7 +47,6 @@
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -57,11 +56,11 @@
import java.util.jar.Manifest;
import java.text.MessageFormat;
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.Checks;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
import jdk.internal.util.jar.JarIndex;
import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
@@ -211,6 +210,7 @@
/* To support additional GNU Style informational options */
enum Info {
HELP(GNUStyleOptions::printHelp),
+ HELP_EXTRA(GNUStyleOptions::printHelpExtra),
COMPAT_HELP(GNUStyleOptions::printCompatHelp),
USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
VERSION(GNUStyleOptions::printVersion);
@@ -225,6 +225,7 @@
/* Modular jar related options */
Version moduleVersion;
Pattern modulesToHash;
+ ModuleResolution moduleResolution = ModuleResolution.empty();
ModuleFinder moduleFinder = ModuleFinder.of();
private static final String MODULE_INFO = "module-info.class";
@@ -1991,12 +1992,13 @@
.collect(joining(" "));
}
- private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
private void printModuleDescriptor(InputStream entryInputStream)
throws IOException
{
- ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
+ ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
+ ModuleDescriptor md = attrs.descriptor();
+ ModuleHashes hashes = attrs.recordedHashes();
+
StringBuilder sb = new StringBuilder();
sb.append("\n");
if (md.isOpen())
@@ -2043,15 +2045,24 @@
md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
- JLMA.hashes(md).ifPresent(hashes ->
- hashes.names().stream().sorted().forEach(
+ if (hashes != null) {
+ hashes.names().stream().sorted().forEach(
mod -> sb.append("\n hashes ").append(mod).append(" ")
.append(hashes.algorithm()).append(" ")
- .append(hashes.hashFor(mod))));
+ .append(toHex(hashes.hashFor(mod))));
+ }
output(sb.toString());
}
+ private static String toHex(byte[] ba) {
+ StringBuilder sb = new StringBuilder(ba.length);
+ for (byte b: ba) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
private static String toBinaryName(String classname) {
return (classname.replace('.', '/')) + ".class";
}
@@ -2212,6 +2223,10 @@
}
}
+ if (moduleResolution.value() != 0) {
+ extender.moduleResolution(moduleResolution);
+ }
+
extender.write(baos);
return baos.toByteArray();
}
@@ -2228,13 +2243,12 @@
// Create a module finder that finds the modular JAR
// being created/updated
URI uri = Paths.get(fname).toUri();
- ModuleReference mref = new ModuleReference(descriptor, uri,
- new Supplier<>() {
- @Override
- public ModuleReader get() {
- throw new UnsupportedOperationException("should not reach here");
- }
- });
+ ModuleReference mref = new ModuleReference(descriptor, uri) {
+ @Override
+ public ModuleReader open() {
+ throw new UnsupportedOperationException("should not reach here");
+ }
+ };
// Compose a module finder with the module path and
// the modular JAR being created or updated
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Mon Dec 19 16:05:38 2016 +0000
@@ -46,6 +46,8 @@
together!
error.bad.dflag=\
'-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
+error.bad.reason=\
+ bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
error.nosuch.fileordir=\
{0} : no such file or directory
error.write.file=\
@@ -246,6 +248,12 @@
main.help.opt.create.update.module-path=\
\ -p, --module-path Location of module dependence for generating\n\
\ the hash
+main.help.opt.create.update.do-not-resolve-by-default=\
+\ --do-not-resolve-by-default Exclude from the default root set of modules
+main.help.opt.create.update.warn-if-resolved=\
+\ --warn-if-resolved Hint for a tool to issue a warning if the module\n\
+\ is resolved. One of deprecated, deprecated-for-removal,\n\
+\ or incubating
main.help.opt.create.update.index=\
\ Operation modifiers valid only in create, update, and generate-index mode:\n
main.help.opt.create.update.index.no-compress=\
@@ -254,6 +262,8 @@
\ Other options:\n
main.help.opt.other.help=\
\ -?, --help[:compat] Give this, or optionally the compatibility, help
+main.help.opt.other.help-extra=\
+\ --help-extra Give help on extra options
main.help.opt.other.version=\
\ --version Print program version
main.help.postopt=\
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java Mon Dec 19 16:05:38 2016 +0000
@@ -130,6 +130,7 @@
}
private final Path root;
+ private final Map<String, String> launchers;
private final Path mdir;
private final Set<String> modules = new HashSet<>();
private String targetOsName;
@@ -140,10 +141,9 @@
* @param root The image root directory.
* @throws IOException
*/
- public DefaultImageBuilder(Path root) throws IOException {
- Objects.requireNonNull(root);
-
- this.root = root;
+ public DefaultImageBuilder(Path root, Map<String, String> launchers) throws IOException {
+ this.root = Objects.requireNonNull(root);
+ this.launchers = Objects.requireNonNull(launchers);
this.mdir = root.resolve("lib");
Files.createDirectories(mdir);
}
@@ -235,7 +235,7 @@
// If native files are stripped completely, <root>/bin dir won't exist!
// So, don't bother generating launcher scripts.
if (Files.isDirectory(bin)) {
- prepareApplicationFiles(files, modules);
+ prepareApplicationFiles(files);
}
} catch (IOException ex) {
throw new PluginException(ex);
@@ -246,22 +246,44 @@
* Generates launcher scripts.
*
* @param imageContent The image content.
- * @param modules The set of modules that the runtime image contains.
* @throws IOException
*/
- protected void prepareApplicationFiles(ResourcePool imageContent, Set<String> modules) throws IOException {
+ protected void prepareApplicationFiles(ResourcePool imageContent) throws IOException {
// generate launch scripts for the modules with a main class
- for (String module : modules) {
+ for (Map.Entry<String, String> entry : launchers.entrySet()) {
+ String launcherEntry = entry.getValue();
+ int slashIdx = launcherEntry.indexOf("/");
+ String module, mainClassName;
+ if (slashIdx == -1) {
+ module = launcherEntry;
+ mainClassName = null;
+ } else {
+ module = launcherEntry.substring(0, slashIdx);
+ assert !module.isEmpty();
+ mainClassName = launcherEntry.substring(slashIdx + 1);
+ assert !mainClassName.isEmpty();
+ }
+
String path = "/" + module + "/module-info.class";
Optional<ResourcePoolEntry> res = imageContent.findEntry(path);
if (!res.isPresent()) {
throw new IOException("module-info.class not found for " + module + " module");
}
- Optional<String> mainClass;
ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes());
- mainClass = ModuleDescriptor.read(stream).mainClass();
- if (mainClass.isPresent()) {
- Path cmd = root.resolve("bin").resolve(module);
+ Optional<String> mainClass = ModuleDescriptor.read(stream).mainClass();
+ if (mainClassName == null && mainClass.isPresent()) {
+ mainClassName = mainClass.get();
+ }
+
+ if (mainClassName != null) {
+ // make sure main class exists!
+ if (!imageContent.findEntry("/" + module + "/" +
+ mainClassName.replace('.', '/') + ".class").isPresent()) {
+ throw new IllegalArgumentException(module + " does not have main class: " + mainClassName);
+ }
+
+ String launcherFile = entry.getKey();
+ Path cmd = root.resolve("bin").resolve(launcherFile);
// generate shell script for Unix platforms
StringBuilder sb = new StringBuilder();
sb.append("#!/bin/sh")
@@ -272,7 +294,7 @@
.append("\n");
sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
.append(module).append('/')
- .append(mainClass.get())
+ .append(mainClassName)
.append(" $@\n");
try (BufferedWriter writer = Files.newBufferedWriter(cmd,
@@ -286,7 +308,7 @@
}
// generate .bat file for Windows
if (isWindows()) {
- Path bat = root.resolve(BIN_DIRNAME).resolve(module + ".bat");
+ Path bat = root.resolve(BIN_DIRNAME).resolve(launcherFile + ".bat");
sb = new StringBuilder();
sb.append("@echo off")
.append("\r\n");
@@ -296,7 +318,7 @@
.append("\r\n");
sb.append("\"%DIR%\\java\" %JLINK_VM_OPTIONS% -m ")
.append(module).append('/')
- .append(mainClass.get())
+ .append(mainClassName)
.append(" %*\r\n");
try (BufferedWriter writer = Files.newBufferedWriter(bat,
@@ -305,6 +327,8 @@
writer.write(sb.toString());
}
}
+ } else {
+ throw new IllegalArgumentException(module + " doesn't contain main class & main not specified in command line");
}
}
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Mon Dec 19 16:05:38 2016 +0000
@@ -53,7 +53,9 @@
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.builder.DefaultImageBuilder;
import jdk.tools.jlink.plugin.Plugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
/**
* Implementation for the jlink tool.
@@ -109,6 +111,27 @@
task.options.output = path;
}, "--output"),
new Option<JlinkTask>(true, (task, opt, arg) -> {
+ String[] values = arg.split("=");
+ // check values
+ if (values.length != 2 || values[0].isEmpty() || values[1].isEmpty()) {
+ throw taskHelper.newBadArgs("err.launcher.value.format", arg);
+ } else {
+ String commandName = values[0];
+ String moduleAndMain = values[1];
+ int idx = moduleAndMain.indexOf("/");
+ if (idx != -1) {
+ if (moduleAndMain.substring(0, idx).isEmpty()) {
+ throw taskHelper.newBadArgs("err.launcher.module.name.empty", arg);
+ }
+
+ if (moduleAndMain.substring(idx + 1).isEmpty()) {
+ throw taskHelper.newBadArgs("err.launcher.main.class.empty", arg);
+ }
+ }
+ task.options.launchers.put(commandName, moduleAndMain);
+ }
+ }, "--launcher"),
+ new Option<JlinkTask>(true, (task, opt, arg) -> {
if ("little".equals(arg)) {
task.options.endian = ByteOrder.LITTLE_ENDIAN;
} else if ("big".equals(arg)) {
@@ -168,6 +191,7 @@
final Set<String> limitMods = new HashSet<>();
final Set<String> addMods = new HashSet<>();
Path output;
+ final Map<String, String> launchers = new HashMap<>();
Path packagedModulesPath;
ByteOrder endian = ByteOrder.nativeOrder();
boolean ignoreSigning = false;
@@ -260,7 +284,8 @@
config.getModules(),
config.getByteOrder(),
null,
- IGNORE_SIGNING_DEFAULT);
+ IGNORE_SIGNING_DEFAULT,
+ null);
// Then create the Plugin Stack
ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
@@ -284,7 +309,7 @@
}
private void postProcessOnly(Path existingImage) throws Exception {
- PluginsConfiguration config = taskHelper.getPluginsConfig(null);
+ PluginsConfiguration config = taskHelper.getPluginsConfig(null, null);
ExecutableImage img = DefaultImageBuilder.getExecutableImage(existingImage);
if (img == null) {
throw taskHelper.newBadArgs("err.existing.image.invalid");
@@ -328,11 +353,12 @@
roots,
options.endian,
options.packagedModulesPath,
- options.ignoreSigning);
+ options.ignoreSigning,
+ log);
// Then create the Plugin Stack
ImagePluginStack stack = ImagePluginConfiguration.
- parseConfiguration(taskHelper.getPluginsConfig(options.output));
+ parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers));
//Ask the stack to proceed
stack.operate(imageProvider);
@@ -344,9 +370,7 @@
*/
private ModuleFinder modulePathFinder() {
Path[] entries = options.modulePath.toArray(new Path[0]);
- ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
- .newModulePath(Runtime.version(), true, entries);
-
+ ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
if (!options.limitMods.isEmpty()) {
finder = limitFinder(finder, options.limitMods, Collections.emptySet());
}
@@ -364,8 +388,7 @@
Set<String> roots)
{
Path[] entries = paths.toArray(new Path[0]);
- ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
- .newModulePath(Runtime.version(), true, entries);
+ ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
// if limitmods is specified then limit the universe
if (!limitMods.isEmpty()) {
@@ -386,7 +409,8 @@
Set<String> roots,
ByteOrder order,
Path retainModulesPath,
- boolean ignoreSigning)
+ boolean ignoreSigning,
+ PrintWriter log)
throws IOException
{
if (roots.isEmpty()) {
@@ -398,6 +422,27 @@
ModuleFinder.of(),
roots);
+ // emit warning for modules that end with a digit
+ cf.modules().stream()
+ .map(ResolvedModule::name)
+ .filter(mn -> !Checks.hasLegalModuleNameLastCharacter(mn))
+ .forEach(mn -> System.err.println("WARNING: Module name \""
+ + mn + "\" may soon be illegal"));
+
+ // emit a warning for any incubating modules in the configuration
+ if (log != null) {
+ String im = cf.modules()
+ .stream()
+ .map(ResolvedModule::reference)
+ .filter(ModuleResolution::hasIncubatingWarning)
+ .map(ModuleReference::descriptor)
+ .map(ModuleDescriptor::name)
+ .collect(Collectors.joining(", "));
+
+ if (!"".equals(im))
+ log.println("WARNING: Using incubator modules: " + im);
+ }
+
Map<String, Path> mods = cf.modules().stream()
.collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java Mon Dec 19 16:05:38 2016 +0000
@@ -28,6 +28,7 @@
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.io.IOException;
import java.io.UncheckedIOException;
@@ -78,10 +79,12 @@
}
private static ModuleReference moduleReference(ModuleDescriptor desc) {
- return new ModuleReference(desc, null, () -> {
- IOException ioe = new IOException("<module reader unsupported>");
- throw new UncheckedIOException(ioe);
- });
+ return new ModuleReference(desc, null) {
+ @Override
+ public ModuleReader open() {
+ throw new UnsupportedOperationException();
+ }
+ };
}
private static Map<String, ModuleReference> allModRefs(ResourcePool pool) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Mon Dec 19 16:05:38 2016 +0000
@@ -58,7 +58,7 @@
import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
/**
*
@@ -403,7 +403,7 @@
return null;
}
- private PluginsConfiguration getPluginsConfig(Path output
+ private PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers
) throws IOException, BadArgs {
if (output != null) {
if (Files.exists(output)) {
@@ -440,9 +440,9 @@
// recreate or postprocessing don't require an output directory.
ImageBuilder builder = null;
if (output != null) {
- builder = new DefaultImageBuilder(output);
+ builder = new DefaultImageBuilder(output, launchers);
+ }
- }
return new Jlink.PluginsConfiguration(pluginsList,
builder, lastSorter);
}
@@ -745,9 +745,9 @@
+ bundleHelper.getMessage(key, args));
}
- public PluginsConfiguration getPluginsConfig(Path output)
+ public PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers)
throws IOException, BadArgs {
- return pluginOptions.getPluginsConfig(output);
+ return pluginOptions.getPluginsConfig(output, launchers);
}
public Path getExistingImage() {
@@ -765,9 +765,7 @@
static Layer createPluginsLayer(List<Path> paths) {
Path[] dirs = paths.toArray(new Path[0]);
- ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
- .newModulePath(Runtime.version(), true, dirs);
-
+ ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
Configuration bootConfiguration = Layer.boot().configuration();
try {
Configuration cf = bootConfiguration
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Mon Dec 19 16:05:38 2016 +0000
@@ -49,6 +49,7 @@
*/
public final class AppRuntimeImageBuilder {
private Path outputDir = null;
+ private Map<String, String> launchers = Collections.emptyMap();
private List<Path> modulePath = null;
private Set<String> addModules = null;
private Set<String> limitModules = null;
@@ -62,6 +63,10 @@
outputDir = value;
}
+ public void setLaunchers(Map<String, String> value) {
+ launchers = value;
+ }
+
public void setModulePath(List<Path> value) {
modulePath = value;
}
@@ -120,7 +125,7 @@
// build the image
Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration(
- plugins, new DefaultImageBuilder(outputDir), null);
+ plugins, new DefaultImageBuilder(outputDir, launchers), null);
Jlink jlink = new Jlink();
jlink.build(jlinkConfig, pluginConfig);
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1083 +0,0 @@
-/*
- * Copyright (c) 2015, 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.tools.jlink.internal.plugins;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.IntSupplier;
-
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleInfoExtender;
-import jdk.internal.module.SystemModules;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.*;
-
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*;
-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 Packages attribute,
- * if not present. It also determines the number of packages of
- * the boot layer at link time.
- *
- * This plugin will override jdk.internal.module.SystemModules class
- *
- * @see java.lang.module.SystemModuleFinder
- * @see SystemModules
- */
-public final class SystemModuleDescriptorPlugin implements Plugin {
- private static final JavaLangModuleAccess JLMA =
- SharedSecrets.getJavaLangModuleAccess();
-
- private static final String NAME = "system-modules";
- private static final String DESCRIPTION =
- PluginsResourceBundle.getDescription(NAME);
-
- private boolean enabled;
- public SystemModuleDescriptorPlugin() {
- this.enabled = true;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getDescription() {
- return DESCRIPTION;
- }
-
- @Override
- public Set<State> getState() {
- return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
- : EnumSet.of(State.DISABLED);
- }
-
- @Override
- public void configure(Map<String, String> config) {
- if (config.containsKey(NAME)) {
- enabled = false;
- }
- }
-
- @Override
- public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
- if (!enabled) {
- throw new PluginException(NAME + " was set");
- }
-
- SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
-
- // generate the byte code to create ModuleDescriptors
- // skip parsing module-info.class and skip name check
- in.moduleView().modules().forEach(module -> {
-
- ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
- // automatic module not supported yet
- () -> new PluginException("module-info.class not found for " +
- module.name() + " module")
- );
-
- assert module.name().equals(data.moduleName());
- try {
- ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes());
- ModuleDescriptor md = ModuleDescriptor.read(bain);
- validateNames(md);
-
- Set<String> packages = module.packages();
- generator.addModule(md, module.packages());
-
- // add Packages attribute if not exist
- if (md.packages().isEmpty() && packages.size() > 0) {
- bain.reset();
- ModuleInfoRewriter minfoWriter =
- new ModuleInfoRewriter(bain, module.packages());
- // replace with the overridden version
- data = data.copyWithContent(minfoWriter.getBytes());
- }
- out.add(data);
- } catch (IOException e) {
- throw new PluginException(e);
- }
- });
-
- // 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 out.build();
- }
-
- /*
- * Add Packages attribute
- */
- class ModuleInfoRewriter extends ByteArrayOutputStream {
- final ModuleInfoExtender extender;
- ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
- this.extender = ModuleInfoExtender.newExtender(in);
- // Add Packages attribute
- this.extender.packages(packages);
- this.extender.write(this);
- }
-
- byte[] getBytes() {
- return buf;
- }
- }
-
- void validateNames(ModuleDescriptor md) {
- Checks.requireModuleName(md.name());
- for (Requires req : md.requires()) {
- Checks.requireModuleName(req.name());
- }
- for (Exports e : md.exports()) {
- Checks.requirePackageName(e.source());
- if (e.isQualified())
- e.targets().forEach(Checks::requireModuleName);
- }
- for (Opens opens : md.opens()) {
- Checks.requirePackageName(opens.source());
- if (opens.isQualified())
- opens.targets().forEach(Checks::requireModuleName);
- }
- for (Provides provides : md.provides()) {
- Checks.requireServiceTypeName(provides.service());
- provides.providers().forEach(Checks::requireServiceProviderName);
- }
- for (String service : md.uses()) {
- Checks.requireServiceTypeName(service);
- }
- for (String pn : md.packages()) {
- Checks.requirePackageName(pn);
- }
- }
-
- /*
- * Returns the initial capacity for a new Set or Map of the given size
- * to avoid resizing.
- */
- static final int initialCapacity(int size) {
- if (size == 0) {
- return 0;
- } else {
- // Adjust to try and get size/capacity as close to the
- // HashSet/HashMap default load factor without going over.
- return (int)(Math.ceil((double)size / 0.75));
- }
- }
-
- /**
- * ClassWriter of a new jdk.internal.module.SystemModules class
- * to reconstitute ModuleDescriptor of the 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 =
- "[Ljava/lang/module/ModuleDescriptor;";
- private static final String REQUIRES_MODIFIER_CLASSNAME =
- "java/lang/module/ModuleDescriptor$Requires$Modifier";
- private static final String EXPORTS_MODIFIER_CLASSNAME =
- "java/lang/module/ModuleDescriptor$Exports$Modifier";
- private static final String OPENS_MODIFIER_CLASSNAME =
- "java/lang/module/ModuleDescriptor$Opens$Modifier";
-
- // static variables in SystemModules class
- private static final String MODULE_NAMES = "MODULE_NAMES";
- private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
- private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
-
- private static final int MAX_LOCAL_VARS = 256;
-
- private final int BUILDER_VAR = 0;
- private final int MD_VAR = 1; // variable for ModuleDescriptor
- private int nextLocalVar = 2; // index to next local variable
-
- private final ClassWriter cw;
- private MethodVisitor mv;
- private int nextModulesIndex = 0;
-
- // list of all ModuleDescriptorBuilders, invoked in turn when building.
- private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
-
- // module name to hash
- private final Map<String, byte[]> modulesToHash = new HashMap<>();
-
- // module name to index in MODULES_TO_HASH
- private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
-
- // A builder to create one single Set instance for a given set of
- // names or modifiers to reduce the footprint
- // e.g. target modules of qualified exports
- private final DedupSetBuilder dedupSetBuilder
- = new DedupSetBuilder(this::getNextLocalVar);
-
- public SystemModulesClassGenerator() {
- this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
- ClassWriter.COMPUTE_FRAMES);
- }
-
- private int getNextLocalVar() {
- return nextLocalVar++;
- }
-
- /*
- * static initializer initializing the static fields
- *
- * static Map<String, ModuleDescriptor> map = new HashMap<>();
- */
- private void clinit(int numModules, int numPackages) {
- 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 byte[][] MODULES_TO_HASH
- cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
- "[[B", null, null)
- .visitEnd();
-
- // public static int PACKAGES_IN_BOOT_LAYER;
- cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
- "I", null, numPackages)
- .visitEnd();
-
- this.mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
- null, null);
- mv.visitCode();
-
- // create the MODULE_NAMES array
- pushInt(numModules);
- mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-
- int index = 0;
- for (ModuleDescriptorBuilder builder : builders) {
- mv.visitInsn(DUP); // arrayref
- pushInt(index++);
- mv.visitLdcInsn(builder.md.name()); // value
- mv.visitInsn(AASTORE);
- }
-
- mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
- "[Ljava/lang/String;");
-
- // create the MODULES_TO_HASH array
- pushInt(numModules);
- mv.visitTypeInsn(ANEWARRAY, "[B");
-
- index = 0;
- for (ModuleDescriptorBuilder builder : builders) {
- String mn = builder.md.name();
- byte[] recordedHash = modulesToHash.get(mn);
- if (recordedHash != null) {
- mv.visitInsn(DUP); // arrayref
- pushInt(index);
- pushInt(recordedHash.length);
- mv.visitIntInsn(NEWARRAY, T_BYTE);
- for (int i = 0; i < recordedHash.length; i++) {
- mv.visitInsn(DUP); // arrayref
- pushInt(i);
- mv.visitIntInsn(BIPUSH, recordedHash[i]);
- mv.visitInsn(BASTORE);
- }
- mv.visitInsn(AASTORE);
- modulesToHashIndex.put(mn, index);
- }
- index++;
- }
-
- mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
-
- mv.visitInsn(RETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
-
- }
-
- /*
- * Adds the given ModuleDescriptor to the system module list, and
- * prepares mapping from various Sets to SetBuilders to emit an
- * optimized number of sets during build.
- */
- public void addModule(ModuleDescriptor md, Set<String> packages) {
- ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
- builders.add(builder);
-
- // exports
- for (Exports e : md.exports()) {
- dedupSetBuilder.stringSet(e.targets());
- dedupSetBuilder.exportsModifiers(e.modifiers());
- }
-
- // opens
- for (Opens opens : md.opens()) {
- dedupSetBuilder.stringSet(opens.targets());
- dedupSetBuilder.opensModifiers(opens.modifiers());
- }
-
- // requires
- for (Requires r : md.requires()) {
- dedupSetBuilder.requiresModifiers(r.modifiers());
- }
-
- // uses
- dedupSetBuilder.stringSet(md.uses());
-
- // hashes
- JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
- }
-
- /*
- * Generate bytecode for SystemModules
- */
- public ClassWriter getClassWriter() {
- int numModules = builders.size();
- int numPackages = 0;
- for (ModuleDescriptorBuilder builder : builders) {
- numPackages += builder.md.packages().size();
- }
-
- this.clinit(numModules, numPackages);
- this.mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
- "modules", "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
- "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, null);
- mv.visitCode();
- pushInt(numModules);
- mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
- mv.visitVarInsn(ASTORE, MD_VAR);
-
- for (ModuleDescriptorBuilder builder : builders) {
- builder.build();
- }
- mv.visitVarInsn(ALOAD, MD_VAR);
- mv.visitInsn(ARETURN);
- mv.visitMaxs(0, 0);
- mv.visitEnd();
- return cw;
- }
-
- public boolean isOverriddenClass(String path) {
- return path.equals("/java.base/" + CLASSNAME + ".class");
- }
-
- void pushInt(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);
- } else {
- throw new IllegalArgumentException("exceed limit: " + num);
- }
- }
-
- class ModuleDescriptorBuilder {
- static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
- static final String EXPORTS_TYPE =
- "Ljava/lang/module/ModuleDescriptor$Exports;";
- static final String OPENS_TYPE =
- "Ljava/lang/module/ModuleDescriptor$Opens;";
- static final String PROVIDES_TYPE =
- "Ljava/lang/module/ModuleDescriptor$Provides;";
- static final String REQUIRES_TYPE =
- "Ljava/lang/module/ModuleDescriptor$Requires;";
-
- // method signature for static Builder::newExports, newOpens,
- // newProvides, newRequires methods
- static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
- "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
- + EXPORTS_TYPE;
- static final String EXPORTS_MODIFIER_SET_STRING_SIG =
- "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
- static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
- "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
- + OPENS_TYPE;
- static final String OPENS_MODIFIER_SET_STRING_SIG =
- "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
- static final String PROVIDES_STRING_LIST_SIG =
- "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
- static final String REQUIRES_SET_STRING_SIG =
- "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
-
- // method signature for Builder instance methods that
- // return this Builder instance
- static final String EXPORTS_ARRAY_SIG =
- "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
- static final String OPENS_ARRAY_SIG =
- "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
- static final String PROVIDES_ARRAY_SIG =
- "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
- static final String REQUIRES_ARRAY_SIG =
- "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
- static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
- static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
- static final String STRING_BYTE_ARRAY_SIG =
- "(Ljava/lang/String;[B)" + BUILDER_TYPE;
- static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
-
-
- final ModuleDescriptor md;
- final Set<String> packages;
-
- ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
- if (md.isAutomatic()) {
- throw new InternalError("linking automatic module is not supported");
- }
- this.md = md;
- this.packages = packages;
- }
-
- void build() {
- // new jdk.internal.module.Builder
- newBuilder();
-
- // requires
- requires(md.requires());
-
- // exports
- exports(md.exports());
-
- // opens
- opens(md.opens());
-
- // uses
- uses(md.uses());
-
- // provides
- provides(md.provides());
-
- // all packages
- packages(packages);
-
- // version
- md.version().ifPresent(this::version);
-
- // main class
- md.mainClass().ifPresent(this::mainClass);
-
- // hashes
- JLMA.hashes(md).ifPresent(mh -> {
- algorithm(mh.algorithm());
- mh.names().forEach(mn -> moduleHash(mn, mh.hashFor(mn)));
- });
-
- putModuleDescriptor();
- }
-
- void newBuilder() {
- mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
- mv.visitInsn(DUP);
- mv.visitLdcInsn(md.name());
- mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
- "<init>", "(Ljava/lang/String;)V", false);
- mv.visitVarInsn(ASTORE, BUILDER_VAR);
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
-
- if (md.isOpen()) {
- setModuleBit("open", true);
- }
- if (md.isSynthetic()) {
- setModuleBit("synthetic", true);
- }
- }
-
- /*
- * Invoke Builder.<methodName>(boolean value)
- */
- void setModuleBit(String methodName, boolean value) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- if (value) {
- mv.visitInsn(ICONST_1);
- } else {
- mv.visitInsn(ICONST_0);
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- methodName, BOOLEAN_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Put ModuleDescriptor into the modules array
- */
- void putModuleDescriptor() {
- mv.visitVarInsn(ALOAD, MD_VAR);
- pushInt(nextModulesIndex++);
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitLdcInsn(md.hashCode());
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "build", "(I)Ljava/lang/module/ModuleDescriptor;",
- false);
- mv.visitInsn(AASTORE);
- }
-
- /*
- * Call Builder::newRequires to create Requires instances and
- * then pass it to the builder by calling:
- * Builder.requires(Requires[])
- *
- */
- void requires(Set<Requires> requires) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- pushInt(requires.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
- int arrayIndex = 0;
- for (Requires require : requires) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex++);
- newRequires(require.modifiers(), require.name());
- mv.visitInsn(AASTORE);
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "requires", REQUIRES_ARRAY_SIG, false);
- }
-
- /*
- * Invoke Builder.newRequires(Set<Modifier> mods, String mn)
- *
- * Set<Modifier> mods = ...
- * Builder.newRequires(mods, mn);
- */
- void newRequires(Set<Requires.Modifier> mods, String name) {
- int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
- mv.visitVarInsn(ALOAD, varIndex);
- mv.visitLdcInsn(name);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newRequires", REQUIRES_SET_STRING_SIG, false);
- }
-
- /*
- * Call Builder::newExports to create Exports instances and
- * then pass it to the builder by calling:
- * Builder.exports(Exports[])
- *
- */
- void exports(Set<Exports> exports) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- pushInt(exports.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
- int arrayIndex = 0;
- for (Exports export : exports) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex++);
- newExports(export.modifiers(), export.source(), export.targets());
- mv.visitInsn(AASTORE);
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "exports", EXPORTS_ARRAY_SIG, false);
- }
-
- /*
- * Invoke
- * Builder.newExports(Set<Exports.Modifier> ms, String pn,
- * Set<String> targets)
- * or
- * Builder.newExports(Set<Exports.Modifier> ms, String pn)
- *
- * Set<String> targets = new HashSet<>();
- * targets.add(t);
- * :
- * :
- *
- * Set<Modifier> mods = ...
- * Builder.newExports(mods, pn, targets);
- */
- void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
- int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
- if (!targets.isEmpty()) {
- int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
- mv.visitVarInsn(ALOAD, modifiersSetIndex);
- mv.visitLdcInsn(pn);
- mv.visitVarInsn(ALOAD, stringSetIndex);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
- } else {
- mv.visitVarInsn(ALOAD, modifiersSetIndex);
- mv.visitLdcInsn(pn);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
- }
- }
-
-
- /**
- * Call Builder::newOpens to create Opens instances and
- * then pass it to the builder by calling:
- * Builder.opens(Opens[])
- *
- */
- void opens(Set<Opens> opens) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- pushInt(opens.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
- int arrayIndex = 0;
- for (Opens open : opens) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex++);
- newOpens(open.modifiers(), open.source(), open.targets());
- mv.visitInsn(AASTORE);
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "opens", OPENS_ARRAY_SIG, false);
- }
-
- /*
- * Invoke
- * Builder.newOpens(Set<Opens.Modifier> ms, String pn,
- * Set<String> targets)
- * or
- * Builder.newOpens(Set<Opens.Modifier> ms, String pn)
- *
- * Set<String> targets = new HashSet<>();
- * targets.add(t);
- * :
- * :
- *
- * Set<Modifier> mods = ...
- * Builder.newOpens(mods, pn, targets);
- */
- void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
- int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
- if (!targets.isEmpty()) {
- int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
- mv.visitVarInsn(ALOAD, modifiersSetIndex);
- mv.visitLdcInsn(pn);
- mv.visitVarInsn(ALOAD, stringSetIndex);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
- } else {
- mv.visitVarInsn(ALOAD, modifiersSetIndex);
- mv.visitLdcInsn(pn);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
- }
- }
-
- /*
- * Invoke Builder.uses(Set<String> uses)
- */
- void uses(Set<String> uses) {
- int varIndex = dedupSetBuilder.indexOfStringSet(uses);
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitVarInsn(ALOAD, varIndex);
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "uses", SET_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Call Builder::newProvides to create Provides instances and
- * then pass it to the builder by calling:
- * Builder.provides(Provides[] provides)
- *
- */
- void provides(Collection<Provides> provides) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- pushInt(provides.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
- int arrayIndex = 0;
- for (Provides provide : provides) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex++);
- newProvides(provide.service(), provide.providers());
- mv.visitInsn(AASTORE);
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "provides", PROVIDES_ARRAY_SIG, false);
- }
-
- /*
- * Invoke Builder.newProvides(String service, Set<String> providers)
- *
- * Set<String> providers = new HashSet<>();
- * providers.add(impl);
- * :
- * :
- * Builder.newProvides(service, providers);
- */
- void newProvides(String service, List<String> providers) {
- mv.visitLdcInsn(service);
- pushInt(providers.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
- int arrayIndex = 0;
- for (String provider : providers) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex++);
- mv.visitLdcInsn(provider);
- mv.visitInsn(AASTORE);
- }
- mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
- "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
- mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
- "newProvides", PROVIDES_STRING_LIST_SIG, false);
- }
-
- /*
- * Invoke Builder.packages(String pn)
- */
- void packages(Set<String> packages) {
- int varIndex = dedupSetBuilder.newStringSet(packages);
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitVarInsn(ALOAD, varIndex);
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "packages", SET_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Invoke Builder.mainClass(String cn)
- */
- void mainClass(String cn) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitLdcInsn(cn);
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "mainClass", STRING_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Invoke Builder.version(Version v);
- */
- void version(Version v) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitLdcInsn(v.toString());
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "version", STRING_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Invoke Builder.algorithm(String a);
- */
- void algorithm(String alg) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitLdcInsn(alg);
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "algorithm", STRING_SIG, false);
- mv.visitInsn(POP);
- }
-
- /*
- * Invoke Builder.moduleHash(String name, byte[] hash);
- */
- void moduleHash(String name, byte[] hash) {
- mv.visitVarInsn(ALOAD, BUILDER_VAR);
- mv.visitLdcInsn(name);
-
- // must exist
- Integer index = modulesToHashIndex.get(name);
- if (index != null) {
- mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
- pushInt(index);
- mv.visitInsn(AALOAD);
- assert(Objects.equals(hash, modulesToHash.get(name)));
- } else {
- pushInt(hash.length);
- mv.visitIntInsn(NEWARRAY, T_BYTE);
- for (int i = 0; i < hash.length; i++) {
- mv.visitInsn(DUP); // arrayref
- pushInt(i);
- mv.visitIntInsn(BIPUSH, hash[i]);
- mv.visitInsn(BASTORE);
- }
- }
- mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
- "moduleHash", STRING_BYTE_ARRAY_SIG, false);
- mv.visitInsn(POP);
- }
- }
-
- /*
- * Wraps set creation, ensuring identical sets are properly deduplicated.
- */
- class DedupSetBuilder {
- // map Set<String> to a specialized builder to allow them to be
- // deduplicated as they are requested
- final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
-
- // map Set<Requires.Modifier> to a specialized builder to allow them to be
- // deduplicated as they are requested
- final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
- requiresModifiersSets = new HashMap<>();
-
- // map Set<Exports.Modifier> to a specialized builder to allow them to be
- // deduplicated as they are requested
- final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
- exportsModifiersSets = new HashMap<>();
-
- // map Set<Opens.Modifier> to a specialized builder to allow them to be
- // deduplicated as they are requested
- final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
- opensModifiersSets = new HashMap<>();
-
- private final int stringSetVar;
- private final int enumSetVar;
- private final IntSupplier localVarSupplier;
-
- DedupSetBuilder(IntSupplier localVarSupplier) {
- this.stringSetVar = localVarSupplier.getAsInt();
- this.enumSetVar = localVarSupplier.getAsInt();
- this.localVarSupplier = localVarSupplier;
- }
-
- /*
- * Add the given set of strings to this builder.
- */
- void stringSet(Set<String> strings) {
- stringSets.computeIfAbsent(strings,
- s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
- ).increment();
- }
-
- /*
- * Add the given set of Exports.Modifiers
- */
- void exportsModifiers(Set<Exports.Modifier> mods) {
- exportsModifiersSets.computeIfAbsent(mods, s ->
- new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
- enumSetVar, localVarSupplier)
- ).increment();
- }
-
- /*
- * Add the given set of Opens.Modifiers
- */
- void opensModifiers(Set<Opens.Modifier> mods) {
- opensModifiersSets.computeIfAbsent(mods, s ->
- new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
- enumSetVar, localVarSupplier)
- ).increment();
- }
-
- /*
- * Add the given set of Requires.Modifiers
- */
- void requiresModifiers(Set<Requires.Modifier> mods) {
- requiresModifiersSets.computeIfAbsent(mods, s ->
- new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
- enumSetVar, localVarSupplier)
- ).increment();
- }
-
- /*
- * Retrieve the index to the given set of Strings. Emit code to
- * generate it when SetBuilder::build is called.
- */
- int indexOfStringSet(Set<String> names) {
- return stringSets.get(names).build();
- }
-
- /*
- * Retrieve the index to the given set of Exports.Modifier.
- * Emit code to generate it when EnumSetBuilder::build is called.
- */
- int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
- return exportsModifiersSets.get(mods).build();
- }
-
- /**
- * Retrieve the index to the given set of Opens.Modifier.
- * Emit code to generate it when EnumSetBuilder::build is called.
- */
- int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
- return opensModifiersSets.get(mods).build();
- }
-
-
- /*
- * Retrieve the index to the given set of Requires.Modifier.
- * Emit code to generate it when EnumSetBuilder::build is called.
- */
- int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
- return requiresModifiersSets.get(mods).build();
- }
-
- /*
- * Build a new string set without any attempt to deduplicate it.
- */
- int newStringSet(Set<String> names) {
- int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
- assert index == stringSetVar;
- return index;
- }
- }
-
- /*
- * SetBuilder generates bytecode to create one single instance of Set
- * for a given set of elements and assign to a local variable slot.
- * When there is only one single reference to a Set<T>,
- * it will reuse defaultVarIndex. For a Set with multiple references,
- * it will use a new local variable retrieved from the nextLocalVar
- */
- class SetBuilder<T> {
- private final Set<T> elements;
- private final int defaultVarIndex;
- private final IntSupplier nextLocalVar;
- private int refCount;
- private int localVarIndex;
-
- SetBuilder(Set<T> elements,
- int defaultVarIndex,
- IntSupplier nextLocalVar) {
- this.elements = elements;
- this.defaultVarIndex = defaultVarIndex;
- this.nextLocalVar = nextLocalVar;
- }
-
- /*
- * Increments the number of references to this particular set.
- */
- final void increment() {
- refCount++;
- }
-
- /**
- * Generate the appropriate instructions to load an object reference
- * to the element onto the stack.
- */
- void visitElement(T element, MethodVisitor mv) {
- mv.visitLdcInsn(element);
- }
-
- /*
- * Build bytecode for the Set represented by this builder,
- * or get the local variable index of a previously generated set
- * (in the local scope).
- *
- * @return local variable index of the generated set.
- */
- final int build() {
- int index = localVarIndex;
- if (localVarIndex == 0) {
- // if non-empty and more than one set reference this builder,
- // emit to a unique local
- index = refCount <= 1 ? defaultVarIndex
- : nextLocalVar.getAsInt();
- if (index < MAX_LOCAL_VARS) {
- localVarIndex = index;
- } else {
- // overflow: disable optimization by using localVarIndex = 0
- index = defaultVarIndex;
- }
-
- generateSetOf(index);
- }
- return index;
- }
-
- private void generateSetOf(int index) {
- if (elements.size() <= 10) {
- // call Set.of(e1, e2, ...)
- StringBuilder sb = new StringBuilder("(");
- for (T t : elements) {
- sb.append("Ljava/lang/Object;");
- visitElement(t, mv);
- }
- sb.append(")Ljava/util/Set;");
- mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
- "of", sb.toString(), true);
- } else {
- // call Set.of(E... elements)
- pushInt(elements.size());
- mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
- int arrayIndex = 0;
- for (T t : elements) {
- mv.visitInsn(DUP); // arrayref
- pushInt(arrayIndex);
- visitElement(t, mv); // value
- mv.visitInsn(AASTORE);
- arrayIndex++;
- }
- mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
- "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
- }
- mv.visitVarInsn(ASTORE, index);
- }
- }
-
- /*
- * Generates bytecode to create one single instance of EnumSet
- * for a given set of modifiers and assign to a local variable slot.
- */
- class EnumSetBuilder<T> extends SetBuilder<T> {
-
- private final String className;
-
- EnumSetBuilder(Set<T> modifiers, String className,
- int defaultVarIndex,
- IntSupplier nextLocalVar) {
- super(modifiers, defaultVarIndex, nextLocalVar);
- this.className = className;
- }
-
- /**
- * Loads an Enum field.
- */
- void visitElement(T t, MethodVisitor mv) {
- mv.visitFieldInsn(GETSTATIC, className, t.toString(),
- "L" + className + ";");
- }
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,1246 @@
+/*
+ * 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.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.IntSupplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.SystemModules;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+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 Packages attribute,
+ * if not present. It also determines the number of packages of
+ * the boot layer at link time.
+ *
+ * This plugin will override jdk.internal.module.SystemModules class
+ *
+ * @see jdk.internal.module.SystemModuleFinder
+ * @see SystemModules
+ */
+public final class SystemModulesPlugin implements Plugin {
+ private static final JavaLangModuleAccess JLMA =
+ SharedSecrets.getJavaLangModuleAccess();
+
+ private static final String NAME = "system-modules";
+ private static final String DESCRIPTION =
+ PluginsResourceBundle.getDescription(NAME);
+
+ private boolean enabled;
+ public SystemModulesPlugin() {
+ this.enabled = true;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+
+ @Override
+ public Set<State> getState() {
+ return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
+ : EnumSet.of(State.DISABLED);
+ }
+
+ @Override
+ public void configure(Map<String, String> config) {
+ if (config.containsKey(NAME)) {
+ enabled = false;
+ }
+ }
+
+ @Override
+ public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+ if (!enabled) {
+ throw new PluginException(NAME + " was set");
+ }
+
+ SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
+
+ // generate the byte code to create ModuleDescriptors
+ // skip parsing module-info.class and skip name check
+ in.moduleView().modules().forEach(module -> {
+
+ ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
+ // automatic module not supported yet
+ () -> new PluginException("module-info.class not found for " +
+ module.name() + " module")
+ );
+
+ assert module.name().equals(data.moduleName());
+ try {
+ ModuleInfo moduleInfo = new ModuleInfo(data.contentBytes(), module.packages());
+ generator.addModule(moduleInfo);
+
+ // link-time validation
+ moduleInfo.validateNames();
+ // check if any exported or open package is not present
+ moduleInfo.validatePackages();
+
+ // Packages attribute needs update
+ if (moduleInfo.shouldAddPackagesAttribute()) {
+ // replace with the overridden version
+ data = data.copyWithContent(moduleInfo.getBytes());
+ }
+ out.add(data);
+ } catch (IOException e) {
+ throw new PluginException(e);
+ }
+ });
+
+ // 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 out.build();
+ }
+
+ class ModuleInfo {
+ final ModuleDescriptor descriptor;
+ final ModuleHashes recordedHashes;
+ final ModuleResolution moduleResolution;
+ final Set<String> packages;
+ final ByteArrayInputStream bain;
+
+ ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
+ this.bain = new ByteArrayInputStream(bytes);
+ this.packages = packages;
+
+ Attributes attrs = jdk.internal.module.ModuleInfo.read(bain, null);
+ this.descriptor = attrs.descriptor();
+ this.recordedHashes = attrs.recordedHashes();
+ this.moduleResolution = attrs.moduleResolution();
+
+ if (descriptor.isAutomatic()) {
+ throw new InternalError("linking automatic module is not supported");
+ }
+ }
+
+ String moduleName() {
+ return descriptor.name();
+ }
+
+ /**
+ * Validates names in ModuleDescriptor
+ */
+ void validateNames() {
+ Checks.requireModuleName(descriptor.name());
+ for (Requires req : descriptor.requires()) {
+ Checks.requireModuleName(req.name());
+ }
+ for (Exports e : descriptor.exports()) {
+ Checks.requirePackageName(e.source());
+ if (e.isQualified())
+ e.targets().forEach(Checks::requireModuleName);
+ }
+ for (Opens opens : descriptor.opens()) {
+ Checks.requirePackageName(opens.source());
+ if (opens.isQualified())
+ opens.targets().forEach(Checks::requireModuleName);
+ }
+ for (Provides provides : descriptor.provides()) {
+ Checks.requireServiceTypeName(provides.service());
+ provides.providers().forEach(Checks::requireServiceProviderName);
+ }
+ for (String service : descriptor.uses()) {
+ Checks.requireServiceTypeName(service);
+ }
+ for (String pn : descriptor.packages()) {
+ Checks.requirePackageName(pn);
+ }
+ }
+
+
+ /**
+ * Validates if exported and open packages are present
+ */
+ void validatePackages() {
+ Set<String> nonExistPackages = new TreeSet<>();
+ descriptor.exports().stream()
+ .map(Exports::source)
+ .filter(pn -> !packages.contains(pn))
+ .forEach(nonExistPackages::add);
+
+ descriptor.opens().stream()
+ .map(Opens::source)
+ .filter(pn -> !packages.contains(pn))
+ .forEach(nonExistPackages::add);
+
+ if (!nonExistPackages.isEmpty()) {
+ throw new PluginException("Packages that are exported or open in "
+ + descriptor.name() + " are not present: " + nonExistPackages);
+ }
+ }
+
+ /**
+ * Returns true if the PackagesAttribute should be written
+ */
+ boolean shouldAddPackagesAttribute() {
+ return descriptor.packages().isEmpty() && packages.size() > 0;
+ }
+
+ /**
+ * Returns the bytes for the module-info.class with PackagesAttribute
+ * if it contains at least one package
+ */
+ byte[] getBytes() throws IOException {
+ bain.reset();
+
+ // add Packages attribute if not exist
+ if (shouldAddPackagesAttribute()) {
+ return new ModuleInfoRewriter(bain, packages).getBytes();
+ } else {
+ return bain.readAllBytes();
+ }
+ }
+
+ class ModuleInfoRewriter extends ByteArrayOutputStream {
+ final ModuleInfoExtender extender;
+ ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
+ this.extender = ModuleInfoExtender.newExtender(in);
+ // Add Packages attribute
+ if (packages.size() > 0) {
+ this.extender.packages(packages);
+ }
+ this.extender.write(this);
+ }
+
+ byte[] getBytes() {
+ return buf;
+ }
+ }
+ }
+
+ /**
+ * ClassWriter of a new jdk.internal.module.SystemModules class
+ * to reconstitute ModuleDescriptor of the 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 =
+ "[Ljava/lang/module/ModuleDescriptor;";
+ private static final String REQUIRES_MODIFIER_CLASSNAME =
+ "java/lang/module/ModuleDescriptor$Requires$Modifier";
+ private static final String EXPORTS_MODIFIER_CLASSNAME =
+ "java/lang/module/ModuleDescriptor$Exports$Modifier";
+ private static final String OPENS_MODIFIER_CLASSNAME =
+ "java/lang/module/ModuleDescriptor$Opens$Modifier";
+ private static final String MODULE_HASHES_ARRAY_SIGNATURE =
+ "[Ljdk/internal/module/ModuleHashes;";
+ private static final String MODULE_RESOLUTION_CLASSNAME =
+ "jdk/internal/module/ModuleResolution";
+ 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;
+ private final int MD_VAR = 1; // variable for ModuleDescriptor
+ private final int MH_VAR = 1; // variable for ModuleHashes
+ private int nextLocalVar = 2; // index to next local variable
+
+ private final ClassWriter cw;
+
+ // Method visitor for generating the SystemModules::modules() method
+ private MethodVisitor mv;
+
+ // list of all ModuleDescriptorBuilders, invoked in turn when building.
+ private final List<ModuleInfo> moduleInfos = new ArrayList<>();
+
+ // A builder to create one single Set instance for a given set of
+ // names or modifiers to reduce the footprint
+ // e.g. target modules of qualified exports
+ private final DedupSetBuilder dedupSetBuilder
+ = new DedupSetBuilder(this::getNextLocalVar);
+
+ public SystemModulesClassGenerator() {
+ this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
+ ClassWriter.COMPUTE_FRAMES);
+ }
+
+ private int getNextLocalVar() {
+ return nextLocalVar++;
+ }
+
+ /*
+ * static initializer initializing the static fields
+ *
+ * static Map<String, ModuleDescriptor> map = new HashMap<>();
+ */
+ private void clinit(int numModules, int numPackages) {
+ 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();
+ }
+
+ /*
+ * Adds the given ModuleDescriptor to the system module list, and
+ * prepares mapping from various Sets to SetBuilders to emit an
+ * optimized number of sets during build.
+ */
+ public void addModule(ModuleInfo moduleInfo) {
+ ModuleDescriptor md = moduleInfo.descriptor;
+ moduleInfos.add(moduleInfo);
+
+ // exports
+ for (Exports e : md.exports()) {
+ dedupSetBuilder.stringSet(e.targets());
+ dedupSetBuilder.exportsModifiers(e.modifiers());
+ }
+
+ // opens
+ for (Opens opens : md.opens()) {
+ dedupSetBuilder.stringSet(opens.targets());
+ dedupSetBuilder.opensModifiers(opens.modifiers());
+ }
+
+ // requires
+ for (Requires r : md.requires()) {
+ dedupSetBuilder.requiresModifiers(r.modifiers());
+ }
+
+ // uses
+ dedupSetBuilder.stringSet(md.uses());
+ }
+
+ /*
+ * Generate bytecode for SystemModules
+ */
+ public ClassWriter getClassWriter() {
+ int numModules = moduleInfos.size();
+ int numPackages = 0;
+ for (ModuleInfo minfo : moduleInfos) {
+ numPackages += minfo.packages.size();
+ }
+
+ clinit(numModules, numPackages);
+
+ // generate SystemModules::descriptors
+ genDescriptorsMethod();
+ // generate SystemModules::hashes
+ genHashesMethod();
+ // generate SystemModules::moduleResolutions
+ genModuleResolutionsMethod();
+
+ return cw;
+ }
+
+ /*
+ * Generate bytecode for SystemModules::descriptors method
+ */
+ private void genDescriptorsMethod() {
+ this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+ "descriptors",
+ "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+ "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+ null);
+ mv.visitCode();
+ pushInt(mv, moduleInfos.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
+ mv.visitVarInsn(ASTORE, MD_VAR);
+
+ for (int index = 0; index < moduleInfos.size(); index++) {
+ ModuleInfo minfo = moduleInfos.get(index);
+ new ModuleDescriptorBuilder(minfo.descriptor,
+ minfo.packages,
+ index).build();
+ }
+ mv.visitVarInsn(ALOAD, MD_VAR);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ }
+
+ /*
+ * Generate bytecode for SystemModules::hashes method
+ */
+ private void genHashesMethod() {
+ MethodVisitor hmv =
+ cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+ "hashes",
+ "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+ "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+ null);
+ hmv.visitCode();
+ pushInt(hmv, moduleInfos.size());
+ hmv.visitTypeInsn(ANEWARRAY, "jdk/internal/module/ModuleHashes");
+ hmv.visitVarInsn(ASTORE, MH_VAR);
+
+ for (int index = 0; index < moduleInfos.size(); index++) {
+ ModuleInfo minfo = moduleInfos.get(index);
+ if (minfo.recordedHashes != null) {
+ new ModuleHashesBuilder(minfo.recordedHashes,
+ index,
+ hmv).build();
+ }
+ }
+
+ hmv.visitVarInsn(ALOAD, MH_VAR);
+ hmv.visitInsn(ARETURN);
+ hmv.visitMaxs(0, 0);
+ hmv.visitEnd();
+
+ }
+
+ /*
+ * Generate bytecode for SystemModules::methodResoultions method
+ */
+ private void genModuleResolutionsMethod() {
+ MethodVisitor mresmv =
+ cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+ "moduleResolutions",
+ "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+ "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+ null);
+ mresmv.visitCode();
+ pushInt(mresmv, moduleInfos.size());
+ mresmv.visitTypeInsn(ANEWARRAY, MODULE_RESOLUTION_CLASSNAME);
+ mresmv.visitVarInsn(ASTORE, 0);
+
+ for (int index=0; index < moduleInfos.size(); index++) {
+ ModuleInfo minfo = moduleInfos.get(index);
+ if (minfo.moduleResolution != null) {
+ mresmv.visitVarInsn(ALOAD, 0);
+ pushInt(mresmv, index);
+ mresmv.visitTypeInsn(NEW, MODULE_RESOLUTION_CLASSNAME);
+ mresmv.visitInsn(DUP);
+ mresmv.visitLdcInsn(minfo.moduleResolution.value());
+ mresmv.visitMethodInsn(INVOKESPECIAL,
+ MODULE_RESOLUTION_CLASSNAME,
+ "<init>",
+ "(I)V", false);
+ mresmv.visitInsn(AASTORE);
+ }
+ }
+ mresmv.visitVarInsn(ALOAD, 0);
+ mresmv.visitInsn(ARETURN);
+ mresmv.visitMaxs(0, 0);
+ mresmv.visitEnd();
+ }
+
+ public boolean isOverriddenClass(String path) {
+ return path.equals("/java.base/" + CLASSNAME + ".class");
+ }
+
+ 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);
+ } else {
+ throw new IllegalArgumentException("exceed limit: " + num);
+ }
+ }
+
+ class ModuleDescriptorBuilder {
+ static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
+ static final String EXPORTS_TYPE =
+ "Ljava/lang/module/ModuleDescriptor$Exports;";
+ static final String OPENS_TYPE =
+ "Ljava/lang/module/ModuleDescriptor$Opens;";
+ static final String PROVIDES_TYPE =
+ "Ljava/lang/module/ModuleDescriptor$Provides;";
+ static final String REQUIRES_TYPE =
+ "Ljava/lang/module/ModuleDescriptor$Requires;";
+
+ // method signature for static Builder::newExports, newOpens,
+ // newProvides, newRequires methods
+ static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+ + EXPORTS_TYPE;
+ static final String EXPORTS_MODIFIER_SET_STRING_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
+ static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+ + OPENS_TYPE;
+ static final String OPENS_MODIFIER_SET_STRING_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
+ static final String PROVIDES_STRING_LIST_SIG =
+ "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
+ static final String REQUIRES_SET_STRING_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
+ static final String REQUIRES_SET_STRING_STRING_SIG =
+ "(Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;)" + REQUIRES_TYPE;
+
+ // method signature for Builder instance methods that
+ // return this Builder instance
+ static final String EXPORTS_ARRAY_SIG =
+ "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
+ static final String OPENS_ARRAY_SIG =
+ "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
+ static final String PROVIDES_ARRAY_SIG =
+ "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
+ static final String REQUIRES_ARRAY_SIG =
+ "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
+ static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
+ static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
+ static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
+
+ final ModuleDescriptor md;
+ final Set<String> packages;
+ final int index;
+ ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) {
+ if (md.isAutomatic()) {
+ throw new InternalError("linking automatic module is not supported");
+ }
+ this.md = md;
+ this.packages = packages;
+ this.index = index;
+ }
+
+ void build() {
+ // new jdk.internal.module.Builder
+ newBuilder();
+
+ // requires
+ requires(md.requires());
+
+ // exports
+ exports(md.exports());
+
+ // opens
+ opens(md.opens());
+
+ // uses
+ uses(md.uses());
+
+ // provides
+ provides(md.provides());
+
+ // all packages
+ packages(packages);
+
+ // version
+ md.version().ifPresent(this::version);
+
+ // main class
+ md.mainClass().ifPresent(this::mainClass);
+
+ putModuleDescriptor();
+ }
+
+ void newBuilder() {
+ mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn(md.name());
+ mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
+ "<init>", "(Ljava/lang/String;)V", false);
+ mv.visitVarInsn(ASTORE, BUILDER_VAR);
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+
+ if (md.isOpen()) {
+ setModuleBit("open", true);
+ }
+ if (md.isSynthetic()) {
+ setModuleBit("synthetic", true);
+ }
+ }
+
+ /*
+ * Invoke Builder.<methodName>(boolean value)
+ */
+ void setModuleBit(String methodName, boolean value) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ if (value) {
+ mv.visitInsn(ICONST_1);
+ } else {
+ mv.visitInsn(ICONST_0);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ methodName, BOOLEAN_SIG, false);
+ mv.visitInsn(POP);
+ }
+
+ /*
+ * Put ModuleDescriptor into the modules array
+ */
+ void putModuleDescriptor() {
+ mv.visitVarInsn(ALOAD, MD_VAR);
+ pushInt(mv, index);
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ mv.visitLdcInsn(md.hashCode());
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "build", "(I)Ljava/lang/module/ModuleDescriptor;",
+ false);
+ mv.visitInsn(AASTORE);
+ }
+
+ /*
+ * Call Builder::newRequires to create Requires instances and
+ * then pass it to the builder by calling:
+ * Builder.requires(Requires[])
+ *
+ */
+ void requires(Set<Requires> requires) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ pushInt(mv, requires.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
+ int arrayIndex = 0;
+ for (Requires require : requires) {
+ String compiledVersion = null;
+ if (require.compiledVersion().isPresent()) {
+ compiledVersion = require.compiledVersion().get().toString();
+ }
+
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex++);
+ newRequires(require.modifiers(), require.name(), compiledVersion);
+ mv.visitInsn(AASTORE);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "requires", REQUIRES_ARRAY_SIG, false);
+ }
+
+ /*
+ * Invoke Builder.newRequires(Set<Modifier> mods, String mn, String compiledVersion)
+ *
+ * Set<Modifier> mods = ...
+ * Builder.newRequires(mods, mn, compiledVersion);
+ */
+ void newRequires(Set<Requires.Modifier> mods, String name, String compiledVersion) {
+ int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
+ mv.visitVarInsn(ALOAD, varIndex);
+ mv.visitLdcInsn(name);
+ if (compiledVersion != null) {
+ mv.visitLdcInsn(compiledVersion);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newRequires", REQUIRES_SET_STRING_STRING_SIG, false);
+ } else {
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newRequires", REQUIRES_SET_STRING_SIG, false);
+ }
+ }
+
+ /*
+ * Call Builder::newExports to create Exports instances and
+ * then pass it to the builder by calling:
+ * Builder.exports(Exports[])
+ *
+ */
+ void exports(Set<Exports> exports) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ pushInt(mv, exports.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
+ int arrayIndex = 0;
+ for (Exports export : exports) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex++);
+ newExports(export.modifiers(), export.source(), export.targets());
+ mv.visitInsn(AASTORE);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "exports", EXPORTS_ARRAY_SIG, false);
+ }
+
+ /*
+ * Invoke
+ * Builder.newExports(Set<Exports.Modifier> ms, String pn,
+ * Set<String> targets)
+ * or
+ * Builder.newExports(Set<Exports.Modifier> ms, String pn)
+ *
+ * Set<String> targets = new HashSet<>();
+ * targets.add(t);
+ * :
+ * :
+ *
+ * Set<Modifier> mods = ...
+ * Builder.newExports(mods, pn, targets);
+ */
+ void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
+ int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
+ if (!targets.isEmpty()) {
+ int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+ mv.visitVarInsn(ALOAD, modifiersSetIndex);
+ mv.visitLdcInsn(pn);
+ mv.visitVarInsn(ALOAD, stringSetIndex);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
+ } else {
+ mv.visitVarInsn(ALOAD, modifiersSetIndex);
+ mv.visitLdcInsn(pn);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
+ }
+ }
+
+
+ /**
+ * Call Builder::newOpens to create Opens instances and
+ * then pass it to the builder by calling:
+ * Builder.opens(Opens[])
+ */
+ void opens(Set<Opens> opens) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ pushInt(mv, opens.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
+ int arrayIndex = 0;
+ for (Opens open : opens) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex++);
+ newOpens(open.modifiers(), open.source(), open.targets());
+ mv.visitInsn(AASTORE);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "opens", OPENS_ARRAY_SIG, false);
+ }
+
+ /*
+ * Invoke
+ * Builder.newOpens(Set<Opens.Modifier> ms, String pn,
+ * Set<String> targets)
+ * or
+ * Builder.newOpens(Set<Opens.Modifier> ms, String pn)
+ *
+ * Set<String> targets = new HashSet<>();
+ * targets.add(t);
+ * :
+ * :
+ *
+ * Set<Modifier> mods = ...
+ * Builder.newOpens(mods, pn, targets);
+ */
+ void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
+ int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
+ if (!targets.isEmpty()) {
+ int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+ mv.visitVarInsn(ALOAD, modifiersSetIndex);
+ mv.visitLdcInsn(pn);
+ mv.visitVarInsn(ALOAD, stringSetIndex);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
+ } else {
+ mv.visitVarInsn(ALOAD, modifiersSetIndex);
+ mv.visitLdcInsn(pn);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
+ }
+ }
+
+ /*
+ * Invoke Builder.uses(Set<String> uses)
+ */
+ void uses(Set<String> uses) {
+ int varIndex = dedupSetBuilder.indexOfStringSet(uses);
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ mv.visitVarInsn(ALOAD, varIndex);
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "uses", SET_SIG, false);
+ mv.visitInsn(POP);
+ }
+
+ /*
+ * Call Builder::newProvides to create Provides instances and
+ * then pass it to the builder by calling:
+ * Builder.provides(Provides[] provides)
+ *
+ */
+ void provides(Collection<Provides> provides) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ pushInt(mv, provides.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
+ int arrayIndex = 0;
+ for (Provides provide : provides) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex++);
+ newProvides(provide.service(), provide.providers());
+ mv.visitInsn(AASTORE);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "provides", PROVIDES_ARRAY_SIG, false);
+ }
+
+ /*
+ * Invoke Builder.newProvides(String service, Set<String> providers)
+ *
+ * Set<String> providers = new HashSet<>();
+ * providers.add(impl);
+ * :
+ * :
+ * Builder.newProvides(service, providers);
+ */
+ void newProvides(String service, List<String> providers) {
+ mv.visitLdcInsn(service);
+ pushInt(mv, providers.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+ int arrayIndex = 0;
+ for (String provider : providers) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex++);
+ mv.visitLdcInsn(provider);
+ mv.visitInsn(AASTORE);
+ }
+ mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
+ "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
+ mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+ "newProvides", PROVIDES_STRING_LIST_SIG, false);
+ }
+
+ /*
+ * Invoke Builder.packages(String pn)
+ */
+ void packages(Set<String> packages) {
+ int varIndex = dedupSetBuilder.newStringSet(packages);
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ mv.visitVarInsn(ALOAD, varIndex);
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "packages", SET_SIG, false);
+ mv.visitInsn(POP);
+ }
+
+ /*
+ * Invoke Builder.mainClass(String cn)
+ */
+ void mainClass(String cn) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ mv.visitLdcInsn(cn);
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "mainClass", STRING_SIG, false);
+ mv.visitInsn(POP);
+ }
+
+ /*
+ * Invoke Builder.version(Version v);
+ */
+ void version(Version v) {
+ mv.visitVarInsn(ALOAD, BUILDER_VAR);
+ mv.visitLdcInsn(v.toString());
+ mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+ "version", STRING_SIG, false);
+ mv.visitInsn(POP);
+ }
+ }
+
+ class ModuleHashesBuilder {
+ private static final String MODULE_HASHES_BUILDER =
+ "jdk/internal/module/ModuleHashes$Builder";
+ private static final String MODULE_HASHES_BUILDER_TYPE =
+ "L" + MODULE_HASHES_BUILDER + ";";
+ static final String STRING_BYTE_ARRAY_SIG =
+ "(Ljava/lang/String;[B)" + MODULE_HASHES_BUILDER_TYPE;
+
+ final ModuleHashes recordedHashes;
+ final MethodVisitor hmv;
+ final int index;
+
+ ModuleHashesBuilder(ModuleHashes hashes, int index, MethodVisitor hmv) {
+ this.recordedHashes = hashes;
+ this.hmv = hmv;
+ this.index = index;
+ }
+
+ /**
+ * Build ModuleHashes
+ */
+ void build() {
+ if (recordedHashes == null)
+ return;
+
+ // new jdk.internal.module.ModuleHashes.Builder
+ newModuleHashesBuilder();
+
+ // Invoke ModuleHashes.Builder::hashForModule
+ recordedHashes
+ .names()
+ .forEach(mn -> hashForModule(mn, recordedHashes.hashFor(mn)));
+
+ // Put ModuleHashes into the hashes array
+ pushModuleHashes();
+ }
+
+
+ /*
+ * Create ModuleHashes.Builder instance
+ */
+ void newModuleHashesBuilder() {
+ hmv.visitTypeInsn(NEW, MODULE_HASHES_BUILDER);
+ hmv.visitInsn(DUP);
+ hmv.visitLdcInsn(recordedHashes.algorithm());
+ pushInt(hmv, ((4 * recordedHashes.names().size()) / 3) + 1);
+ hmv.visitMethodInsn(INVOKESPECIAL, MODULE_HASHES_BUILDER,
+ "<init>", "(Ljava/lang/String;I)V", false);
+ hmv.visitVarInsn(ASTORE, BUILDER_VAR);
+ hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+ }
+
+
+ /*
+ * Invoke ModuleHashes.Builder::build and put the returned
+ * ModuleHashes to the hashes array
+ */
+ void pushModuleHashes() {
+ hmv.visitVarInsn(ALOAD, MH_VAR);
+ pushInt(hmv, index);
+ hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+ hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+ "build", "()Ljdk/internal/module/ModuleHashes;",
+ false);
+ hmv.visitInsn(AASTORE);
+ }
+
+ /*
+ * Invoke ModuleHashes.Builder.hashForModule(String name, byte[] hash);
+ */
+ void hashForModule(String name, byte[] hash) {
+ hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+ hmv.visitLdcInsn(name);
+
+ pushInt(hmv, hash.length);
+ hmv.visitIntInsn(NEWARRAY, T_BYTE);
+ for (int i = 0; i < hash.length; i++) {
+ hmv.visitInsn(DUP); // arrayref
+ pushInt(hmv, i);
+ hmv.visitIntInsn(BIPUSH, hash[i]);
+ hmv.visitInsn(BASTORE);
+ }
+
+ hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+ "hashForModule", STRING_BYTE_ARRAY_SIG, false);
+ hmv.visitInsn(POP);
+ }
+ }
+
+ /*
+ * Wraps set creation, ensuring identical sets are properly deduplicated.
+ */
+ class DedupSetBuilder {
+ // map Set<String> to a specialized builder to allow them to be
+ // deduplicated as they are requested
+ final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
+
+ // map Set<Requires.Modifier> to a specialized builder to allow them to be
+ // deduplicated as they are requested
+ final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
+ requiresModifiersSets = new HashMap<>();
+
+ // map Set<Exports.Modifier> to a specialized builder to allow them to be
+ // deduplicated as they are requested
+ final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
+ exportsModifiersSets = new HashMap<>();
+
+ // map Set<Opens.Modifier> to a specialized builder to allow them to be
+ // deduplicated as they are requested
+ final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
+ opensModifiersSets = new HashMap<>();
+
+ private final int stringSetVar;
+ private final int enumSetVar;
+ private final IntSupplier localVarSupplier;
+
+ DedupSetBuilder(IntSupplier localVarSupplier) {
+ this.stringSetVar = localVarSupplier.getAsInt();
+ this.enumSetVar = localVarSupplier.getAsInt();
+ this.localVarSupplier = localVarSupplier;
+ }
+
+ /*
+ * Add the given set of strings to this builder.
+ */
+ void stringSet(Set<String> strings) {
+ stringSets.computeIfAbsent(strings,
+ s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
+ ).increment();
+ }
+
+ /*
+ * Add the given set of Exports.Modifiers
+ */
+ void exportsModifiers(Set<Exports.Modifier> mods) {
+ exportsModifiersSets.computeIfAbsent(mods, s ->
+ new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
+ enumSetVar, localVarSupplier)
+ ).increment();
+ }
+
+ /*
+ * Add the given set of Opens.Modifiers
+ */
+ void opensModifiers(Set<Opens.Modifier> mods) {
+ opensModifiersSets.computeIfAbsent(mods, s ->
+ new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
+ enumSetVar, localVarSupplier)
+ ).increment();
+ }
+
+ /*
+ * Add the given set of Requires.Modifiers
+ */
+ void requiresModifiers(Set<Requires.Modifier> mods) {
+ requiresModifiersSets.computeIfAbsent(mods, s ->
+ new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
+ enumSetVar, localVarSupplier)
+ ).increment();
+ }
+
+ /*
+ * Retrieve the index to the given set of Strings. Emit code to
+ * generate it when SetBuilder::build is called.
+ */
+ int indexOfStringSet(Set<String> names) {
+ return stringSets.get(names).build();
+ }
+
+ /*
+ * Retrieve the index to the given set of Exports.Modifier.
+ * Emit code to generate it when EnumSetBuilder::build is called.
+ */
+ int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
+ return exportsModifiersSets.get(mods).build();
+ }
+
+ /**
+ * Retrieve the index to the given set of Opens.Modifier.
+ * Emit code to generate it when EnumSetBuilder::build is called.
+ */
+ int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
+ return opensModifiersSets.get(mods).build();
+ }
+
+
+ /*
+ * Retrieve the index to the given set of Requires.Modifier.
+ * Emit code to generate it when EnumSetBuilder::build is called.
+ */
+ int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
+ return requiresModifiersSets.get(mods).build();
+ }
+
+ /*
+ * Build a new string set without any attempt to deduplicate it.
+ */
+ int newStringSet(Set<String> names) {
+ int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
+ assert index == stringSetVar;
+ return index;
+ }
+ }
+
+ /*
+ * SetBuilder generates bytecode to create one single instance of Set
+ * for a given set of elements and assign to a local variable slot.
+ * When there is only one single reference to a Set<T>,
+ * it will reuse defaultVarIndex. For a Set with multiple references,
+ * it will use a new local variable retrieved from the nextLocalVar
+ */
+ class SetBuilder<T> {
+ private final Set<T> elements;
+ private final int defaultVarIndex;
+ private final IntSupplier nextLocalVar;
+ private int refCount;
+ private int localVarIndex;
+
+ SetBuilder(Set<T> elements,
+ int defaultVarIndex,
+ IntSupplier nextLocalVar) {
+ this.elements = elements;
+ this.defaultVarIndex = defaultVarIndex;
+ this.nextLocalVar = nextLocalVar;
+ }
+
+ /*
+ * Increments the number of references to this particular set.
+ */
+ final void increment() {
+ refCount++;
+ }
+
+ /**
+ * Generate the appropriate instructions to load an object reference
+ * to the element onto the stack.
+ */
+ void visitElement(T element, MethodVisitor mv) {
+ mv.visitLdcInsn(element);
+ }
+
+ /*
+ * Build bytecode for the Set represented by this builder,
+ * or get the local variable index of a previously generated set
+ * (in the local scope).
+ *
+ * @return local variable index of the generated set.
+ */
+ final int build() {
+ int index = localVarIndex;
+ if (localVarIndex == 0) {
+ // if non-empty and more than one set reference this builder,
+ // emit to a unique local
+ index = refCount <= 1 ? defaultVarIndex
+ : nextLocalVar.getAsInt();
+ if (index < MAX_LOCAL_VARS) {
+ localVarIndex = index;
+ } else {
+ // overflow: disable optimization by using localVarIndex = 0
+ index = defaultVarIndex;
+ }
+
+ generateSetOf(index);
+ }
+ return index;
+ }
+
+ private void generateSetOf(int index) {
+ if (elements.size() <= 10) {
+ // call Set.of(e1, e2, ...)
+ StringBuilder sb = new StringBuilder("(");
+ for (T t : elements) {
+ sb.append("Ljava/lang/Object;");
+ visitElement(t, mv);
+ }
+ sb.append(")Ljava/util/Set;");
+ mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+ "of", sb.toString(), true);
+ } else {
+ // call Set.of(E... elements)
+ pushInt(mv, elements.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+ int arrayIndex = 0;
+ for (T t : elements) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, arrayIndex);
+ visitElement(t, mv); // value
+ mv.visitInsn(AASTORE);
+ arrayIndex++;
+ }
+ mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+ "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
+ }
+ mv.visitVarInsn(ASTORE, index);
+ }
+ }
+
+ /*
+ * Generates bytecode to create one single instance of EnumSet
+ * for a given set of modifiers and assign to a local variable slot.
+ */
+ class EnumSetBuilder<T> extends SetBuilder<T> {
+
+ private final String className;
+
+ EnumSetBuilder(Set<T> modifiers, String className,
+ int defaultVarIndex,
+ IntSupplier nextLocalVar) {
+ super(modifiers, defaultVarIndex, nextLocalVar);
+ this.className = className;
+ }
+
+ /**
+ * Loads an Enum field.
+ */
+ void visitElement(T t, MethodVisitor mv) {
+ mv.visitFieldInsn(GETSTATIC, className, t.toString(),
+ "L" + className + ";");
+ }
+ }
+ }
+}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Mon Dec 19 16:05:38 2016 +0000
@@ -53,6 +53,11 @@
main.opt.output=\
\ --output <path> Location of output path
+main.opt.launcher=\
+\ --launcher <command>=<module> Launcher command name for the module\n\
+\ --launcher <command>=<module>/<main>\n\
+\ Launcher command name for the module and the main class
+
main.command.files=\
\ @<filename> Read options from file
@@ -91,6 +96,9 @@
err.unknown.byte.order:unknown byte order {0}
+err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
+err.launcher.module.name.empty:launcher module name cannot be empty: {0}
+err.launcher.value.format:launcher value should be of form <command>=<module>[/<main-class>]: {0}
err.output.must.be.specified:--output must be specified
err.modulepath.must.be.specified:--module-path must be specified
err.mods.must.be.specified:no modules specified to {0}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Mon Dec 19 16:05:38 2016 +0000
@@ -66,6 +66,7 @@
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -98,10 +99,11 @@
import jdk.internal.joptsimple.OptionSpec;
import jdk.internal.joptsimple.ValueConverter;
import jdk.internal.loader.ResourceHelper;
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
import jdk.tools.jlink.internal.Utils;
import static java.util.stream.Collectors.joining;
@@ -163,6 +165,7 @@
Mode mode;
Path jmodFile;
boolean help;
+ boolean helpExtra;
boolean version;
List<Path> classpath;
List<Path> cmds;
@@ -178,6 +181,7 @@
String osArch;
String osVersion;
Pattern modulesToHash;
+ ModuleResolution moduleResolution;
boolean dryrun;
List<PathMatcher> excludes;
Path extractDir;
@@ -191,7 +195,7 @@
showUsageSummary();
return EXIT_CMDERR;
}
- if (options.help) {
+ if (options.help || options.helpExtra) {
showHelp();
return EXIT_OK;
}
@@ -287,8 +291,8 @@
private boolean describe() throws IOException {
try (JmodFile jf = new JmodFile(options.jmodFile)) {
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
- ModuleDescriptor md = ModuleDescriptor.read(in);
- printModuleDescriptor(md);
+ ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
+ printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
return true;
} catch (IOException e) {
throw new CommandException("err.module.descriptor.not.found");
@@ -302,9 +306,7 @@
.collect(joining(" "));
}
- private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
- private void printModuleDescriptor(ModuleDescriptor md)
+ private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
throws IOException
{
StringBuilder sb = new StringBuilder();
@@ -350,15 +352,24 @@
md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
- JLMA.hashes(md).ifPresent(
- hashes -> hashes.names().stream().sorted().forEach(
- mod -> sb.append("\n hashes ").append(mod).append(" ")
- .append(hashes.algorithm()).append(" ")
- .append(hashes.hashFor(mod))));
+ if (hashes != null) {
+ hashes.names().stream().sorted().forEach(
+ mod -> sb.append("\n hashes ").append(mod).append(" ")
+ .append(hashes.algorithm()).append(" ")
+ .append(toHex(hashes.hashFor(mod))));
+ }
out.println(sb.toString());
}
+ private String toHex(byte[] ba) {
+ StringBuilder sb = new StringBuilder(ba.length);
+ for (byte b: ba) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
private boolean create() throws IOException {
JmodFileWriter jmod = new JmodFileWriter();
@@ -400,6 +411,7 @@
final String osVersion = options.osVersion;
final List<PathMatcher> excludes = options.excludes;
final Hasher hasher = hasher();
+ final ModuleResolution moduleResolution = options.moduleResolution;
JmodFileWriter() { }
@@ -509,6 +521,10 @@
}
}
+ if (moduleResolution != null && moduleResolution.value() != 0) {
+ extender.moduleResolution(moduleResolution);
+ }
+
// write the (possibly extended or modified) module-info.class
out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
}
@@ -537,12 +553,12 @@
}
URI uri = options.jmodFile.toUri();
- ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
+ ModuleReference mref = new ModuleReference(descriptor, uri) {
@Override
- public ModuleReader get() {
+ public ModuleReader open() {
throw new UnsupportedOperationException();
}
- });
+ };
// compose a module finder with the module path and also
// a module finder that can find the jmod file being created
@@ -1139,6 +1155,28 @@
@Override public String valuePattern() { return "module-version"; }
}
+ static class WarnIfResolvedReasonConverter
+ implements ValueConverter<ModuleResolution>
+ {
+ @Override
+ public ModuleResolution convert(String value) {
+ if (value.equals("deprecated"))
+ return ModuleResolution.empty().withDeprecated();
+ else if (value.equals("deprecated-for-removal"))
+ return ModuleResolution.empty().withDeprecatedForRemoval();
+ else if (value.equals("incubating"))
+ return ModuleResolution.empty().withIncubating();
+ else
+ throw new CommandException("err.bad.WarnIfResolvedReason", value);
+ }
+
+ @Override public Class<ModuleResolution> valueType() {
+ return ModuleResolution.class;
+ }
+
+ @Override public String valuePattern() { return "reason"; }
+ }
+
static class PatternConverter implements ValueConverter<Pattern> {
@Override
public Pattern convert(String value) {
@@ -1182,12 +1220,24 @@
*/
private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
- private JmodHelpFormatter() { super(80, 2); }
+ private final Options opts;
+
+ private JmodHelpFormatter(Options opts) {
+ super(80, 2);
+ this.opts = opts;
+ }
@Override
public String format(Map<String, ? extends OptionDescriptor> options) {
- Map<String, OptionDescriptor> all = new HashMap<>();
+ Map<String, OptionDescriptor> all = new LinkedHashMap<>();
all.putAll(options);
+
+ // extra options
+ if (!opts.helpExtra) {
+ all.remove("do-not-resolve-by-default");
+ all.remove("warn-if-resolved");
+ }
+
all.put(CMD_FILENAME, new OptionDescriptor() {
@Override
public Collection<String> options() {
@@ -1243,7 +1293,8 @@
private final OptionParser parser = new OptionParser("hp");
private void handleOptions(String[] args) {
- parser.formatHelpWith(new JmodHelpFormatter());
+ options = new Options();
+ parser.formatHelpWith(new JmodHelpFormatter(options));
OptionSpec<Path> classPath
= parser.accepts("class-path", getMessage("main.opt.class-path"))
@@ -1285,6 +1336,9 @@
= parser.acceptsAll(Set.of("h", "help"), getMessage("main.opt.help"))
.forHelp();
+ OptionSpec<Void> helpExtra
+ = parser.accepts("help-extra", getMessage("main.opt.help-extra"));
+
OptionSpec<Path> headerFiles
= parser.accepts("header-files", getMessage("main.opt.header-files"))
.withRequiredArg()
@@ -1342,6 +1396,15 @@
.withRequiredArg()
.describedAs(getMessage("main.opt.os-version.arg"));
+ OptionSpec<Void> doNotResolveByDefault
+ = parser.accepts("do-not-resolve-by-default",
+ getMessage("main.opt.do-not-resolve-by-default"));
+
+ OptionSpec<ModuleResolution> warnIfResolved
+ = parser.accepts("warn-if-resolved", getMessage("main.opt.warn-if-resolved"))
+ .withRequiredArg()
+ .withValuesConvertedBy(new WarnIfResolvedReasonConverter());
+
OptionSpec<Void> version
= parser.accepts("version", getMessage("main.opt.version"));
@@ -1351,9 +1414,9 @@
try {
OptionSet opts = parser.parse(args);
- if (opts.has(help) || opts.has(version)) {
- options = new Options();
+ if (opts.has(help) || opts.has(helpExtra) || opts.has(version)) {
options.help = opts.has(help);
+ options.helpExtra = opts.has(helpExtra);
options.version = opts.has(version);
return; // informational message will be shown
}
@@ -1362,7 +1425,6 @@
if (words.isEmpty())
throw new CommandException("err.missing.mode").showUsage(true);
String verb = words.get(0);
- options = new Options();
try {
options.mode = Enum.valueOf(Mode.class, verb.toUpperCase());
} catch (IllegalArgumentException e) {
@@ -1391,7 +1453,7 @@
options.legalNotices = opts.valuesOf(legalNotices);
if (opts.has(modulePath)) {
Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
- options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs);
+ options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
}
if (opts.has(moduleVersion))
options.moduleVersion = opts.valueOf(moduleVersion);
@@ -1403,6 +1465,13 @@
options.osArch = opts.valueOf(osArch);
if (opts.has(osVersion))
options.osVersion = opts.valueOf(osVersion);
+ if (opts.has(warnIfResolved))
+ options.moduleResolution = opts.valueOf(warnIfResolved);
+ if (opts.has(doNotResolveByDefault)) {
+ if (options.moduleResolution == null)
+ options.moduleResolution = ModuleResolution.empty();
+ options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault();
+ }
if (opts.has(hashModules)) {
options.modulesToHash = opts.valueOf(hashModules);
// if storing hashes then the module path is required
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties Mon Dec 19 16:05:38 2016 +0000
@@ -47,6 +47,7 @@
\hash - Records hashes of tied modules.
main.opt.help=Print this usage message
+main.opt.help-extra=Print help on extra options
main.opt.version=Version information
main.opt.class-path=Application jar files|dir containing classes
main.opt.libs=Location of native libraries
@@ -74,6 +75,9 @@
\ with modules matching the given <regex-pattern> and depending upon it directly\
\ or indirectly. The hashes are recorded in the JMOD file being created, or\
\ a JMOD file or modular JAR on the module path specified the jmod hash command.
+main.opt.do-not-resolve-by-default=Exclude from the default root set of modules
+main.opt.warn-if-resolved=Hint for a tool to issue a warning if the module \
+is resolved. One of deprecated, deprecated-for-removal, or incubating
main.opt.cmdfile=Read options from the specified file
@@ -96,6 +100,8 @@
err.file.already.exists=file already exists: {0}
err.jmod.not.found=no jmod file found: {0}
err.bad.pattern=bad pattern {0}
+err.bad.WarnIfResolvedReason=bad reason: {0}, must be one of deprecated,\
+\ deprecated-for-removal, or incubating
err.unknown.option=unknown option(s): {0}
err.missing.arg=no value given for {0}
err.internal.error=internal error: {0} {1} {2}
--- a/jdk/src/jdk.jlink/share/classes/module-info.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java Mon Dec 19 16:05:38 2016 +0000
@@ -41,7 +41,7 @@
jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
jdk.tools.jlink.internal.plugins.LegalNoticeFilePlugin,
- jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
+ jdk.tools.jlink.internal.plugins.SystemModulesPlugin,
jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
--- a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java Mon Dec 19 16:05:38 2016 +0000
@@ -27,8 +27,10 @@
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.misc.VM;
+import jdk.internal.ref.Cleaner;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
+import sun.nio.ch.DirectBuffer;
import java.lang.reflect.Field;
import java.security.ProtectionDomain;
@@ -1228,4 +1230,28 @@
public void fullFence() {
theInternalUnsafe.fullFence();
}
+
+ /**
+ * Invokes the given direct byte buffer's cleaner, if any.
+ *
+ * @param directBuffer a direct byte buffer
+ * @throws NullPointerException if {@code directBuffer} is null
+ * @throws IllegalArgumentException if {@code directBuffer} is non-direct,
+ * or is a {@link java.nio.Buffer#slice slice}, or is a
+ * {@link java.nio.Buffer#duplicate duplicate}
+ * @since 9
+ */
+ public void invokeCleaner(java.nio.ByteBuffer directBuffer) {
+ if (!directBuffer.isDirect())
+ throw new IllegalArgumentException("buffer is non-direct");
+
+ DirectBuffer db = (DirectBuffer)directBuffer;
+ if (db.attachment() != null)
+ throw new IllegalArgumentException("duplicate or slice");
+
+ Cleaner cleaner = db.cleaner();
+ if (cleaner != null) {
+ cleaner.clean();
+ }
+ }
}
--- a/jdk/test/ProblemList.txt Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/ProblemList.txt Mon Dec 19 16:05:38 2016 +0000
@@ -205,6 +205,8 @@
java/rmi/transport/dgcDeadLock/DGCDeadLock.java 8029360 macosx-all
+java/rmi/registry/readTest/readTest.sh 7146543 generic-all
+
############################################################################
# jdk_security
@@ -217,6 +219,10 @@
sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java 8161232 macosx-all
+sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java 8171043 windows-all
+
+javax/net/ssl/DTLS/PacketLossRetransmission.java 8169086 macosx-x64
+
############################################################################
# jdk_sound
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8169589
+ * @summary Activating a dialog puts to back another dialog owned by the same frame
+ * @author Dmitry Markov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main DialogAboveFrameTest
+ */
+
+import java.awt.Color;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+
+import test.java.awt.regtesthelpers.Util;
+
+public class DialogAboveFrameTest {
+ public static void main(String[] args) {
+ Robot robot = Util.createRobot();
+
+ Frame frame = new Frame("Frame");
+ frame.setBackground(Color.BLUE);
+ frame.setBounds(200, 50, 300, 300);
+ frame.setVisible(true);
+
+ Dialog dialog1 = new Dialog(frame, "Dialog 1", false);
+ dialog1.setBackground(Color.RED);
+ dialog1.setBounds(100, 100, 200, 200);
+ dialog1.setVisible(true);
+
+ Dialog dialog2 = new Dialog(frame, "Dialog 2", false);
+ dialog2.setBackground(Color.GREEN);
+ dialog2.setBounds(400, 100, 200, 200);
+ dialog2.setVisible(true);
+
+ Util.waitForIdle(robot);
+
+ Util.clickOnComp(dialog2, robot);
+ Util.waitForIdle(robot);
+
+ Point point = dialog1.getLocationOnScreen();
+ int x = point.x + (int)(dialog1.getWidth() * 0.9);
+ int y = point.y + (int)(dialog1.getHeight() * 0.9);
+
+ try {
+ if (!robot.getPixelColor(x, y).equals(dialog1.getBackground())) {
+ throw new RuntimeException("Test FAILED: Dialog is behind the frame");
+ }
+ } finally {
+ frame.dispose();
+ dialog1.dispose();
+ dialog2.dispose();
+ }
+ }
+}
+
--- a/jdk/test/java/awt/JAWT/Makefile.unix Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/JAWT/Makefile.unix Mon Dec 19 16:05:38 2016 +0000
@@ -1,4 +1,4 @@
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 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
@@ -32,7 +32,7 @@
J_INC = $(TESTJAVA)/include
INCLUDES = -I$(J_INC) -I$(J_INC)/$(SYST) -I.
-LIBS = -L$(TESTJAVA)/lib/$(ARCH) -ljawt -lX11
+LIBS = -L$(TESTJAVA)/lib -ljawt -lX11
all: $(CLASSES) libmylib.so
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Menu/WrongParentAfterRemoveMenu/WrongParentAfterRemoveMenu.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.PopupMenu;
+import java.awt.Window;
+
+/**
+ * @test
+ * @bug 8165769
+ * @key headful
+ */
+public final class WrongParentAfterRemoveMenu {
+
+ public static void main(final String[] args) {
+ testMenuBar();
+ testComponent();
+ testFrame();
+ }
+
+ private static void testFrame() {
+ // peer exists
+ Frame frame = new Frame();
+ try {
+ frame.pack();
+ PopupMenu popupMenu = new PopupMenu();
+ frame.add(popupMenu);
+ checkParent(popupMenu, frame);
+ frame.remove(popupMenu);
+ checkParent(popupMenu, null);
+ } finally {
+ frame.dispose();
+ }
+ // peer is null
+ frame = new Frame();
+ PopupMenu popupMenu = new PopupMenu();
+ frame.add(popupMenu);
+ checkParent(popupMenu, frame);
+ frame.remove(popupMenu);
+ checkParent(popupMenu, null);
+ }
+
+ private static void testComponent() {
+ // peer exists
+ Window w = new Window(null);
+ try {
+ w.pack();
+ PopupMenu popupMenu = new PopupMenu();
+ w.add(popupMenu);
+ checkParent(popupMenu, w);
+ w.remove(popupMenu);
+ checkParent(popupMenu, null);
+ } finally {
+ w.dispose();
+ }
+ // peer is null
+ w = new Window(null);
+ PopupMenu popupMenu = new PopupMenu();
+ w.add(popupMenu);
+ checkParent(popupMenu, w);
+ w.remove(popupMenu);
+ checkParent(popupMenu, null);
+ }
+
+ private static void testMenuBar() {
+ // peer exists
+ MenuBar mb = new MenuBar();
+ try {
+ mb.addNotify();
+ Menu m1 = new Menu();
+ Menu m2 = new Menu();
+ m1.add(m2);
+ mb.add(m1);
+ checkParent(m1, mb);
+ checkParent(m2, m1);
+ m1.remove(m2);
+ checkParent(m2, null);
+ mb.remove(m1);
+ checkParent(m1, null);
+ } finally {
+ mb.removeNotify();
+ }
+ // peer is null
+ mb = new MenuBar();
+ Menu m1 = new Menu();
+ Menu m2 = new Menu();
+ m1.add(m2);
+ mb.add(m1);
+ checkParent(m1, mb);
+ checkParent(m2, m1);
+ m1.remove(m2);
+ checkParent(m2, null);
+ mb.remove(m1);
+ checkParent(m1, null);
+ }
+
+ private static void checkParent(final Menu menu, final Object parent) {
+ if (menu.getParent() != parent) {
+ System.err.println("Expected: " + parent);
+ System.err.println("Actual: " + menu.getParent());
+ throw new RuntimeException("Wrong parent");
+ }
+ }
+}
--- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -44,9 +44,11 @@
import javax.imageio.ImageIO;
/**
- * @test @bug 8145174 8151787
+ * @test
+ * @bug 8145174 8151787 8168657
* @summary HiDPI splash screen support on Linux
* @modules java.desktop/sun.java2d
+ * @requires (os.family == "linux")
* @run main UnixMultiResolutionSplashTest
*/
public class UnixMultiResolutionSplashTest {
--- a/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java Mon Dec 19 16:05:38 2016 +0000
@@ -25,6 +25,7 @@
test
@bug 6242241
@summary Tests basic DnD functionality in an applet
+ @requires (os.family == "windows")
@author Your Name: Alexey Utkin area=dnd
@run applet/manual=yesno DnDFileGroupDescriptor.html
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/Fallback/SurrogatesFallbackTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 JetBrains s.r.o.
+ * 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
+ * @bug 8169202
+ * @summary verify font fallback for surrogate pairs on macOS
+ * @requires os.family == "mac"
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+import java.awt.image.BufferedImage;
+import java.util.function.Consumer;
+
+public class SurrogatesFallbackTest {
+ private static final int CHARACTER = 0x1d400; // MATHEMATICAL BOLD CAPITAL A
+ private static final Font FONT = new Font("Menlo", // expected to fallback to STIXGeneral for the character above
+ Font.PLAIN,
+ 12);
+ private static final int IMAGE_WIDTH = 20;
+ private static final int IMAGE_HEIGHT = 20;
+ private static final int GLYPH_X = 5;
+ private static final int GLYPH_Y = 15;
+
+ public static void main(String[] args) {
+ BufferedImage noGlyph = createImage(g -> {});
+ BufferedImage missingGlyph = createImage(g -> {
+ GlyphVector gv = FONT.createGlyphVector(g.getFontRenderContext(), new int[]{FONT.getMissingGlyphCode()});
+ g.drawGlyphVector(gv, GLYPH_X, GLYPH_Y);
+ });
+ BufferedImage surrogateCharGlyph = createImage(g -> {
+ g.setFont(FONT);
+ g.drawString(new String(Character.toChars(CHARACTER)), GLYPH_X, GLYPH_Y);
+ });
+
+ if (imagesAreEqual(surrogateCharGlyph, noGlyph)) {
+ throw new RuntimeException("Character was not rendered");
+ }
+ if (imagesAreEqual(surrogateCharGlyph, missingGlyph)) {
+ throw new RuntimeException("Character is rendered as missing");
+ }
+ }
+
+ private static BufferedImage createImage(Consumer<Graphics2D> drawing) {
+ BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g = image.createGraphics();
+ g.setColor(Color.white);
+ g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+ g.setColor(Color.black);
+ drawing.accept(g);
+ g.dispose();
+ return image;
+ }
+
+ private static boolean imagesAreEqual(BufferedImage i1, BufferedImage i2) {
+ if (i1.getWidth() != i2.getWidth() || i1.getHeight() != i2.getHeight()) return false;
+ for (int i = 0; i < i1.getWidth(); i++) {
+ for (int j = 0; j < i1.getHeight(); j++) {
+ if (i1.getRGB(i, j) != i2.getRGB(i, j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/TextLayout/ArabicDiacriticTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,95 @@
+/*
+ * 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
+ */
+
+/* @test
+ * @summary verify Arab Diacritic Positioning
+ * @bug 8168759
+ */
+
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.util.Locale;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class ArabicDiacriticTest {
+
+ static final String SAMPLE =
+ "\u0627\u0644\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629";
+
+ static final String STR1 = "\u0644\u0639\u064e\u0629";
+ static final String STR2 = "\u0644\u0639\u0629";
+
+ static JFrame frame;
+ static final String FONT = "DejaVu Sans";
+
+ public static void main(String args[]) throws Exception {
+ showText(); // for a human
+ measureText(); // for the test harness
+ Thread.sleep(5000);
+ frame.dispose();
+ }
+
+ static void showText() {
+ SwingUtilities.invokeLater(() -> {
+ frame = new JFrame();
+ JLabel label = new JLabel(SAMPLE);
+ Font font = new Font(FONT, Font.PLAIN, 36);
+ label.setFont(font);
+ frame.setLayout(new GridLayout(3,1));
+ frame.add(label);
+ label = new JLabel(STR1);
+ label.setFont(font);
+ frame.add(label);
+ label = new JLabel(STR2);
+ label.setFont(font);
+ frame.add(label);
+ frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ });
+ }
+
+ static void measureText() {
+ Font font = new Font(FONT, Font.PLAIN, 36);
+ if (!font.getFamily(Locale.ENGLISH).equals(FONT)) {
+ return;
+ }
+ FontRenderContext frc = new FontRenderContext(null, false, false);
+ TextLayout tl1 = new TextLayout(STR1, font, frc);
+ TextLayout tl2 = new TextLayout(STR2, font, frc);
+ Rectangle r1 = tl1.getPixelBounds(frc, 0f, 0f);
+ Rectangle r2 = tl2.getPixelBounds(frc, 0f, 0f);
+ if (r1.height > r2.height) {
+ System.out.println(font);
+ System.out.println(r1);
+ System.out.println(r2);
+ throw new RuntimeException("BAD BOUNDS");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/StrictMath/ExpTests.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * 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
+ * @bug 8139688
+ * @key randomness
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.RandomFactory
+ * @build Tests
+ * @build FdlibmTranslit
+ * @build ExpTests
+ * @run main ExpTests
+ * @summary Tests specifically for StrictMath.exp
+ */
+
+import jdk.testlibrary.RandomFactory;
+
+/**
+ * The role of this test is to verify that the FDLIBM exp algorithm is
+ * being used by running golden file style tests on values that may
+ * vary from one conforming exponential implementation to another.
+ */
+
+public class ExpTests {
+ private ExpTests(){}
+
+ public static void main(String [] argv) {
+ int failures = 0;
+
+ failures += testExp();
+ failures += testAgainstTranslit();
+
+ if (failures > 0) {
+ System.err.println("Testing the exponential incurred "
+ + failures + " failures.");
+ throw new RuntimeException();
+ }
+ }
+
+ // From the fdlibm source, the overflow threshold in hex is:
+ // 0x4086_2E42_FEFA_39EF.
+ static final double EXP_OVERFLOW_THRESH = Double.longBitsToDouble(0x4086_2E42_FEFA_39EFL);
+
+ // From the fdlibm source, the underflow threshold in hex is:
+ // 0xc087_4910_D52D_3051L.
+ static final double EXP_UNDERFLOW_THRESH = Double.longBitsToDouble(0xc087_4910_D52D_3051L);
+
+ static int testExp() {
+ int failures = 0;
+
+ double [][] testCases = {
+ // Some of these could be moved to common Math/StrictMath exp testing.
+ {Double.NaN, Double.NaN},
+ {Double.MAX_VALUE, Double.POSITIVE_INFINITY},
+ {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
+ {Double.NEGATIVE_INFINITY, +0.0},
+ {EXP_OVERFLOW_THRESH, 0x1.ffff_ffff_fff2ap1023},
+ {Math.nextUp(EXP_OVERFLOW_THRESH), Double.POSITIVE_INFINITY},
+ {Math.nextDown(EXP_UNDERFLOW_THRESH), +0.0},
+ {EXP_UNDERFLOW_THRESH, +Double.MIN_VALUE},
+ };
+
+ for(double[] testCase: testCases)
+ failures+=testExpCase(testCase[0], testCase[1]);
+
+ return failures;
+ }
+
+ static int testExpCase(double input, double expected) {
+ int failures = 0;
+
+ failures+=Tests.test("StrictMath.exp(double)", input,
+ StrictMath.exp(input), expected);
+ return failures;
+ }
+
+ // Initialize shared random number generator
+ private static java.util.Random random = RandomFactory.getRandom();
+
+ /**
+ * Test StrictMath.exp against transliteration port of exp.
+ */
+ private static int testAgainstTranslit() {
+ int failures = 0;
+
+ double[] decisionPoints = {
+ // Near overflow threshold
+ EXP_OVERFLOW_THRESH - 512*Math.ulp(EXP_OVERFLOW_THRESH),
+
+ // Near underflow threshold
+ EXP_UNDERFLOW_THRESH - 512*Math.ulp(EXP_UNDERFLOW_THRESH),
+
+ // Straddle algorithm conditional checks
+ Double.longBitsToDouble(0x4086_2E42_0000_0000L - 512L),
+ Double.longBitsToDouble(0x3fd6_2e42_0000_0000L - 512L),
+ Double.longBitsToDouble(0x3FF0_A2B2_0000_0000L - 512L),
+ Double.longBitsToDouble(0x3e30_0000_0000_0000L - 512L),
+
+ // Other notable points
+ Double.MIN_NORMAL - Math.ulp(Double.MIN_NORMAL)*512,
+ -Double.MIN_VALUE*512,
+ };
+
+ for (double decisionPoint : decisionPoints) {
+ double ulp = Math.ulp(decisionPoint);
+ failures += testRange(decisionPoint - 1024*ulp, ulp, 1_024);
+ }
+
+ // Try out some random values
+ for (int i = 0; i < 100; i++) {
+ double x = Tests.createRandomDouble(random);
+ failures += testRange(x, Math.ulp(x), 100);
+ }
+
+ return failures;
+ }
+
+ private static int testRange(double start, double increment, int count) {
+ int failures = 0;
+ double x = start;
+ for (int i = 0; i < count; i++, x += increment) {
+ failures += testExpCase(x, FdlibmTranslit.Exp.compute(x));
+ }
+ return failures;
+ }
+}
--- a/jdk/test/java/lang/StrictMath/FdlibmTranslit.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/StrictMath/FdlibmTranslit.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -48,7 +48,8 @@
*/
private static double __LO(double x, int low) {
long transX = Double.doubleToRawLongBits(x);
- return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+ return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+ (low & 0x0000_0000_FFFF_FFFFL));
}
/**
@@ -65,7 +66,8 @@
*/
private static double __HI(double x, int high) {
long transX = Double.doubleToRawLongBits(x);
- return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+ return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+ ( ((long)high)) << 32 );
}
public static double hypot(double x, double y) {
@@ -250,4 +252,136 @@
return w;
}
}
+
+ /**
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Reme algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+ static class Exp {
+ private static final double one = 1.0;
+ private static final double[] halF = {0.5,-0.5,};
+ private static final double huge = 1.0e+300;
+ private static final double twom1000= 9.33263618503218878990e-302; /* 2**-1000=0x01700000,0*/
+ private static final double o_threshold= 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */
+ private static final double u_threshold= -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */
+ private static final double[] ln2HI ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01}; /* 0xbfe62e42, 0xfee00000 */
+ private static final double[] ln2LO ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,}; /* 0xbdea39ef, 0x35793c76 */
+ private static final double invln2 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */
+ private static final double P1 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */
+ private static final double P2 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */
+ private static final double P3 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */
+ private static final double P4 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */
+ private static final double P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+ public static strictfp double compute(double x) {
+ double y,hi=0,lo=0,c,t;
+ int k=0,xsb;
+ /*unsigned*/ int hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|__LO(x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = (int)(invln2*x+halF[xsb]);
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ y = __HI(y, __HI(y) + (k<<20)); /* add k to y's exponent */
+ return y;
+ } else {
+ y = __HI(y, __HI(y) + ((k+1000)<<20));/* add k to y's exponent */
+ return y*twom1000;
+ }
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/DropLookupModeTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @run testng DropLookupModeTest
+ * @summary Basic unit tests Lookup::dropLookupMode
+ */
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class DropLookupModeTest {
+
+ /**
+ * Basic test of dropLookupMode
+ */
+ public void testBasic() {
+ final Lookup fullPowerLookup = MethodHandles.lookup();
+ final Class<?> lc = fullPowerLookup.lookupClass();
+ assertTrue(fullPowerLookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+ Lookup lookup = fullPowerLookup.dropLookupMode(PRIVATE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+ lookup = fullPowerLookup.dropLookupMode(PROTECTED);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+ lookup = fullPowerLookup.dropLookupMode(PACKAGE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+ lookup = fullPowerLookup.dropLookupMode(MODULE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC));
+
+ lookup = fullPowerLookup.dropLookupMode(PUBLIC);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == 0);
+ }
+
+ /**
+ * Starting with a full power Lookup, use dropLookupMode to create new Lookups
+ * with reduced access.
+ */
+ public void testReducingAccess() {
+ Lookup lookup = MethodHandles.lookup();
+ final Class<?> lc = lookup.lookupClass();
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+ lookup = lookup.dropLookupMode(PROTECTED);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+ lookup = lookup.dropLookupMode(PRIVATE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+ lookup = lookup.dropLookupMode(PACKAGE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+ lookup = lookup.dropLookupMode(MODULE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == PUBLIC);
+
+ lookup = lookup.dropLookupMode(PUBLIC);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == 0);
+
+ // repeat with lookup has no access
+ lookup = lookup.dropLookupMode(PUBLIC);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == 0);
+ }
+
+ /**
+ * Test dropLookupMode on the public Lookup.
+ */
+ public void testPublicLookup() {
+ final Lookup publicLookup = MethodHandles.publicLookup();
+ final Class<?> lc = publicLookup.lookupClass();
+ assertTrue(publicLookup.lookupModes() == PUBLIC);
+
+ Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == PUBLIC);
+
+ lookup = publicLookup.dropLookupMode(PROTECTED);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == PUBLIC);
+
+ lookup = publicLookup.dropLookupMode(PACKAGE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == PUBLIC);
+
+ lookup = publicLookup.dropLookupMode(MODULE);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == PUBLIC);
+
+ lookup = publicLookup.dropLookupMode(PUBLIC);
+ assertTrue(lookup.lookupClass() == lc);
+ assertTrue(lookup.lookupModes() == 0);
+ }
+
+ @DataProvider(name = "badInput")
+ public Object[][] badInput() {
+ return new Object[][] {
+ { 0, null },
+ { (PACKAGE|PRIVATE), null }, // two modes
+ { Integer.MAX_VALUE, null },
+ { Integer.MIN_VALUE, null },
+ };
+ }
+
+ /**
+ * Check that IllegalArgumentException is thrown for bad input
+ */
+ @Test(dataProvider = "badInput", expectedExceptions = {IllegalArgumentException.class})
+ public void testBadInput(Integer modeToDrop, Object ignore) {
+ MethodHandles.lookup().dropLookupMode(modeToDrop);
+ }
+
+}
\ No newline at end of file
--- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Mon Dec 19 16:05:38 2016 +0000
@@ -84,8 +84,7 @@
// Invoke MethodHandles.privateLookupIn with a reduced-power caller
public void testReducedAccessCallerSameModule() throws Throwable {
- // drop access
- Lookup caller = MethodHandles.lookup().in(publicType);
+ Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
assertTrue((caller.lookupModes() & PRIVATE) == 0);
assertTrue((caller.lookupModes() & PACKAGE) == 0);
assertTrue((caller.lookupModes() & MODULE) != 0);
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -23,8 +23,7 @@
/**
* @test
- * @modules java.base/java.lang.module:open
- * java.base/jdk.internal.module
+ * @modules java.base/jdk.internal.module
* @run testng ModuleDescriptorTest
* @summary Basic test for java.lang.module.ModuleDescriptor and its builder
*/
@@ -41,16 +40,13 @@
import java.lang.module.ModuleDescriptor.Provides;
import java.lang.module.ModuleDescriptor.Requires.Modifier;
import java.lang.module.ModuleDescriptor.Version;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Module;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
@@ -66,10 +62,20 @@
public Object[][] invalidJavaIdentifiers() {
return new Object[][]{
- { null, null },
- { ".foo", null },
- { "foo.", null },
- { "[foo]", null },
+ { null, null },
+ { "1", null },
+ { "1foo", null },
+ { ".foo", null },
+ { "foo.", null },
+ { "[foo]", null },
+ { "foo.1", null },
+ { "1foo.bar", null },
+ { "foo.1bar", null },
+ { "foo.[bar]", null },
+ { "foo..bar", null },
+ { "foo.bar.1", null },
+ { "foo.bar.1gus", null },
+ { "foo.bar.[gus]", null },
};
}
@@ -86,6 +92,15 @@
.next();
}
+ private Requires requires(Set<Modifier> mods, String mn, Version v) {
+ return ModuleDescriptor.module("m")
+ .requires(mods, mn, v)
+ .build()
+ .requires()
+ .iterator()
+ .next();
+ }
+
private Requires requires(String mn) {
return requires(Collections.emptySet(), mn);
}
@@ -103,6 +118,7 @@
assertTrue(r.compareTo(r) == 0);
assertTrue(r.modifiers().isEmpty());
assertEquals(r.name(), "foo");
+ assertFalse(r.compiledVersion().isPresent());
}
public void testRequiresWithOneModifier() {
@@ -111,6 +127,7 @@
assertTrue(r.compareTo(r) == 0);
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
assertEquals(r.name(), "foo");
+ assertFalse(r.compiledVersion().isPresent());
}
public void testRequiresWithTwoModifiers() {
@@ -119,6 +136,7 @@
assertTrue(r.compareTo(r) == 0);
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
assertEquals(r.name(), "foo");
+ assertFalse(r.compiledVersion().isPresent());
}
public void testRequiresWithAllModifiers() {
@@ -127,6 +145,18 @@
assertTrue(r.compareTo(r) == 0);
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
assertEquals(r.name(), "foo");
+ assertFalse(r.compiledVersion().isPresent());
+ }
+
+ public void testRequiresWithCompiledVersion() {
+ Version v = Version.parse("1.0");
+ Requires r = requires(Set.of(), "foo", v);
+ assertEquals(r, r);
+ assertTrue(r.compareTo(r) == 0);
+ assertEquals(r.modifiers(), Set.of());
+ assertEquals(r.name(), "foo");
+ assertTrue(r.compiledVersion().isPresent());
+ assertEquals(r.compiledVersion().get().toString(), "1.0");
}
@Test(expectedExceptions = IllegalStateException.class)
@@ -167,6 +197,16 @@
ModuleDescriptor.module("m").requires((Requires) null);
}
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testRequiresWithNullModifiers() {
+ ModuleDescriptor.module("m").requires(null, "foo");
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testRequiresWithNullVersion() {
+ ModuleDescriptor.module("m").requires(Set.of(), "foo", null);
+ }
+
public void testRequiresCompare() {
Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo");
Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar");
@@ -190,6 +230,20 @@
assertTrue(r2.compareTo(r1) == 0);
}
+ public void testRequiresCompareWithSameCompiledVersion() {
+ Requires r1 = requires(Set.of(), "foo", Version.parse("2.0"));
+ Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+ assertTrue(r1.compareTo(r2) == 0);
+ assertTrue(r2.compareTo(r1) == 0);
+ }
+
+ public void testRequiresCompareWithDifferentCompiledVersion() {
+ Requires r1 = requires(Set.of(), "foo", Version.parse("1.0"));
+ Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+ assertTrue(r1.compareTo(r2) < 0);
+ assertTrue(r2.compareTo(r1) > 0);
+ }
+
public void testRequiresEqualsAndHashCode() {
Requires r1 = requires("foo");
Requires r2 = requires("foo");
@@ -208,6 +262,17 @@
r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
r2 = requires(Set.of(), "foo");
assertNotEquals(r1, r2);
+
+ Version v1 = Version.parse("1.0");
+ r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+ r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+ assertEquals(r1, r2);
+ assertTrue(r1.hashCode() == r2.hashCode());
+
+ Version v2 = Version.parse("2.0");
+ r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+ r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v2);
+ assertNotEquals(r1, r2);
}
public void testRequiresToString() {
@@ -938,7 +1003,7 @@
};
// basic test reading module-info.class
- public void testRead1() throws Exception {
+ public void testRead() throws Exception {
Module base = Object.class.getModule();
try (InputStream in = base.getResourceAsStream("module-info.class")) {
@@ -954,45 +1019,6 @@
assertEquals(descriptor.name(), "java.base");
}
}
-
- /**
- * Test reading a module-info.class that has a module name, requires,
- * and qualified exports with module names that are not supported in the
- * Java Language.
- */
- public void testRead2() throws Exception {
- // use non-public constructor to create a Builder that is not strict
- Constructor<?> ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class);
- ctor.setAccessible(true);
-
- Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false);
- ModuleDescriptor descriptor = builder
- .requires("java.base")
- .requires("-m1")
- .exports("p", Set.of("m2-"))
- .build();
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ModuleInfoWriter.write(descriptor, baos);
- ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
-
- descriptor = ModuleDescriptor.read(bb);
- assertEquals(descriptor.name(), "m?1");
-
- Set<String> requires = descriptor.requires()
- .stream()
- .map(Requires::name)
- .collect(Collectors.toSet());
- assertTrue(requires.size() == 2);
- assertTrue(requires.contains("java.base"));
- assertTrue(requires.contains("-m1"));
-
- assertTrue(descriptor.exports().size() == 1);
- Exports e = descriptor.exports().iterator().next();
- assertTrue(e.targets().size() == 1);
- assertTrue(e.targets().contains("m2-"));
- }
-
/**
* Test ModuleDescriptor with a packager finder
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/module/ModuleNamesTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.misc
+ * java.base/jdk.internal.module
+ * @run testng ModuleNamesTest
+ * @summary Basic test of reading a module-info.class with module names that
+ * are legal in class files but not legal in the Java Language
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleInfoWriter;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleNamesTest {
+
+ @DataProvider(name = "legalModuleNames")
+ public Object[][] legalModuleNames() {
+ return new Object[][] {
+
+ { ".", "." },
+ { ".foo", ".foo" },
+ { "foo.", "foo." },
+ { "foo.bar", "foo.bar" },
+
+ { "..", ".." },
+ { "..foo", "..foo" },
+ { "foo..", "foo.." },
+ { "foo..bar", "foo..bar" },
+
+ { "[", "[" },
+ { "[foo", "[foo" },
+ { "foo[", "foo[" },
+ { "foo[bar", "foo[bar" },
+
+ { ";", ";" },
+ { ";foo", ";foo" },
+ { "foo;", "foo;" },
+ { "foo;bar", "foo;bar" },
+
+ { "\\\\", "\\" },
+ { "\\\\foo", "\\foo" },
+ { "foo\\\\", "foo\\" },
+ { "foo\\\\bar", "foo\\bar" },
+
+ { "\\\\\\\\", "\\\\" },
+ { "\\\\\\\\foo", "\\\\foo" },
+ { "foo\\\\\\\\", "foo\\\\" },
+ { "foo\\\\\\\\bar", "foo\\\\bar" },
+
+ { "\\:", ":" },
+ { "\\:foo", ":foo" },
+ { "foo\\:", "foo:" },
+ { "foo\\:bar", "foo:bar" },
+
+ { "\\:\\:", "::" },
+ { "\\:\\:foo", "::foo" },
+ { "foo\\:\\:", "foo::" },
+ { "foo\\:\\:bar", "foo::bar" },
+
+ { "\\@", "@" },
+ { "\\@foo", "@foo" },
+ { "foo\\@", "foo@" },
+ { "foo\\@bar", "foo@bar" },
+
+ { "\\@\\@", "@@" },
+ { "\\@\\@foo", "@@foo" },
+ { "foo\\@\\@", "foo@@" },
+ { "foo\\@\\@bar", "foo@@bar" },
+
+ { makeString("", 0x20, ""), " " },
+ { makeString("foo", 0x20, ""), "foo " },
+ { makeString("", 0x20, "foo"), " foo" },
+ { makeString("foo", 0x20, "bar"), "foo bar" },
+ };
+ }
+
+ @DataProvider(name = "illegalModuleNames")
+ public Object[][] illegalModuleNames() {
+ return new Object[][] {
+
+ { "", null },
+
+ { ":", null },
+ { ":foo", null },
+ { "foo:", null },
+ { "foo:bar", null },
+
+ { "@", null },
+ { "@foo", null },
+ { "foo@", null },
+ { "foo@bar", null },
+
+ { "\\", null },
+ { "\\foo", null },
+ { "foo\\", null },
+ { "foo\\bar", null },
+
+ { makeString("", 0x00, ""), null },
+ { makeString("", 0x00, "foo"), null },
+ { makeString("foo", 0x00, ""), null },
+ { makeString("foo", 0x00, "bar"), null },
+
+ { makeString("", 0x1f, ""), null },
+ { makeString("", 0x1f, "foo"), null },
+ { makeString("foo", 0x1f, ""), null },
+ { makeString("foo", 0x1f, "bar"), null },
+
+ };
+ }
+
+ @Test(dataProvider = "legalModuleNames")
+ public void testLegalModuleName(String mn, String expected) throws Exception {
+ ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+ ByteBuffer bb = toBuffer(md);
+ String name = ModuleDescriptor.read(bb).name();
+ assertEquals(name, expected);
+ }
+
+ @Test(dataProvider = "illegalModuleNames",
+ expectedExceptions = InvalidModuleDescriptorException.class)
+ public void testIllegalModuleName(String mn, String ignore) throws Exception {
+ ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
+ }
+
+ @Test(dataProvider = "legalModuleNames")
+ public void testLegalRequires(String mn, String expected) throws Exception {
+ ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+ Optional<Requires> requires = descriptor.requires().stream()
+ .filter(r -> !r.name().equals("java.base"))
+ .findAny();
+ assertTrue(requires.isPresent());
+ assertEquals(requires.get().name(), expected);
+ }
+
+ @Test(dataProvider = "illegalModuleNames",
+ expectedExceptions = InvalidModuleDescriptorException.class)
+ public void testIllegalRequires(String mn, String ignore) throws Exception {
+ ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
+ }
+
+ @Test(dataProvider = "legalModuleNames")
+ public void testLegalExports(String mn, String expected) throws Exception {
+ ModuleDescriptor md = newBuilder("m")
+ .requires("java.base")
+ .exports("p", Set.of(mn))
+ .build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+ Optional<Exports> export = descriptor.exports().stream().findAny();
+ assertTrue(export.isPresent());
+ assertTrue(export.get().targets().contains(expected));
+ }
+
+ @Test(dataProvider = "illegalModuleNames",
+ expectedExceptions = InvalidModuleDescriptorException.class)
+ public void testIllegalExports(String mn, String ignore) throws Exception {
+ ModuleDescriptor md = newBuilder("m")
+ .requires("java.base")
+ .exports("p", Set.of(mn))
+ .build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
+ }
+
+ @Test(dataProvider = "legalModuleNames")
+ public void testLegalOpens(String mn, String expected) throws Exception {
+ ModuleDescriptor md = newBuilder("m")
+ .requires("java.base")
+ .opens("p", Set.of(mn))
+ .build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+ Optional<Opens> opens = descriptor.opens().stream().findAny();
+ assertTrue(opens.isPresent());
+ assertTrue(opens.get().targets().contains(expected));
+ }
+
+ @Test(dataProvider = "illegalModuleNames",
+ expectedExceptions = InvalidModuleDescriptorException.class)
+ public void testIllegalOpens(String mn, String ignore) throws Exception {
+ ModuleDescriptor md = newBuilder("m")
+ .requires("java.base")
+ .opens("p", Set.of(mn))
+ .build();
+ ByteBuffer bb = toBuffer(md);
+ ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
+ }
+
+ /**
+ * Returns a Builder that does not validate module names.
+ */
+ private Builder newBuilder(String mn) {
+ return SharedSecrets.getJavaLangModuleAccess()
+ .newModuleBuilder(mn, false, false, false);
+ }
+
+ /**
+ * Returns a {@code ByteBuffer} containing the given module descriptor
+ * in module-info.class format.
+ */
+ private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ModuleInfoWriter.write(descriptor, baos);
+ return ByteBuffer.wrap(baos.toByteArray());
+ }
+
+ /**
+ * Returns a string containing a given code point.
+ */
+ private String makeString(String prefix, int codePoint, String suffix) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(prefix);
+ sb.appendCodePoint(codePoint);
+ sb.append(suffix);
+ return sb.toString();
+ }
+}
--- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -24,7 +24,7 @@
/**
* @test
* @library /lib/testlibrary
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.module
* jdk.compiler
* @build ModuleReaderTest CompilerUtils JarUtils
* @run testng ModuleReaderTest
@@ -53,7 +53,7 @@
import java.util.stream.Collectors;
import java.util.spi.ToolProvider;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
@@ -216,9 +216,7 @@
*/
void test(Path mp) throws IOException {
- ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
- .newModulePath(Runtime.version(), true, mp);
-
+ ModuleFinder finder = new ModulePath(Runtime.version(), true, mp);
ModuleReference mref = finder.find(TEST_MODULE).get();
ModuleReader reader = mref.open();
--- a/jdk/test/java/lang/module/ModuleReferenceTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleReferenceTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -31,7 +31,6 @@
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
-import java.util.function.Supplier;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@@ -39,8 +38,13 @@
@Test
public class ModuleReferenceTest {
- private Supplier<ModuleReader> makeSupplier() {
- return () -> { throw new UnsupportedOperationException(); };
+ private ModuleReference newModuleReference(ModuleDescriptor descriptor, URI uri) {
+ return new ModuleReference(descriptor, uri) {
+ @Override
+ public ModuleReader open() {
+ throw new UnsupportedOperationException();
+ }
+ };
}
public void testBasic() throws Exception {
@@ -53,25 +57,16 @@
URI uri = URI.create("module:/m");
- Supplier<ModuleReader> supplier = makeSupplier();
-
- ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+ ModuleReference mref = newModuleReference(descriptor, uri);
assertTrue(mref.descriptor().equals(descriptor));
assertTrue(mref.location().get().equals(uri));
-
- // check that the supplier is called
- try {
- mref.open();
- assertTrue(false);
- } catch (UnsupportedOperationException expected) { }
}
-
@Test(expectedExceptions = { NullPointerException.class })
public void testNullDescriptor() throws Exception {
URI location = URI.create("module:/m");
- new ModuleReference(null, location, makeSupplier());
+ newModuleReference(null, location);
}
public void testNullLocation() {
@@ -79,55 +74,8 @@
= ModuleDescriptor.module("m")
.exports("p")
.build();
- Supplier<ModuleReader> supplier = makeSupplier();
- ModuleReference mref = new ModuleReference(descriptor, null, supplier);
+ ModuleReference mref = newModuleReference(descriptor, null);
assertTrue(!mref.location().isPresent());
}
- @Test(expectedExceptions = { NullPointerException.class })
- public void testNullSupplier() throws Exception {
- ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
- URI location = URI.create("module:/m");
- new ModuleReference(descriptor, location, null);
- }
-
-
- public void testEqualsAndHashCode() {
- ModuleDescriptor descriptor1
- = ModuleDescriptor.module("m1")
- .exports("p")
- .build();
- ModuleDescriptor descriptor2
- = ModuleDescriptor.module("m1")
- .exports("p")
- .build();
-
- URI uri = URI.create("module:/m1");
- Supplier<ModuleReader> supplier = makeSupplier();
-
- ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
- ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
- ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
-
- assertTrue(mref1.equals(mref1));
- assertTrue(mref1.equals(mref2));
- assertTrue(mref2.equals(mref1));
- assertTrue(mref1.hashCode() == mref2.hashCode());
-
- assertTrue(mref3.equals(mref3));
- assertFalse(mref3.equals(mref1));
- assertFalse(mref1.equals(mref3));
- }
-
-
- public void testToString() {
- ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
- URI uri = URI.create("module:/m1");
- Supplier<ModuleReader> supplier = makeSupplier();
- ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
- String s = mref.toString();
- assertTrue(s.contains("m1"));
- assertTrue(s.contains(uri.toString()));
- }
-
}
--- a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -119,7 +119,6 @@
List<Attribute> attrs = new ArrayList<>();
attrs.add(new ClassFileAttributes.ModuleAttribute());
attrs.add(new ClassFileAttributes.ModulePackagesAttribute());
- attrs.add(new ClassFileAttributes.ModuleVersionAttribute());
attrs.add(new ClassFileAttributes.ModuleTargetAttribute());
cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
--- a/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -21,10 +21,11 @@
* questions.
*/
-/**
+/*
* @test
* @bug 4167874
- * @modules jdk.httpserver
+ * @modules java.logging
+ * jdk.httpserver
* @library ../../../../com/sun/net/httpserver
* @library /lib/testlibrary
* @build FileServerHandler jdk.testlibrary.FileUtils
@@ -33,10 +34,13 @@
* @summary URL-downloaded jar files can consume all available file descriptors
*/
-import java.io.*;
-import java.net.*;
-import java.lang.reflect.*;
-import com.sun.net.httpserver.*;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpServer;
public class CloseTest extends Common {
@@ -130,7 +134,7 @@
// load tests
loadClass ("com.foo.TestClass1", loader, false);
loadClass ("com.foo.TestClass", loader, true);
- loadClass ("java.sql.Array", loader, true);
+ loadClass ("java.util.ArrayList", loader, true);
// now check we can delete the path
rm_minus_rf (new File(name));
--- a/jdk/test/java/rmi/registry/reexport/Reexport.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/rmi/registry/reexport/Reexport.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -67,10 +67,6 @@
System.err.println("Creating duplicate registry, this should fail...");
reg = createReg(true, regPort);
- if (reg != null) {
- TestLibrary.bomb("failed was able to duplicate the registry?!?");
- }
-
// Kill the first registry.
System.err.println("Bringing down the first registry");
try {
@@ -105,6 +101,9 @@
try {
reg = LocateRegistry.createRegistry(port);
+ if (remoteOk) {
+ TestLibrary.bomb("Remote registry is up, an Exception is expected!");
+ }
} catch (Throwable e) {
if (remoteOk) {
System.err.println("EXPECTING PORT IN USE EXCEPTION:");
--- a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -223,7 +223,7 @@
ImageReader reader = getTIFFReader();
ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
- reader.setInput(s, false, true);
+ reader.setInput(s, false, false);
int ni = reader.getNumImages(true);
check(ni == 2, "invalid number of images");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8154058
+ * @author a.stepanov
+ * @summary Some checks for ignoring metadata
+ * @run main ReadUnknownTagsTest
+ */
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import javax.imageio.*;
+import javax.imageio.metadata.*;
+
+import javax.imageio.stream.*;
+import javax.imageio.plugins.tiff.*;
+
+
+public class ReadUnknownTagsTest {
+
+ private final static int SZ = 50;
+ private final static Color C = Color.RED;
+
+ private final static int DESCRIPTION_TAG =
+ BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION;
+ private final static String DESCRIPTION = "A Test Image";
+
+ private final static int FAX_TAG = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA;
+ private final static short FAX_DATA =
+ FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED;
+
+ private final boolean ignoreMetadata;
+ private final boolean readUnknownTags;
+
+ public ReadUnknownTagsTest(boolean ignoreMetadata,
+ boolean readUnknownTags) {
+ this.ignoreMetadata = ignoreMetadata;
+ this.readUnknownTags = readUnknownTags;
+ }
+
+ private ImageWriter getTIFFWriter() {
+
+ java.util.Iterator<ImageWriter> writers =
+ ImageIO.getImageWritersByFormatName("TIFF");
+ if (!writers.hasNext()) {
+ throw new RuntimeException("No writers available for TIFF format");
+ }
+ return writers.next();
+ }
+
+ private ImageReader getTIFFReader() {
+
+ java.util.Iterator<ImageReader> readers =
+ ImageIO.getImageReadersByFormatName("TIFF");
+ if (!readers.hasNext()) {
+ throw new RuntimeException("No readers available for TIFF format");
+ }
+ return readers.next();
+ }
+
+
+ private void writeImage() throws Exception {
+
+ String fn = "test-" + ignoreMetadata + ".tiff";
+ OutputStream s = new BufferedOutputStream(new FileOutputStream(fn));
+ try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) {
+
+ ImageWriter writer = getTIFFWriter();
+ writer.setOutput(ios);
+
+ BufferedImage img = new BufferedImage(SZ, SZ,
+ BufferedImage.TYPE_INT_RGB);
+ Graphics g = img.getGraphics();
+ g.setColor(C);
+ g.fillRect(0, 0, SZ, SZ);
+ g.dispose();
+
+ ImageWriteParam param = writer.getDefaultWriteParam();
+
+ IIOMetadata md = writer.getDefaultImageMetadata(
+ new ImageTypeSpecifier(img), param);
+
+ TIFFDirectory dir = TIFFDirectory.createFromMetadata(md);
+
+ TIFFTag descTag =
+ BaselineTIFFTagSet.getInstance().getTag(DESCRIPTION_TAG);
+ dir.addTIFFField(new TIFFField(descTag, TIFFTag.TIFF_ASCII, 1,
+ new String[] {DESCRIPTION}));
+
+ TIFFTag faxTag = FaxTIFFTagSet.getInstance().getTag(FAX_TAG);
+ dir.addTIFFField(new TIFFField(faxTag, FAX_DATA));
+
+ writer.write(new IIOImage(img, null, dir.getAsMetadata()));
+
+ ios.flush();
+ writer.dispose();
+ }
+ s.close();
+ }
+
+ private void readAndCheckImage() throws Exception {
+
+ ImageReader reader = getTIFFReader();
+
+ String fn = "test-" + ignoreMetadata + ".tiff";
+ ImageInputStream s = ImageIO.createImageInputStream(new File(fn));
+
+ reader.setInput(s, false, ignoreMetadata);
+
+ int ni = reader.getNumImages(true);
+ check(ni == 1, "invalid number of images");
+
+
+ TIFFImageReadParam param = new TIFFImageReadParam();
+ // fax data are allowed by default
+ param.removeAllowedTagSet(FaxTIFFTagSet.getInstance());
+
+ // readUnknownTags setting
+ if (param.getReadUnknownTags()) {
+ throw new RuntimeException("Default readUnknownTags is not false");
+ }
+ param.setReadUnknownTags(readUnknownTags);
+ if (param.getReadUnknownTags() != readUnknownTags) {
+ throw new RuntimeException("Incorrect readUnknownTags setting "
+ + "\"" + readUnknownTags + "\"");
+ }
+
+ // read images and metadata
+ IIOImage i = reader.readAll(0, param);
+ BufferedImage bi = (BufferedImage) i.getRenderedImage();
+
+ check(bi.getWidth() == SZ, "invalid width");
+ check(bi.getHeight() == SZ, "invalid height");
+ Color c = new Color(bi.getRGB(SZ / 2, SZ / 2));
+ check(c.equals(C), "invalid color");
+
+ IIOMetadata metadata = i.getMetadata();
+
+ //
+ // Verify presence of image metadata
+ //
+ if (metadata == null) {
+ throw new RuntimeException("No image metadata retrieved");
+ }
+
+ TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
+
+ //
+ // Verify presence of essential ImageWidth field regardless of
+ // settings of ignoreMetadata and readUnknownTags
+ //
+ int failures = 0;
+ if (!dir.containsTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH)) {
+ System.err.println("Metadata is missing essential ImageWidth tag");
+ failures++;
+ } else {
+ TIFFField widthField =
+ dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
+ System.out.printf("ImageWidth: %d%n", widthField.getAsLong(0));
+ }
+
+ //
+ // Verify presence of non-essential baseline ImageDescription field
+ // if and only if ignoreMetadata == false
+ //
+ boolean hasDescription = dir.containsTIFFField(DESCRIPTION_TAG);
+ System.out.println("ImageDescription (" + !ignoreMetadata + "): "
+ + hasDescription);
+ if (ignoreMetadata && hasDescription) {
+ System.err.println
+ ("Description metadata present despite ignoreMetadata");
+ failures++;
+ } else if (!ignoreMetadata && !hasDescription) {
+ System.err.println
+ ("Description metadata absent despite !ignoreMetadata");
+ failures++;
+ }
+
+ //
+ // Verify presence of CleanFaxData field if and only if
+ // ignoreMetadata == false and readUnknownTags == true
+ //
+ boolean shouldHaveFaxField = !ignoreMetadata && readUnknownTags;
+ boolean hasFaxField = dir.containsTIFFField(FAX_TAG);
+ System.out.println("CleanFaxData (" + shouldHaveFaxField + "): "
+ + hasFaxField);
+
+ if (ignoreMetadata) {
+ if (hasFaxField) {
+ System.err.println
+ ("Fax metadata present despite ignoreMetadata");
+ failures++;
+ }
+ } else { // !ignoreMetadata
+ if (!readUnknownTags && hasFaxField) {
+ System.err.println
+ ("Fax metadata present despite !readUnknownTags");
+ failures++;
+ } else if (readUnknownTags && !hasFaxField) {
+ System.err.println
+ ("Fax metadata absent despite readUnknownTags");
+ failures++;
+ }
+ }
+
+ if (failures > 0) {
+ throw new RuntimeException("Test failed for ignoreMetadata "
+ + ignoreMetadata + " and readUnknownTags " + readUnknownTags);
+ }
+ }
+
+ public void run() {
+ try {
+ writeImage();
+ readAndCheckImage();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void check(boolean ok, String msg) {
+ if (!ok) { throw new RuntimeException(msg); }
+ }
+
+ public static void main(String[] args) {
+ int failures = 0;
+
+ System.out.println();
+ for (boolean ignoreMetadata : new boolean[] {false, true}) {
+ for (boolean readUnknownTags : new boolean[] {false, true}) {
+ try {
+ System.out.printf
+ ("ignoreMetadata: %s, readUnknownTags: %s%n",
+ ignoreMetadata, readUnknownTags);
+ (new ReadUnknownTagsTest(ignoreMetadata,
+ readUnknownTags)).run();
+ } catch (Exception e) {
+ e.printStackTrace();
+ failures++;
+ } finally {
+ System.out.println();
+ }
+ }
+ }
+ }
+}
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -154,7 +154,7 @@
"must return null TIFFField");
long offset = 4L;
- long a[] = {Long.MIN_VALUE, 0, Long.MAX_VALUE};
+ long a[] = {0, Integer.MAX_VALUE, (1 << 32) - 1};
int v = 100500;
TIFFField
f1 = new TIFFField(tag1, type, offset, d),
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 8152183 8149562
+ * @bug 8152183 8149562 8169725 8169728
* @author a.stepanov
* @summary Some checks for TIFFField methods
* @run main TIFFFieldTest
@@ -65,7 +65,26 @@
ok = false;
try { new TIFFField(tag, -1); }
catch (IllegalArgumentException e) { ok = true; }
- check(ok, CONSTRUCT + "invalid count");
+ check(ok, CONSTRUCT + "negative value");
+
+ ok = false;
+ try { new TIFFField(tag, 1L << 32); }
+ catch (IllegalArgumentException e) { ok = true; }
+ check(ok, CONSTRUCT + "value > 0xffffffff");
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT);
+ new TIFFField(t, 0x10000);
+ } catch (IllegalArgumentException e) { ok = true; }
+ check(ok, CONSTRUCT + "value 0x10000 incompatible with TIFF_SHORT");
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+ new TIFFField(t, 0xffff);
+ } catch (IllegalArgumentException e) { ok = true; }
+ check(ok, CONSTRUCT + "value 0xffff incompatible with TIFF_LONG");
// check value type recognition
int v = 1 << 16;
@@ -152,6 +171,94 @@
check((f.getDirectory() == null) && !f.hasDirectory(),
"must not have directory");
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+ long[][] tiffRationals = new long[6][3];
+ new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+ tiffRationals);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SRATIONAL);
+ int[][] tiffSRationals = new int[6][3];
+ new TIFFField(t, TIFFTag.TIFF_SRATIONAL, tiffSRationals.length,
+ tiffSRationals);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+ long[] tiffLongs = new long[] {0, -7, 10};
+ new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+ tiffLongs);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+ long[] tiffLongs = new long[] {0, 7, 0x100000000L};
+ new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+ tiffLongs);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+ long[] tiffLongs = new long[] {-7};
+ new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+ tiffLongs);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+ long[] tiffLongs = new long[] {0x100000000L};
+ new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+ tiffLongs);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+ long[][] tiffRationals = new long[][] {
+ {10, 2},
+ {1, -3},
+ {4, 7}
+ };
+ new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+ tiffRationals);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
+ ok = false;
+ try {
+ TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+ long[][] tiffRationals = new long[][] {
+ {10, 2},
+ {0x100000000L, 3},
+ {4, 7}
+ };
+ new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+ tiffRationals);
+ } catch (IllegalArgumentException e) {
+ ok = true;
+ }
+
// constructor: TIFFField(tag, type, offset, dir)
List<TIFFTag> tags = new ArrayList<>();
tags.add(tag);
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -159,7 +159,7 @@
ImageReader reader = getTIFFReader();
ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
- reader.setInput(s, false, true);
+ reader.setInput(s, false, false);
int ni = reader.getNumImages(true);
check(ni == 1, "invalid number of images: " + ni);
--- a/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java Mon Dec 19 16:05:38 2016 +0000
@@ -34,15 +34,17 @@
static final String ERROR = "ERROR";
X509ExtendedKeyManager akm;
String expectedAP;
+ boolean doCheck = true;
MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
this.akm = akm;
}
public MyX509ExtendedKeyManager(
- X509ExtendedKeyManager akm, String expectedAP) {
+ X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) {
this.akm = akm;
this.expectedAP = expectedAP;
+ this.doCheck = doCheck;
}
@@ -104,6 +106,12 @@
private void checkALPN(String ap) {
+ if (!doCheck) {
+ System.out.println("Skipping KeyManager checks " +
+ "because a callback has been registered");
+ return;
+ }
+
if (ERROR.equals(expectedAP)) {
throw new RuntimeException("Should not reach here");
}
--- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,23 +26,53 @@
/*
* @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLEngineAlpnTest h2 h2 h2
- * @run main/othervm SSLEngineAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLEngineAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLEngineAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLEngineAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLEngineAlpnTest H2 h2 ERROR
- * @run main/othervm SSLEngineAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLEngineAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2 http/1.1 ERROR
*/
/**
* A simple SSLEngine-based client/server that demonstrates the proposed API
* changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
*
+ * Usage:
+ * java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
* This example is based on our standard SSLEngineTemplate.
*
* The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
@@ -98,6 +128,7 @@
import java.io.*;
import java.security.*;
import java.nio.*;
+import java.util.Arrays;
public class SSLEngineAlpnTest {
@@ -117,6 +148,9 @@
*/
private static final boolean debug = false;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
private final SSLContext sslc;
private SSLEngine clientEngine; // client Engine
@@ -157,17 +191,21 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
- SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]);
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !args[1].equals("UNUSED"); // is callback being used?
+
+ SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
try {
- test.runTest(convert(args[0]), convert(args[1]), args[2]);
+ test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -199,7 +237,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
@@ -215,12 +254,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings = null;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
@@ -247,12 +289,12 @@
* One could easily separate these phases into separate
* sections of code.
*/
- private void runTest(String[] serverAPs, String[] clientAPs,
- String expectedAP) throws Exception {
+ private void runTest(String[] serverAPs, String callbackAP,
+ String[] clientAPs, String expectedAP) throws Exception {
boolean dataDone = false;
- createSSLEngines(serverAPs, clientAPs);
+ createSSLEngines(serverAPs, callbackAP, clientAPs);
createBuffers();
SSLEngineResult clientResult; // results from client's last operation
@@ -364,8 +406,8 @@
* Using the SSLContext created during object creation,
* create/configure the SSLEngines we'll use for this test.
*/
- private void createSSLEngines(String[] serverAPs, String[] clientAPs)
- throws Exception {
+ private void createSSLEngines(String[] serverAPs, String callbackAP,
+ String[] clientAPs) throws Exception {
/*
* Configure the serverEngine to act as a server in the SSL/TLS
* handshake. Also, require SSL client authentication.
@@ -385,18 +427,42 @@
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslp.setUseCipherSuitesOrder(true); // Set server side order
serverEngine.setSSLParameters(sslp);
+ // check that no callback has been registered
+ if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ serverEngine.setHandshakeApplicationProtocolSelector(
+ (sslEngine, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (serverEngine.getHandshakeApplicationProtocolSelector()
+ == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()"
+ + " should return non-null");
+ }
+ }
+
/*
* Similar to above, but using client mode instead.
*/
clientEngine = sslc.createSSLEngine("client", 80);
clientEngine.setUseClientMode(true);
sslp = clientEngine.getSSLParameters();
- sslp.setApplicationProtocols(clientAPs);
+ if (clientAPs != null) {
+ sslp.setApplicationProtocols(clientAPs);
+ }
clientEngine.setSSLParameters(sslp);
if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
--- a/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,61 @@
/*
* @test
- * @bug 8051498 8145849 8158978
+ * @bug 8051498 8145849 8158978 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLServerSocketAlpnTest h2 h2 h2
- * @run main/othervm SSLServerSocketAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLServerSocketAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLServerSocketAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLServerSocketAlpnTest H2 h2 ERROR
- * @run main/othervm SSLServerSocketAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR
+ *
* @author Brad Wetmore
*/
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ * java SSLServerSocketAlpnTest
+ * <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
import java.io.*;
import java.security.KeyStore;
+import java.util.Arrays;
import javax.net.ssl.*;
@@ -73,6 +112,9 @@
static String trustFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + trustStoreFile;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
/*
* SSLContext
*/
@@ -89,6 +131,7 @@
static boolean debug = false;
static String[] serverAPs;
+ static String callbackAP;
static String[] clientAPs;
static String expectedAP;
@@ -129,7 +172,9 @@
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslServerSocket.setSSLParameters(sslp);
serverPort = sslServerSocket.getLocalPort();
@@ -146,6 +191,25 @@
+ "return null before the handshake starts");
}
+ // check that no callback has been registered
+ if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ sslSocket.setHandshakeApplicationProtocolSelector(
+ (serverSocket, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()"
+ + " should return non-null");
+ }
+ }
+
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -276,14 +340,19 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
- clientAPs = convert(args[1]);
- expectedAP = args[2];
+ callbackAP = args[1];
+ clientAPs = convert(args[2]);
+ expectedAP = args[3];
+
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
/*
* Start the tests.
@@ -291,7 +360,7 @@
try {
new SSLServerSocketAlpnTest();
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -322,7 +391,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustKS);
@@ -338,12 +408,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
--- a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,60 @@
/*
* @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLSocketAlpnTest h2 h2 h2
- * @run main/othervm SSLSocketAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLSocketAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLSocketAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLSocketAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLSocketAlpnTest H2 h2 ERROR
- * @run main/othervm SSLSocketAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLSocketAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR
+ *
* @author Brad Wetmore
*/
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ * java SSLSocketAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
import java.io.*;
import java.security.KeyStore;
+import java.util.Arrays;
import javax.net.ssl.*;
@@ -73,6 +111,9 @@
static String trustFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + trustStoreFile;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
/*
* SSLContext
*/
@@ -89,6 +130,7 @@
static boolean debug = false;
static String[] serverAPs;
+ static String callbackAP;
static String[] clientAPs;
static String expectedAP;
@@ -136,7 +178,9 @@
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslSocket.setSSLParameters(sslp);
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -144,6 +188,24 @@
+ "return null before the handshake starts");
}
+ // check that no callback has been registered
+ if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ sslSocket.setHandshakeApplicationProtocolSelector(
+ (serverSocket, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()" + " should return non-null");
+ }
+ }
+
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -274,14 +336,19 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
- clientAPs = convert(args[1]);
- expectedAP = args[2];
+ callbackAP = args[1];
+ clientAPs = convert(args[2]);
+ expectedAP = args[3];
+
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
/*
* Start the tests.
@@ -289,7 +356,7 @@
try {
new SSLSocketAlpnTest();
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -320,7 +387,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustKS);
@@ -336,12 +404,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
--- a/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -29,30 +29,37 @@
/*
* @test
- * @bug 8013810
- * @summary Test that print service returned without filter are of the same class as with name filter
+ * @bug 8013810 8025439
+ * @summary Test that print service returned without filter are of the same class
+ * as with name filter
*/
public class GetPrintServices {
- public static void main(String[] args) throws Exception {
- for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
- String serviceName = service.getName();
- PrintService serviceByName = lookupByName(serviceName);
- if (!service.equals(serviceByName)) {
- throw new RuntimeException("NOK " + serviceName
+ public static void main(String[] args) throws Exception {
+ for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
+ String serviceName = service.getName();
+ PrinterName name = service.getAttribute(PrinterName.class);
+ String printerName = name.getValue();
+
+ PrintService serviceByName = lookupByName(printerName);
+ System.out.println("service " + service);
+ System.out.println("serviceByName " + serviceByName);
+ if (!service.equals(serviceByName)) {
+ throw new RuntimeException("NOK " + serviceName
+ " expected: " + service.getClass().getName()
+ " got: " + serviceByName.getClass().getName());
- }
+ }
+ }
+ System.out.println("Test PASSED");
}
- System.out.println("Test PASSED");
- }
- private static PrintService lookupByName(String name) {
- AttributeSet attributes = new HashAttributeSet();
- attributes.add(new PrinterName(name, null));
- for (PrintService service : PrintServiceLookup.lookupPrintServices(null, attributes)) {
- return service;
+ private static PrintService lookupByName(String name) {
+ AttributeSet attributes = new HashAttributeSet();
+ attributes.add(new PrinterName(name, null));
+ for (PrintService service :
+ PrintServiceLookup.lookupPrintServices(null, attributes)) {
+ return service;
+ }
+ return null;
}
- return null;
- }
}
--- a/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,7 +26,7 @@
* @summary Test to check JComboBox does not lose its ability to invoke
* registerd ActionListener in case of exception in ActionListener
* @run main ActionListenerExceptionTest
- */
+ */
import java.awt.AWTEvent;
import java.awt.AWTException;
@@ -44,6 +44,7 @@
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ActionListenerExceptionTest {
@@ -133,7 +134,11 @@
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
Object comp = combo.getUI().getAccessibleChild(combo, 0);
- JComponent scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(0);
+ int i = 0;
+ JComponent scrollPane;
+ do {
+ scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(i++);
+ } while (!(scrollPane instanceof JScrollPane));
menuItemHeight = scrollPane.getSize().height / TOTAL_MENU_ITEMS;
yPos = scrollPane.getLocationOnScreen().y + menuItemHeight / 2;
--- a/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -24,10 +24,12 @@
/*
@test
@key headful
- @bug 8062946
+ @bug 8062946 8159906
@summary Verify Transparency upon iconify/deiconify sequence
@run main TransparencyTest
*/
+import java.awt.GraphicsEnvironment;
+import java.awt.GraphicsDevice;
import java.awt.Color;
import java.awt.Point;
import java.awt.Robot;
@@ -43,7 +45,7 @@
private static final int WIDTH = 250;
private static final int HEIGHT = 250;
private static final float OPACITY = 0.60f;
- private static Point dlgPos;
+ private static volatile Point dlgPos;
public static void createAndShowGUI() {
frame = new JFrame("JFrame");
@@ -67,6 +69,14 @@
public static void main(String[] args) throws Exception {
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ GraphicsDevice.WindowTranslucency mode = GraphicsDevice.WindowTranslucency.TRANSLUCENT;
+ boolean translucencyCheck = gd.isWindowTranslucencySupported(mode);
+ if(!translucencyCheck) {
+ return;
+ }
+
Robot robot = new Robot();
// create a GUI
SwingUtilities.invokeAndWait(new Runnable() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JLightweightFrame/JLightweightFrameRoundTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170387
+ * @summary JLightweightFrame#syncCopyBuffer() may throw IOOBE
+ * @modules java.desktop/sun.swing
+ * @run main JLightweightFrameRoundTest
+ */
+
+import sun.swing.JLightweightFrame;
+import sun.swing.LightweightContent;
+
+import javax.swing.*;
+
+public class JLightweightFrameRoundTest {
+ public static void main(String[] args) throws Exception {
+ SwingUtilities.invokeAndWait(() -> {
+ JLightweightFrame jLightweightFrame = new JLightweightFrame();
+ jLightweightFrame.setContent(new XLightweightContent());
+ jLightweightFrame.setSize(600, 600);
+ jLightweightFrame.notifyDisplayChanged(1.0001, 1.0001);
+ });
+ }
+
+ static class XLightweightContent implements LightweightContent {
+ @Override
+ public JComponent getComponent() {
+ return new JPanel();
+ }
+
+ @Override
+ public void paintLock() {}
+
+ @Override
+ public void paintUnlock() {}
+
+ @Override
+ public void imageBufferReset(int[] data, int x, int y, int width,
+ int height, int linestride,
+ double scaleX,
+ double scaleY) {}
+
+ @Override
+ public void imageReshaped(int x, int y, int width, int height) {}
+
+ @Override
+ public void imageUpdated(int dirtyX, int dirtyY, int dirtyWidth,
+ int dirtyHeight) {}
+
+ @Override
+ public void focusGrabbed() {}
+
+ @Override
+ public void focusUngrabbed() {}
+
+ @Override
+ public void preferredSizeChanged(int width, int height) {}
+
+ @Override
+ public void maximumSizeChanged(int width, int height) {}
+
+ @Override
+ public void minimumSizeChanged(int width, int height) {}
+ }
+}
--- a/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,31 @@
* @key headful
* @library ../../regtesthelpers
* @build Util
- * @bug 8033699 8154043
+ * @bug 8033699 8154043 8167160
* @summary Incorrect radio button behavior when pressing tab key
- * @author Vivi An
* @run main bug8033699
*/
-
-import javax.swing.*;
-import javax.swing.event.*;
-import java.awt.event.*;
-import java.awt.*;
+import java.awt.KeyboardFocusManager;
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
public class bug8033699 {
+
+ private static JFrame mainFrame;
private static Robot robot;
-
private static JButton btnStart;
- private static ButtonGroup btnGrp;
private static JButton btnEnd;
private static JButton btnMiddle;
private static JRadioButton radioBtn1;
@@ -51,7 +60,9 @@
public static void main(String args[]) throws Throwable {
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
+ changeLAF();
createAndShowGUI();
}
});
@@ -84,11 +95,30 @@
// down key circle back to first button in grouped radio button
runTest8();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ mainFrame.dispose();
+ }
+ });
+ }
+
+ private static void changeLAF() {
+ String currentLAF = UIManager.getLookAndFeel().toString();
+ System.out.println(currentLAF);
+ currentLAF = currentLAF.toLowerCase();
+ if (currentLAF.contains("aqua") || currentLAF.contains("nimbus")) {
+ try {
+ UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
}
private static void createAndShowGUI() {
- JFrame mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
-
+ mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
btnStart = new JButton("Start");
btnEnd = new JButton("End");
btnMiddle = new JButton("Middle");
@@ -132,12 +162,13 @@
}
// Radio button Group as a single component when traversing through tab key
- private static void runTest1() throws Exception{
+ private static void runTest1() throws Exception {
hitKey(robot, KeyEvent.VK_TAB);
hitKey(robot, KeyEvent.VK_TAB);
hitKey(robot, KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
System.out.println("Radio Button Group Go To Next Component through Tab Key failed");
@@ -148,9 +179,10 @@
}
// Non-Grouped Radio button as a single component when traversing through tab key
- private static void runTest2() throws Exception{
+ private static void runTest2() throws Exception {
hitKey(robot, KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) {
System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed");
@@ -161,11 +193,12 @@
}
// Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key
- private static void runTest3() throws Exception{
+ private static void runTest3() throws Exception {
hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed");
@@ -176,10 +209,11 @@
}
// Using arrow key to move focus in radio button group
- private static void runTest4() throws Exception{
+ private static void runTest4() throws Exception {
hitKey(robot, KeyEvent.VK_DOWN);
hitKey(robot, KeyEvent.VK_RIGHT);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) {
System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed");
@@ -189,10 +223,11 @@
});
}
- private static void runTest5() throws Exception{
+ private static void runTest5() throws Exception {
hitKey(robot, KeyEvent.VK_UP);
hitKey(robot, KeyEvent.VK_LEFT);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed");
@@ -202,10 +237,11 @@
});
}
- private static void runTest6() throws Exception{
+ private static void runTest6() throws Exception {
hitKey(robot, KeyEvent.VK_UP);
hitKey(robot, KeyEvent.VK_UP);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) {
System.out.println("Radio button Group Circle Back To First Button Test");
@@ -215,9 +251,10 @@
});
}
- private static void runTest7() throws Exception{
+ private static void runTest7() throws Exception {
hitKey(robot, KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) {
System.out.println("Separate Component added in button group layout");
@@ -227,9 +264,10 @@
});
}
- private static void runTest8() throws Exception{
+ private static void runTest8() throws Exception {
hitKey(robot, KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
public void run() {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
System.out.println("Separate Component added in button group layout");
--- a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java Mon Dec 19 16:05:38 2016 +0000
@@ -42,7 +42,6 @@
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
-import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
@@ -133,43 +132,21 @@
}
private static void runTestCase() throws Exception {
- LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
focusOn(a);
- if (isExcludedLookAndFeel(lookAndFeel)) {
- robot.keyPress(KeyEvent.VK_ENTER);
- robot.keyRelease(KeyEvent.VK_ENTER);
- robot.waitForIdle();
- isFocusOwner(b, "forward");
- robot.keyPress(KeyEvent.VK_SHIFT);
- robot.keyPress(KeyEvent.VK_TAB);
- robot.keyRelease(KeyEvent.VK_TAB);
- robot.keyRelease(KeyEvent.VK_SHIFT);
- robot.waitForIdle();
- isFocusOwner(a, "backward");
-
- } else {
- robot.keyPress(KeyEvent.VK_ENTER);
- robot.keyRelease(KeyEvent.VK_ENTER);
- robot.waitForIdle();
- isFocusOwner(next, "forward");
- robot.keyPress(KeyEvent.VK_SHIFT);
- robot.keyPress(KeyEvent.VK_TAB);
- robot.keyRelease(KeyEvent.VK_TAB);
- robot.keyRelease(KeyEvent.VK_SHIFT);
- robot.waitForIdle();
- isFocusOwner(d, "backward");
- }
+ robot.keyPress(KeyEvent.VK_ENTER);
+ robot.keyRelease(KeyEvent.VK_ENTER);
+ robot.waitForIdle();
+ isFocusOwner(next, "forward");
+ robot.keyPress(KeyEvent.VK_SHIFT);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_SHIFT);
+ robot.waitForIdle();
+ isFocusOwner(a, "backward");
}
- private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) {
-
- return lookAndFeel.toString().toLowerCase().contains("aqua")
- || lookAndFeel.toString().toLowerCase().contains("nimbus")
- || lookAndFeel.toString().toLowerCase().contains("gtk");
- }
-
private static void focusOn(Component component)
throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JTable/SorterIOOBEtest/DefaultRowSorterIOOBEtest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8160087
+ * @summary Change IOOBE to warning in the scenarios when it had not being
+ * thrown before the JDK-8078514
+ * @run main/othervm DefaultRowSorterIOOBEtest
+ */
+
+import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultRowSorterIOOBEtest extends TableRowSorter<TableModel> {
+ static List<String> rows = new ArrayList<>();
+
+ static TableModel tableModel = new AbstractTableModel() {
+
+ @Override
+ public int getRowCount() {
+ return rows.size();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 1;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ return rows.get(rowIndex);
+ }
+ };
+
+ public static void main(String[] args) {
+ DefaultRowSorter<TableModel, Integer> sorter =
+ new DefaultRowSorter<>() {
+ {
+ setModelWrapper(new SorterModelWrapper());
+ }
+ };
+
+ PrintStream err = System.err;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(10000) {
+ @Override
+ public synchronized void write(byte[] b, int off, int len) {
+ super.write(b, off, len);
+ err.print(new String(b, off, len));
+ }
+ };
+ System.setErr(new PrintStream(bos));
+
+ rows.add("New");
+
+ sorter.convertRowIndexToView(0);
+ sorter.convertRowIndexToModel(0);
+
+ String out = new String(bos.toByteArray());
+ if(out.indexOf("WARNING:") < 0) {
+ throw new RuntimeException("No warnings found");
+ }
+ }
+
+ static class SorterModelWrapper extends
+ DefaultRowSorter.ModelWrapper<TableModel, Integer> {
+
+ @Override
+ public TableModel getModel() {
+ return tableModel;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return tableModel.getColumnCount();
+ }
+
+ @Override
+ public int getRowCount() {
+ return tableModel.getRowCount();
+ }
+
+ @Override
+ public Object getValueAt(int row, int column) {
+ return tableModel.getValueAt(row, column);
+ }
+
+ @Override
+ public Integer getIdentifier(int row) {
+ return row;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/RepaintManager/8162350/RepaintManagerFPUIScaleTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/*
+ * @test
+ * @bug 8162350
+ * @summary RepaintManager shifts repainted region when the floating point UI scale is used
+ * @run main/manual/othervm -Dsun.java2d.uiScale=1.5 RepaintManagerFPUIScaleTest
+ */
+public class RepaintManagerFPUIScaleTest {
+
+ private static volatile boolean testResult = false;
+ private static volatile CountDownLatch countDownLatch;
+ private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
+ + "Check JScrollPane correctly repaints the view"
+ + " when UI scale has floating point value:\n"
+ + "\n"
+ + "1. Scroll down the JScrollPane\n"
+ + "2. Select some values\n"
+ + "If the scrolled selected value is painted without artifacts,"
+ + "press PASS, else press FAIL.";
+
+ public static void main(String args[]) throws Exception {
+
+ countDownLatch = new CountDownLatch(1);
+
+ SwingUtilities.invokeLater(RepaintManagerFPUIScaleTest::createUI);
+ countDownLatch.await(15, TimeUnit.MINUTES);
+
+ if (!testResult) {
+ throw new RuntimeException("Test fails!");
+ }
+ }
+
+ private static void createUI() {
+
+ final JFrame mainFrame = new JFrame("Motif L&F icons test");
+ GridBagLayout layout = new GridBagLayout();
+ JPanel mainControlPanel = new JPanel(layout);
+ JPanel resultButtonPanel = new JPanel(layout);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+
+ JComponent testPanel = createComponent();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ mainControlPanel.add(testPanel, gbc);
+
+ JTextArea instructionTextArea = new JTextArea();
+ instructionTextArea.setText(INSTRUCTIONS);
+ instructionTextArea.setEditable(false);
+ instructionTextArea.setBackground(Color.white);
+
+ gbc.gridx = 0;
+ gbc.gridy = 1;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ mainControlPanel.add(instructionTextArea, gbc);
+
+ JButton passButton = new JButton("Pass");
+ passButton.setActionCommand("Pass");
+ passButton.addActionListener((ActionEvent e) -> {
+ testResult = true;
+ mainFrame.dispose();
+ countDownLatch.countDown();
+
+ });
+
+ JButton failButton = new JButton("Fail");
+ failButton.setActionCommand("Fail");
+ failButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ mainFrame.dispose();
+ countDownLatch.countDown();
+ }
+ });
+
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ resultButtonPanel.add(passButton, gbc);
+
+ gbc.gridx = 1;
+ gbc.gridy = 0;
+ resultButtonPanel.add(failButton, gbc);
+
+ gbc.gridx = 0;
+ gbc.gridy = 2;
+ mainControlPanel.add(resultButtonPanel, gbc);
+
+ mainFrame.add(mainControlPanel);
+ mainFrame.pack();
+
+ mainFrame.addWindowListener(new WindowAdapter() {
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ mainFrame.dispose();
+ countDownLatch.countDown();
+ }
+ });
+ mainFrame.setVisible(true);
+ }
+
+ private static JComponent createComponent() {
+
+ int N = 100;
+ String[] data = new String[N];
+ for (int i = 0; i < N; i++) {
+ data[i] = "Floating point test List Item: " + i;
+ }
+ JList list = new JList(data);
+ list.setCellRenderer(new TestListCellRenderer());
+
+ JScrollPane scrollPane = new JScrollPane(list);
+ return scrollPane;
+ }
+
+ private static Color[] COLORS = {
+ Color.RED, Color.ORANGE, Color.GREEN, Color.BLUE, Color.GRAY
+ };
+
+ private static Image createTestImage(int width, int height, int colorindex) {
+
+ Color color = COLORS[colorindex % COLORS.length];
+
+ AffineTransform tx = GraphicsEnvironment
+ .getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice()
+ .getDefaultConfiguration()
+ .getDefaultTransform();
+
+ Image baseImage = createTestImage(width, height, 1, 1, color);
+ Image rvImage = createTestImage(width, height, tx.getScaleX(), tx.getScaleY(), color);
+
+ return new BaseMultiResolutionImage(baseImage, rvImage);
+ }
+
+ private static Image createTestImage(int w, int h,
+ double scaleX, double scaleY, Color color) {
+
+ int width = (int) Math.ceil(scaleX * w);
+ int height = (int) Math.ceil(scaleY * h);
+ BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+ Graphics2D g = img.createGraphics();
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, width, height);
+ g.scale(scaleX, scaleY);
+ g.setColor(color);
+ int d = 1;
+ int d2 = 2 * d;
+ g.drawLine(d, h / 2, w - d2, h / 2);
+ g.drawLine(w / 2, d, w / 2, h - d2);
+ g.drawRect(d, d, w - d2, h - d2);
+ g.dispose();
+
+ return img;
+ }
+
+ static class TestListCellRenderer extends DefaultListCellRenderer {
+
+ public Component getListCellRendererComponent(
+ JList list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus) {
+ Component retValue = super.getListCellRendererComponent(
+ list, value, index, isSelected, cellHasFocus
+ );
+ setIcon(new ImageIcon(createTestImage(20, 10, index)));
+ return retValue;
+ }
+ }
+}
--- a/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -44,20 +44,20 @@
* @key headful
* @summary [macos 10.12] Trackpad scrolling of text on OS X 10.12 Sierra
* is very fast (Trackpad, Retina only)
+ * @requires (os.family == "windows" | os.family == "mac")
* @run main/manual/othervm TooMuchWheelRotationEventsTest
*/
public class TooMuchWheelRotationEventsTest {
private static volatile boolean testResult = false;
private static volatile CountDownLatch countDownLatch;
- private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
- + "Try to check the issue on Mac OS X 10.12 Sierra with trackpad"
- + " on Retina display.\n"
+ private static final String INSTRUCTIONS = " INSTRUCTIONS:\n"
+ + " Try to check the issue with trackpad\n"
+ "\n"
- + "If the trackpad is not supported, press PASS\n"
+ + " If the trackpad is not supported, press PASS\n"
+ "\n"
- + "Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
- + "If the text area is scrolled too fast press FAIL, else press PASS.";
+ + " Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
+ + " If the text area is scrolled too fast press FAIL, else press PASS.";
public static void main(String args[]) throws Exception {
countDownLatch = new CountDownLatch(1);
@@ -138,6 +138,7 @@
countDownLatch.countDown();
}
});
+ mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
--- a/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java Mon Dec 19 16:05:38 2016 +0000
@@ -23,7 +23,7 @@
*/
/* @test
- @bug 6427244 8144240 8166003
+ @bug 6427244 8144240 8166003 8169879
@summary Test that pressing HOME correctly moves caret in I18N document.
@author Sergey Groznyh
@library ../../../regtesthelpers
@@ -69,10 +69,12 @@
bug6427244 t = new bug6427244();
for (String space: SPACES) {
t.init(space);
- t.runAllTests();
+ t.testCaretPosition();
}
System.out.println("OK");
+ // Dispose the test interface upon completion
+ t.destroyTestInterface();
}
void init(final String space) {
@@ -113,29 +115,65 @@
}
}
- void blockTillDisplayed(JComponent comp) {
- if(comp != null) {
- while (!comp.isVisible()) {
- try {
+ void destroyTestInterface() {
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ // Dispose the frame
+ jf.dispose();
+ }
+ });
+ } catch (Exception ex) {
+ // No-op
+ }
+ }
+
+ void blockTillDisplayed(JComponent comp) throws Exception {
+ while (comp != null && isCompVisible == false) {
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ isCompVisible = comp.isVisible();
+ }
+ });
+
+ if (isCompVisible == false) {
+ // A short wait for component to be visible
Thread.sleep(1000);
- } catch (InterruptedException ie) {
- /* No-op */
}
+ } catch (InterruptedException ex) {
+ // No-op. Thread resumed from sleep
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
}
}
}
public void testCaretPosition() {
- Point p = tp.getLocationOnScreen();
- // the right-top corner position
- p.x += (dim.width - 5);
- p.y += 5;
- ROBOT.mouseMove(p.x, p.y);
+ final Point p[] = new Point[1];
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ p[0] = tp.getLocationOnScreen();
+
+ // the right-top corner position
+ p[0].x += (dim.width - 5);
+ p[0].y += 5;
+ }
+ });
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ ROBOT.mouseMove(p[0].x, p[0].y);
ROBOT.clickMouse();
ROBOT.hitKey(KeyEvent.VK_HOME);
ROBOT.waitForIdle();
// this will fail if caret moves out of the 1st line.
if (getCaretOrdinate() != 0) {
+ // Dispose the test interface upon completion
+ destroyTestInterface();
throw new RuntimeException("Test Failed.");
}
}
@@ -162,7 +200,8 @@
return y[0];
}
- JFrame jf;
- JTextPane tp;
- Dimension dim;
+ private JFrame jf;
+ private JTextPane tp;
+ private Dimension dim;
+ private volatile boolean isCompVisible = false;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/StyleSheet/bug4936917.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+/* @test
+ @bug 4936917 7190578
+ @summary Tests if background is correctly painted when <BODY> has css margins
+ @author Denis Sharypov
+ @library ../../../regtesthelpers
+ @run main bug4936917
+*/
+
+
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.Robot;
+import java.util.Timer;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+
+public class bug4936917 {
+
+ private boolean passed = false;
+ private Timer timer;
+ private JEditorPane editorPane;
+ private static JFrame f;
+ private volatile Point p = null;
+
+ private String text =
+ "<html><head><style>" +
+ "body {background-color: #cccccc; margin-top: 36.000000pt;}" +
+ "</style></head>" +
+ "<body> some text </body></html>";
+
+ public void init() throws Exception {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ editorPane = new JEditorPane("text/html", "");
+ editorPane.setEditable(false);
+ editorPane.setMargin(new java.awt.Insets(0, 0, 0, 0));
+ editorPane.setText(text);
+
+ f = new JFrame();
+ f.getContentPane().add(editorPane);
+ f.setSize(600, 400);
+ f.setVisible(true);
+ }
+ });
+ blockTillDisplayed(editorPane);
+ Robot robot = new Robot();
+ robot.waitForIdle();
+
+ int x0 = p.x + 15 ;
+ int y = p.y + 15;
+ int match = 0;
+ int nonmatch = 0;
+
+ passed = true;
+ for (int x = x0; x < x0 + 10; x++) {
+ System.out.println("color ("+x+"," + y +")=" + robot.getPixelColor(x,y));
+ if (!robot.getPixelColor(x, y).equals(new Color(0xcc, 0xcc, 0xcc))) {
+ nonmatch++;
+ } else match++;
+ }
+ if (nonmatch > match) {
+ passed = false;
+ }
+ }
+
+ void blockTillDisplayed(JComponent comp) throws Exception {
+ while (p == null) {
+ try {
+ SwingUtilities.invokeAndWait(() -> {
+ p = comp.getLocationOnScreen();
+ });
+ } catch (IllegalStateException e) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ }
+
+ public void destroy() throws Exception {
+ SwingUtilities.invokeAndWait(()->f.dispose());
+ if(!passed) {
+ throw new RuntimeException("Test failed.");
+ }
+ }
+
+
+ public static void main(String args[]) throws Exception {
+ bug4936917 test = new bug4936917();
+ test.init();
+ test.destroy();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/DefaultImage.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Ensure no incubator modules are resolved by default in the image
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng DefaultImage
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class DefaultImage {
+ private static final String JAVA_HOME = System.getProperty("java.home");
+ private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+ private static final Path CP_DIR = Paths.get("cp");
+
+ @BeforeTest
+ private void setup() throws Throwable {
+ Path src = TEST_SRC.resolve("src").resolve("cp").resolve("listmods");
+ assertTrue(CompilerUtils.compile(src, CP_DIR));
+ }
+
+ public void test() throws Throwable {
+ if (isExplodedBuild()) {
+ System.out.println("Test cannot run on exploded build");
+ return;
+ }
+
+ java("-cp", CP_DIR.toString(),
+ "listmods.ListModules")
+ .assertSuccess()
+ .resultChecker(r -> r.assertOutputContains("java.base"))
+ .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+ }
+
+ @DataProvider(name = "tokens")
+ public Object[][] singleModuleValues() throws IOException {
+ return new Object[][]{ { "ALL-DEFAULT" }, { "ALL-SYSTEM"} };
+ }
+
+ @Test(dataProvider = "tokens")
+ public void testAddMods(String addModsToken) throws Throwable {
+ if (isExplodedBuild()) {
+ System.out.println("Test cannot run on exploded build");
+ return;
+ }
+
+ java("--add-modules", addModsToken,
+ "-cp", CP_DIR.toString(),
+ "listmods.ListModules")
+ .assertSuccess()
+ .resultChecker(r -> r.assertOutputContains("java.base"))
+ .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+ }
+
+ static ToolResult java(String... opts) throws Throwable {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ String[] options = Stream.concat(Stream.of(getJava()), Stream.of(opts))
+ .toArray(String[]::new);
+
+ ProcessBuilder pb = new ProcessBuilder(options);
+ int exitValue = executeCommand(pb).outputTo(ps)
+ .errorTo(ps)
+ .getExitValue();
+
+ return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+ }
+
+ static class ToolResult {
+ final int exitCode;
+ final String output;
+
+ ToolResult(int exitValue, String output) {
+ this.exitCode = exitValue;
+ this.output = output;
+ }
+
+ ToolResult assertSuccess() {
+ assertEquals(exitCode, 0,
+ "Expected exit code 0, got " + exitCode
+ + ", with output[" + output + "]");
+ return this;
+ }
+
+ ToolResult resultChecker(Consumer<ToolResult> r) {
+ r.accept(this);
+ return this;
+ }
+
+ ToolResult assertOutputContains(String subString) {
+ assertTrue(output.contains(subString),
+ "Expected to find [" + subString + "], in output ["
+ + output + "]" + "\n");
+ return this;
+ }
+
+ ToolResult assertOutputDoesNotContain(String subString) {
+ assertFalse(output.contains(subString),
+ "Expected to NOT find [" + subString + "], in output ["
+ + output + "]" + "\n");
+ return this;
+ }
+ }
+
+ static String getJava() {
+ Path image = Paths.get(JAVA_HOME);
+ boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+ Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+ if (Files.notExists(java))
+ throw new RuntimeException(java + " not found");
+ return java.toAbsolutePath().toString();
+ }
+
+ static boolean isExplodedBuild() {
+ Path modulesPath = Paths.get(JAVA_HOME).resolve("lib").resolve("modules");
+ return Files.notExists(modulesPath);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/ImageModules.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Basic test for incubator modules in jmods and images
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jartool jdk.jlink
+ * @build CompilerUtils
+ * @run testng/othervm ImageModules
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class ImageModules {
+ private static final String JAVA_HOME = System.getProperty("java.home");
+ private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods");
+
+ private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+ private static final Path MODS_DIR = Paths.get("mods");
+ private static final Path CP_DIR = Paths.get("cp");
+ private static final Path JARS_DIR = Paths.get("jars");
+ private static final Path JMODS_DIR = Paths.get("jmods");
+ private static final Path IMAGE = Paths.get("image");
+
+ private static final String JAVA_BASE = "java.base";
+ private final String[] modules = new String[] { "message.writer",
+ "message.converter" };
+
+ @BeforeTest
+ private void setup() throws Throwable {
+ Path src = TEST_SRC.resolve("src");
+ for (String name : modules) {
+ assertTrue(CompilerUtils.compile(src.resolve(name),
+ MODS_DIR,
+ "--module-source-path", src.toString()));
+ }
+
+ assertTrue(CompilerUtils.compile(src.resolve("cp"),
+ CP_DIR,
+ "--module-path", MODS_DIR.toString(),
+ "--add-modules", "message.writer"));
+ }
+
+ @DataProvider(name = "singleModule")
+ public Object[][] singleModuleValues() throws IOException {
+ Object[][] values = new Object[][]{
+ // { Extra args to the build the message.converter jmod
+ // Tokens to pass to the run time --add-modules option
+ // SUCCESS or FAILURE expected
+ // Messages expected in the run time output
+ // Messages that must not appear in the run time output },
+ { "",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("hello world", "message.converter", "java.base"),
+ List.of("WARNING") },
+ { "--do-not-resolve-by-default",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_FAILURE,
+ List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+ List.of("WARNING", "message.converter") },
+ { "--warn-if-resolved=incubating",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("hello world", "message.converter", "java.base",
+ "WARNING: Using incubator modules: message.converter"),
+ List.of() },
+ { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_FAILURE,
+ List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+ List.of("WARNING", "message.converter") },
+ { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+ List.of("message.converter"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("hello world", "message.converter", "java.base", "WARNING"),
+ List.of() }
+ };
+ return values;
+ }
+
+ @Test(dataProvider = "singleModule")
+ public void singleModule(String extraJmodArg,
+ List<String> addModsTokens,
+ Consumer<ToolResult> assertExitCode,
+ List<String> expectedOutput,
+ List<String> unexpectedOutput)
+ throws Throwable
+ {
+ if (Files.notExists(JDK_JMODS)) {
+ System.out.println("JDK jmods not found test cannot run.");
+ return;
+ }
+
+ FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+ FileUtils.deleteFileTreeUnchecked(IMAGE);
+ Files.createDirectories(JMODS_DIR);
+ Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+ jmod("create",
+ "--class-path", MODS_DIR.resolve("message.converter").toString(),
+ extraJmodArg,
+ converterJmod.toString())
+ .assertSuccess();
+
+ String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+ jlink("--module-path", mpath,
+ "--add-modules", JAVA_BASE + ",message.converter",
+ "--output", IMAGE.toString())
+ .assertSuccess();
+
+ for (String addModsToken : addModsTokens) {
+ String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+ for (String systemProp : props)
+ java(IMAGE,
+ systemProp,
+ "--add-modules", addModsToken,
+ "-cp", CP_DIR.toString(),
+ "test.ConvertToLowerCase", "HEllo WoRlD")
+ .resultChecker(assertExitCode)
+ .resultChecker(r -> {
+ expectedOutput.forEach(e -> r.assertContains(e));
+ unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+ });
+ }
+ }
+
+ @Test
+ public void singleModularJar() throws Throwable {
+ FileUtils.deleteFileTreeUnchecked(JARS_DIR);
+ Files.createDirectories(JARS_DIR);
+ Path converterJar = JARS_DIR.resolve("converter.jar");
+
+ jar("--create",
+ "--file", converterJar.toString(),
+ "--warn-if-resolved=incubating",
+ "-C", MODS_DIR.resolve("message.converter").toString() , ".")
+ .assertSuccess();
+
+
+ java(Paths.get(JAVA_HOME),
+ "--module-path", JARS_DIR.toString(),
+ "--add-modules", "message.converter",
+ "-cp", CP_DIR.toString(),
+ "test.ConvertToLowerCase", "HEllo WoRlD")
+ .assertSuccess()
+ .resultChecker(r -> {
+ r.assertContains("WARNING: Using incubator modules: message.converter");
+ });
+ }
+
+ @DataProvider(name = "twoModules")
+ public Object[][] twoModulesValues() throws IOException {
+ Object[][] values = new Object[][]{
+ // { Extra args to the build the message.writer jmod
+ // Extra args to the build the message.converter jmod
+ // Tokens to pass to the run time --add-modules option
+ // SUCCESS or FAILURE expected
+ // Messages expected in the run time output
+ // Messages that must not appear in the run time output },
+ { "",
+ "",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+ List.of() },
+ { "",
+ "--do-not-resolve-by-default",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+ List.of() },
+ { "--do-not-resolve-by-default",
+ "",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_FAILURE,
+ List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+ List.of("message.writer") },
+ { "--do-not-resolve-by-default",
+ "--do-not-resolve-by-default",
+ List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+ ToolResult.ASSERT_FAILURE,
+ List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+ List.of("message.converter", "message.writer") },
+ // now add in warnings
+ { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+ "",
+ List.of("message.writer"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+ "WARNING: Using incubator modules: message.writer"),
+ List.of() },
+ { "",
+ "--do-not-resolve-by-default --warn-if-resolved=incubating",
+ List.of("message.writer"),
+ ToolResult.ASSERT_SUCCESS,
+ List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+ "WARNING: Using incubator modules: message.converter"),
+ List.of() } };
+ return values;
+ }
+
+ @Test(dataProvider = "twoModules")
+ public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg,
+ String extraSecondJmodArg,
+ List<String> addModsTokens,
+ Consumer<ToolResult> assertExitCode,
+ List<String> expectedOutput,
+ List<String> unexpectedOutput)
+ throws Throwable
+ {
+ if (Files.notExists(JDK_JMODS)) {
+ System.out.println("JDK jmods not found test cannot run.");
+ return;
+ }
+
+ FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+ FileUtils.deleteFileTreeUnchecked(IMAGE);
+ Files.createDirectories(JMODS_DIR);
+ Path writerJmod = JMODS_DIR.resolve("writer.jmod");
+ Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+ jmod("create",
+ extraFirstJmodArg,
+ "--class-path", MODS_DIR.resolve("message.writer").toString(),
+ writerJmod.toString());
+
+ jmod("create",
+ "--class-path", MODS_DIR.resolve("message.converter").toString(),
+ extraSecondJmodArg,
+ converterJmod.toString())
+ .assertSuccess();
+
+ String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+ jlink("--module-path", mpath,
+ "--add-modules", JAVA_BASE + ",message.writer,message.converter",
+ "--output", IMAGE.toString())
+ .assertSuccess();
+
+ for (String addModsToken : addModsTokens) {
+ String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+ for (String systemProp : props)
+ java(IMAGE,
+ systemProp,
+ "--add-modules", addModsToken,
+ "-cp", CP_DIR.toString(),
+ "test.WriteUpperCase", "hello chegar !!!")
+ .resultChecker(assertExitCode)
+ .resultChecker(r -> {
+ expectedOutput.forEach(e -> r.assertContains(e));
+ unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+ });
+ }
+ }
+
+ static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
+ .orElseThrow(() -> new RuntimeException("jmod tool not found"));
+ static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+ .orElseThrow(() -> new RuntimeException("jar tool not found"));
+ static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+ .orElseThrow(() -> new RuntimeException("jlink tool not found"));
+
+ static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); }
+
+ static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); }
+
+ static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); }
+
+ static ToolResult java(Path image, String... opts) throws Throwable {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ String[] options = Stream.concat(Stream.of(getJava(image)),
+ Stream.of(opts).filter(s -> !s.equals("")))
+ .toArray(String[]::new);
+
+ ProcessBuilder pb = new ProcessBuilder(options);
+ int exitValue = executeCommand(pb).outputTo(ps)
+ .errorTo(ps)
+ .getExitValue();
+
+ return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+ }
+
+ static ToolResult execTool(ToolProvider tool, String... args) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ List<String> filteredArgs = Stream.of(args)
+ .map(s -> s.split(" ")).flatMap(Stream::of)
+ .filter(s -> !s.equals(""))
+ .collect(Collectors.toList());
+ System.out.println(tool + " " + filteredArgs);
+ int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {}));
+ return new ToolResult(ec, new String(baos.toByteArray(), UTF_8));
+ }
+
+ static class ToolResult {
+ final int exitCode;
+ final String output;
+
+ ToolResult(int exitValue, String output) {
+ this.exitCode = exitValue;
+ this.output = output;
+ }
+
+ static Consumer<ToolResult> ASSERT_SUCCESS = r ->
+ assertEquals(r.exitCode, 0,
+ "Expected exit code 0, got " + r.exitCode
+ + ", with output[" + r.output + "]");
+ static Consumer<ToolResult> ASSERT_FAILURE = r ->
+ assertNotEquals(r.exitCode, 0,
+ "Expected exit code != 0, got " + r.exitCode
+ + ", with output[" + r.output + "]");
+
+ ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; }
+ ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; }
+ ToolResult resultChecker(Consumer<ToolResult> r) { r.accept(this); return this; }
+
+ ToolResult assertContains(String subString) {
+ assertTrue(output.contains(subString),
+ "Expected to find [" + subString + "], in output ["
+ + output + "]" + "\n");
+ return this;
+ }
+ ToolResult assertDoesNotContains(String subString) {
+ assertFalse(output.contains(subString),
+ "Expected to NOT find [" + subString + "], in output ["
+ + output + "]" + "\n");
+ return this;
+ }
+ }
+
+ static String getJava(Path image) {
+ boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+ Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+ if (Files.notExists(java))
+ throw new RuntimeException(java + " not found");
+ return java.toAbsolutePath().toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/listmods/ListModules.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * 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 listmods;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ListModules {
+ public static void main(String[] args) throws Exception {
+ System.out.println(Layer.boot()
+ .modules()
+ .stream()
+ .map(Module::getName)
+ .sorted()
+ .collect(joining("\n")));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * 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 test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ConvertToLowerCase {
+ public static void main(String[] args) {
+ System.out.println(Layer.boot()
+ .modules()
+ .stream()
+ .map(Module::getName)
+ .sorted()
+ .collect(joining("\n")));
+ System.out.println(converter.MessageConverter.toLowerCase(args[0]));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * 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 test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class WriteUpperCase {
+ public static void main(String[] args) {
+ System.out.println(Layer.boot()
+ .modules()
+ .stream()
+ .map(Module::getName)
+ .sorted()
+ .collect(joining("\n")));
+ writer.MessageWriter.writeOn(args[0], System.out);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/converter/MessageConverter.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * 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 converter;
+
+public class MessageConverter {
+ public static String toUpperCase(String message) {
+ return message.toUpperCase(java.util.Locale.ROOT);
+ }
+
+ public static String toLowerCase(String message) {
+ return message.toLowerCase(java.util.Locale.ROOT);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/module-info.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module message.converter {
+ exports converter;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/module-info.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+module message.writer {
+ requires message.converter;
+ exports writer;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/writer/MessageWriter.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * 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 writer;
+
+import java.io.PrintStream;
+import java.util.Locale;
+
+public class MessageWriter {
+ public static void writeOn(String message, PrintStream out) {
+ String newMesssage = converter.MessageConverter.toUpperCase(message);
+ if (!newMesssage.equals(message.toUpperCase(Locale.ROOT)))
+ throw new RuntimeException("Expected " + message.toUpperCase(Locale.ROOT)
+ + ", got " + newMesssage );
+
+ out.println(newMesssage);
+ }
+}
--- a/jdk/test/lib/testlibrary/ModuleUtils.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/lib/testlibrary/ModuleUtils.java Mon Dec 19 16:05:38 2016 +0000
@@ -32,7 +32,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.Supplier;
/**
@@ -58,12 +57,13 @@
URI uri = URI.create("module:/" + name);
- Supplier<ModuleReader> supplier = () -> {
- throw new UnsupportedOperationException();
+ ModuleReference mref = new ModuleReference(descriptor, uri) {
+ @Override
+ public ModuleReader open() {
+ throw new UnsupportedOperationException();
+ }
};
- ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-
namesToReference.put(name, mref);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/InvokeCleaner.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/* @test
+ * @bug 8171377
+ * @summary Basic test for Unsafe::invokeCleaner
+ * @modules jdk.unsupported
+ * @run testng/othervm InvokeCleaner
+ */
+
+import java.io.Closeable;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import sun.misc.Unsafe;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+public class InvokeCleaner {
+
+ static Unsafe UNSAFE;
+ static Path bob = Paths.get("bob");
+ static List<Closeable> closeables = new ArrayList<>();
+
+ @BeforeClass
+ static void init() throws Exception {
+ UNSAFE = getUnsafe();
+
+ byte[] srcData = new byte[20];
+ for (int i=0; i<20; i++)
+ srcData[i] = (byte)i;
+ Files.write(bob, srcData);
+ }
+
+ @DataProvider(name = "badBuffers")
+ static Object[][] createBadBuffers() throws Exception {
+ FileChannel fc = FileChannel.open(bob);
+ closeables.add(fc);
+ MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+
+ return new Object[][] {
+ { ByteBuffer.allocate(0) },
+ { ByteBuffer.allocate(10) },
+ { ByteBuffer.allocate(10).duplicate() },
+ { ByteBuffer.allocate(10).slice() },
+ { ByteBuffer.allocateDirect(10).duplicate() },
+ { ByteBuffer.allocateDirect(10).slice() },
+ { ByteBuffer.allocateDirect(0).duplicate() },
+ { ByteBuffer.allocateDirect(0).slice() },
+ { mbb.duplicate() },
+ { mbb.slice() }
+ };
+ }
+
+ @Test(dataProvider="badBuffers",
+ expectedExceptions = IllegalArgumentException.class)
+ public void badBuffers(ByteBuffer buffer) throws Exception {
+ UNSAFE.invokeCleaner(buffer);
+ }
+
+ @DataProvider(name = "goodBuffers")
+ static Object[][] createGoodBuffers() throws Exception {
+ FileChannel fc = FileChannel.open(bob);
+ closeables.add(fc);
+ MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+ mbb.load();
+
+ return new Object[][] {
+ { ByteBuffer.allocateDirect(0) },
+ { ByteBuffer.allocateDirect(10) },
+ { mbb },
+ { fc.map(FileChannel.MapMode.READ_ONLY, 1, 11) }
+ };
+ }
+
+ @Test(dataProvider="goodBuffers")
+ public void goodBuffers(ByteBuffer buffer) throws Exception {
+ UNSAFE.invokeCleaner(buffer);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void npe() throws Exception {
+ UNSAFE.invokeCleaner(null);
+ }
+
+ static Unsafe getUnsafe() throws ReflectiveOperationException {
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ return (Unsafe)f.get(null);
+ }
+
+ @AfterClass
+ public void cleanup() throws Exception {
+ for(Closeable fc : closeables)
+ fc.close();
+ }
+}
--- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Mon Dec 19 16:05:38 2016 +0000
@@ -23,10 +23,12 @@
/*
* @test
- * @bug 6578647 6829283
+ * @bug 6578647 6829283 8171340
* @run main/othervm HttpNegotiateServer
- * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
- * @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
+ * @summary Undefined requesting URL in java.net.Authenticator
+ * .getPasswordAuthentication()
+ * @summary HTTP/Negotiate: Authenticator triggered again when
+ * user cancels the first one
*/
import com.sun.net.httpserver.Headers;
@@ -240,16 +242,15 @@
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
reader = new BufferedReader(new InputStreamReader(
- webUrl.openConnection().getInputStream()));
+ webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
if (!reader.readLine().equals(CONTENT)) {
throw new RuntimeException("Bad content");
}
reader = new BufferedReader(new InputStreamReader(
- proxyUrl.openConnection(
- new Proxy(Proxy.Type.HTTP,
- new InetSocketAddress(PROXY_HOST, proxyPort)))
- .getInputStream()));
+ proxyUrl.openConnection(new Proxy(Proxy.Type.HTTP,
+ new InetSocketAddress(PROXY_HOST, proxyPort)))
+ .getInputStream()));
if (!reader.readLine().equals(CONTENT)) {
throw new RuntimeException("Bad content");
}
@@ -260,7 +261,7 @@
java.net.Authenticator.setDefault(new KnowNothingAuthenticator());
try {
new BufferedReader(new InputStreamReader(
- webUrl.openConnection().getInputStream()));
+ webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
} catch (IOException ioe) {
// Will fail since no username and password is provided.
}
@@ -274,7 +275,7 @@
try {
URL url = webUrl;
- URLConnection conn = url.openConnection();
+ URLConnection conn = url.openConnection(Proxy.NO_PROXY);
conn.connect();
inputStream = conn.getInputStream();
byte[] b = new byte[inputStream.available()];
@@ -285,7 +286,7 @@
System.out.println("Length: " + s.length());
System.out.println(s);
} catch (Exception ex) {
- throw new RuntimeException(ex);
+ throw new RuntimeException(ex);
} finally {
if (inputStream != null) {
try {
@@ -307,7 +308,8 @@
CallbackHandler callback = new CallbackHandler() {
@Override
- public void handle(Callback[] pCallbacks) throws IOException, UnsupportedCallbackException {
+ public void handle(Callback[] pCallbacks)
+ throws IOException, UnsupportedCallbackException {
for (Callback cb : pCallbacks) {
if (cb instanceof NameCallback) {
NameCallback ncb = (NameCallback)cb;
@@ -323,7 +325,8 @@
};
final String jaasConfigName = "oracle.test.kerberos.login";
- final String krb5LoginModule = "com.sun.security.auth.module.Krb5LoginModule";
+ final String krb5LoginModule
+ = "com.sun.security.auth.module.Krb5LoginModule";
Configuration loginConfig = new Configuration() {
@Override
@@ -347,7 +350,8 @@
// oracle context/subject/login
LoginContext context = null;
try {
- context = new LoginContext("oracle.test.kerberos.login", null, callback, loginConfig);
+ context = new LoginContext(
+ "oracle.test.kerberos.login", null, callback, loginConfig);
context.login();
} catch (LoginException ex) {
@@ -358,29 +362,35 @@
Subject subject = context.getSubject();
- final PrivilegedExceptionAction<Object> test_action = new PrivilegedExceptionAction<Object>() {
+ final PrivilegedExceptionAction<Object> test_action
+ = new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
testConnect();
return null;
}
};
- System.err.println("\n\nExpecting to succeed when executing with the the logged in subject.");
+ System.err.println("\n\nExpecting to succeed when executing " +
+ "with the the logged in subject.");
try {
Subject.doAs(subject, test_action);
- System.err.println("\n\nConnection succeed when executing with the the logged in subject.");
+ System.err.println("\n\nConnection succeed when executing " +
+ "with the the logged in subject.");
} catch (PrivilegedActionException e) {
- System.err.println("\n\nFailure unexpected when executing with the the logged in subject.");
+ System.err.println("\n\nFailure unexpected when executing " +
+ "with the the logged in subject.");
e.printStackTrace();
throw new RuntimeException("Failed to login as subject");
}
try {
- System.err.println("\n\nExpecting to fail when running with the current user's login.");
+ System.err.println("\n\nExpecting to fail when running " +
+ "with the current user's login.");
testConnect();
} catch (Exception ex) {
- System.err.println("\nConnect failed when running with the current user's login:\n" + ex.getMessage());
+ System.err.println("\nConnect failed when running " +
+ "with the current user's login:\n" + ex.getMessage());
}
}
@@ -450,8 +460,9 @@
return m.createCredential(
null,
GSSCredential.INDEFINITE_LIFETIME,
- MyServerAuthenticator.this.scheme.equalsIgnoreCase("Negotiate")?
- GSSUtil.GSS_SPNEGO_MECH_OID:
+ MyServerAuthenticator.this.scheme
+ .equalsIgnoreCase("Negotiate") ?
+ GSSUtil.GSS_SPNEGO_MECH_OID :
GSSUtil.GSS_KRB5_MECH_OID,
GSSCredential.ACCEPT_ONLY);
}
@@ -465,7 +476,8 @@
GSSContext c = null;
String auth = exch.getRequestHeaders().getFirst(respHdr);
try {
- c = (GSSContext)exch.getHttpContext().getAttributes().get("GSSContext");
+ c = (GSSContext)exch.getHttpContext()
+ .getAttributes().get("GSSContext");
if (auth == null) { // First request
Headers map = exch.getResponseHeaders();
map.set (reqHdr, scheme); // Challenge!
@@ -478,7 +490,8 @@
exch.getHttpContext().getAttributes().put("GSSContext", c);
return new com.sun.net.httpserver.Authenticator.Retry(err);
} else { // Later requests
- byte[] token = Base64.getMimeDecoder().decode(auth.split(" ")[1]);
+ byte[] token = Base64.getMimeDecoder()
+ .decode(auth.split(" ")[1]);
token = c.acceptSecContext(token, 0, token.length);
Headers map = exch.getResponseHeaders();
map.set (reqHdr, scheme + " " + Base64.getMimeEncoder()
--- a/jdk/test/tools/jar/compat/CLICompatibility.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jar/compat/CLICompatibility.java Mon Dec 19 16:05:38 2016 +0000
@@ -43,6 +43,7 @@
import static java.lang.String.format;
import static java.lang.System.out;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
/*
@@ -428,10 +429,12 @@
jar("--help")
.assertSuccess()
- .resultChecker(r ->
+ .resultChecker(r -> {
assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
- "Failed, got [" + r.output + "]")
- );
+ "Failed, got [" + r.output + "]");
+ assertFalse(r.output.contains("--do-not-resolve-by-default"));
+ assertFalse(r.output.contains("--warn-if-resolved"));
+ });
jar("--help:compat")
.assertSuccess()
@@ -439,6 +442,15 @@
assertTrue(r.output.startsWith("Compatibility Interface:"),
"Failed, got [" + r.output + "]")
);
+
+ jar("--help-extra")
+ .assertSuccess()
+ .resultChecker(r -> {
+ assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
+ "Failed, got [" + r.output + "]");
+ assertTrue(r.output.contains("--do-not-resolve-by-default"));
+ assertTrue(r.output.contains("--warn-if-resolved"));
+ });
}
// -- Infrastructure
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Mon Dec 19 16:05:38 2016 +0000
@@ -25,16 +25,18 @@
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Module;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.HashSet;
import java.util.Set;
-
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
import jdk.test.bar.internal.Message;
public class Bar {
@@ -71,9 +73,14 @@
if (!sj.toString().equals(""))
System.out.println("contains:" + sj.toString());
- ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
- JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
- Optional<ModuleHashes> oHashes = jlma.hashes(foo);
- System.out.println("hashes:" + oHashes.get().hashFor("bar"));
+
+ Module foo = jdk.test.foo.Foo.class.getModule();
+ Optional<ResolvedModule> om = foo.getLayer().configuration().findModule(foo.getName());
+ assert om.isPresent();
+ ModuleReference mref = om.get().reference();
+ assert mref instanceof ModuleReferenceImpl;
+ ModuleHashes hashes = ((ModuleReferenceImpl) mref).recordedHashes();
+ assert hashes != null;
+ System.out.println("hashes:" + hashes.hashFor("bar"));
}
}
--- a/jdk/test/tools/jimage/VerifyJimage.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jimage/VerifyJimage.java Mon Dec 19 16:05:38 2016 +0000
@@ -49,7 +49,7 @@
* @test
* @summary Verify jimage
* @modules java.base/jdk.internal.jimage
- * @run main/othervm --add-modules=ALL-SYSTEM VerifyJimage
+ * @run main/othervm --add-modules=ALL-SYSTEM,jdk.incubator.httpclient VerifyJimage
*/
/**
--- a/jdk/test/tools/jlink/IntegrationTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/IntegrationTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -186,7 +186,7 @@
lst.add(new MyPostProcessor());
}
// Image builder
- DefaultImageBuilder builder = new DefaultImageBuilder(output);
+ DefaultImageBuilder builder = new DefaultImageBuilder(output, Collections.emptyMap());
PluginsConfiguration plugins
= new Jlink.PluginsConfiguration(lst, builder, null);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/ReleaseImplementorTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+/*
+ * @test
+ * @bug 8171316
+ * @summary Add IMPLEMENTOR property to the release file
+ * @run main ReleaseImplementorTest
+ */
+public class ReleaseImplementorTest {
+ public static void main(String[] args) throws Exception {
+ Properties props = new Properties();
+ Path release = Paths.get(System.getProperty("test.jdk"), "release");
+ try (InputStream in = Files.newInputStream(release)) {
+ props.load(in);
+ }
+
+ if (!props.containsKey("IMPLEMENTOR")) {
+ throw new RuntimeException("IMPLEMENTOR key is missing");
+ }
+
+ String implementor = props.getProperty("IMPLEMENTOR");
+ if (implementor.length() < 3) {
+ throw new RuntimeException("IMPLEMENTOR value is not expected length");
+ }
+
+ if (implementor.charAt(0) != '"' ||
+ implementor.charAt(implementor.length() - 1) != '"') {
+ throw new RuntimeException("IMPLEMENTOR value not quoted property");
+ }
+
+ System.out.println("IMPLEMENTOR is " + implementor);
+ }
+}
--- a/jdk/test/tools/jlink/basic/BasicTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/basic/BasicTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -87,20 +87,29 @@
JarUtils.createJarFile(jarfile, classes);
Path image = Paths.get("mysmallimage");
- runJmod(jarfile.toString(), TEST_MODULE);
- runJlink(image, TEST_MODULE, "--compress", "2");
- execute(image, TEST_MODULE);
+ runJmod(jarfile.toString(), TEST_MODULE, true);
+ runJlink(image, TEST_MODULE, "--compress", "2", "--launcher", "foo=" + TEST_MODULE);
+ execute(image, "foo");
Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
image = Paths.get("myimage");
- runJmod(classes.toString(), TEST_MODULE);
- runJlink(image, TEST_MODULE);
- execute(image, TEST_MODULE);
+ runJmod(classes.toString(), TEST_MODULE, true);
+ runJlink(image, TEST_MODULE, "--launcher", "bar=" + TEST_MODULE);
+ execute(image, "bar");
+
+ Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
+
+ image = Paths.get("myimage2");
+ runJmod(classes.toString(), TEST_MODULE, false /* no ModuleMainClass! */);
+ // specify main class in --launcher command line
+ runJlink(image, TEST_MODULE, "--launcher", "bar2=" + TEST_MODULE + "/jdk.test.Test");
+ execute(image, "bar2");
+
}
- private void execute(Path image, String moduleName) throws Throwable {
- String cmd = image.resolve("bin").resolve(moduleName).toString();
+ private void execute(Path image, String scriptName) throws Throwable {
+ String cmd = image.resolve("bin").resolve(scriptName).toString();
OutputAnalyzer analyzer;
if (System.getProperty("os.name").startsWith("Windows")) {
analyzer = ProcessTools.executeProcess("sh.exe", cmd, "1", "2", "3");
@@ -127,14 +136,25 @@
}
}
- private void runJmod(String cp, String modName) {
- int rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+ private void runJmod(String cp, String modName, boolean main) {
+ int rc;
+ if (main) {
+ rc = JMOD_TOOL.run(System.out, System.out, new String[] {
"create",
"--class-path", cp,
"--module-version", "1.0",
"--main-class", "jdk.test.Test",
+ jmods.resolve(modName + ".jmod").toString()
+ });
+ } else {
+ rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+ "create",
+ "--class-path", cp,
+ "--module-version", "1.0",
jmods.resolve(modName + ".jmod").toString(),
- });
+ });
+ }
+
if (rc != 0) {
throw new AssertionError("Jmod failed: rc = " + rc);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import static jdk.testlibrary.ProcessTools.*;
+
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jlink
+ * @build CompiledVersionTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
+ * @run testng CompiledVersionTest
+ */
+
+public class CompiledVersionTest {
+ private static final String JAVA_HOME = System.getProperty("java.home");
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+ private static final Path IMAGE = Paths.get("image");
+ private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+ private static final String MAIN_MID = "test/jdk.test.Main";
+
+ // the names of the modules in this test
+ private static String[] modules = new String[] { "m1", "m2", "test"};
+ private static String[] versions = new String[] { "1.0", "2-ea", "3-internal"};
+
+
+ private static boolean hasJmods() {
+ if (!Files.exists(JMODS)) {
+ System.err.println("Test skipped. NO jmods directory");
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * Compiles all modules used by the test
+ */
+ @BeforeTest
+ public void compileAll() throws Throwable {
+ if (!hasJmods()) return;
+
+ for (int i=0; i < modules.length; i++) {
+ String mn = modules[i];
+ String version = versions[i];
+ Path msrc = SRC_DIR.resolve(mn);
+ if (version.equals("0")) {
+ assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+ "--module-source-path", SRC_DIR.toString()));
+ } else {
+ assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+ "--module-source-path", SRC_DIR.toString(),
+ "--module-version", version));
+ }
+ }
+
+ if (Files.exists(IMAGE)) {
+ FileUtils.deleteFileTreeUnchecked(IMAGE);
+ }
+
+ createImage(IMAGE, modules);
+ }
+
+ private void createImage(Path outputDir, String... modules) throws Throwable {
+ Path jlink = Paths.get(JAVA_HOME, "bin", "jlink");
+ String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString();
+ assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(),
+ "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
+ "--module-path", mp)
+ .outputTo(System.out)
+ .errorTo(System.out)
+ .getExitValue() == 0);
+ }
+
+ /*
+ * Test the image created when linking with a module with
+ * no Packages attribute
+ */
+ @Test
+ public void testCompiledVersions() throws Throwable {
+ if (!hasJmods()) return;
+
+ Path java = IMAGE.resolve("bin").resolve("java");
+ Stream<String> options = Stream.concat(
+ Stream.of(java.toString(), "-m", MAIN_MID, String.valueOf(modules.length)),
+ Stream.concat(Arrays.stream(modules), Arrays.stream(versions))
+ );
+
+ assertTrue(executeProcess(options.toArray(String[]::new))
+ .outputTo(System.out)
+ .errorTo(System.out)
+ .getExitValue() == 0);
+ }
+}
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -59,7 +59,7 @@
private void testModuleDescriptor(ModuleDescriptor md) {
assertUnmodifiable(md.packages(), "package");
assertUnmodifiable(md.requires(),
- jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
+ jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require", null));
for (Requires req : md.requires()) {
assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
}
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -39,7 +39,7 @@
/**
* @test
* @library /lib/testlibrary
- * @modules jdk.compiler
+ * @modules jdk.compiler jdk.jlink
* @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
* @run testng UserModuleTest
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * 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.test;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+
+/*
+ * Main class to verify if ModuleDescriptor carries the correct version
+ */
+public class Main {
+ static final Map<String, String> nameToVersion = new HashMap<>();
+
+ // jdk.test.Main $count $module-name... $version...
+ public static void main(String... args) throws Exception {
+ int count = args.length > 0 ? Integer.valueOf(args[0]) : 0;
+ if (count < 1 || args.length != count*2+1) {
+ throw new IllegalArgumentException(Arrays.toString(args));
+ }
+
+ List<String> modules = List.of(Arrays.copyOfRange(args, 1, 1+count));
+ List<String> versions = List.of(Arrays.copyOfRange(args, 1+count, args.length));
+ for (int i=0; i < modules.size(); i++) {
+ System.out.format("module %s expects %s version%n",
+ modules.get(i), versions.get(i));
+ nameToVersion.put(modules.get(i), versions.get(i));
+ }
+
+ FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
+ Collections.emptyMap());
+ // check the module descriptor of a system module
+ for (int i=0; i < modules.size(); i++) {
+ String mn = modules.get(i);
+ Module module = Layer.boot().findModule(mn).orElseThrow(
+ () -> new RuntimeException(mn + " not found")
+ );
+
+ // check ModuleDescriptor from the run-time
+ validate(module.getDescriptor());
+
+ // check module-info.class in the image
+ Path path = fs.getPath("/", "modules", modules.get(i), "module-info.class");
+ validate(ModuleDescriptor.read(Files.newInputStream(path)));
+ }
+ }
+
+ static void validate(ModuleDescriptor descriptor) {
+ checkVersion(descriptor.name(), descriptor.version());
+ descriptor.requires()
+ .stream()
+ .filter(r -> !r.name().equals("java.base"))
+ .forEach(r -> checkVersion(r.name(), r.compiledVersion()));
+ }
+
+ static void checkVersion(String mn, Optional<ModuleDescriptor.Version> version) {
+ boolean matched;
+ String v = nameToVersion.get(mn);
+ if (version.isPresent()) {
+ matched = version.get().toString().equals(v);
+ } else {
+ // 0 indicate no version
+ matched = v.equals("0");
+ }
+
+ if (!matched) {
+ throw new RuntimeException(mn + " mismatched version " + version
+ + " expected: " + v);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/module-info.java Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+module test {
+ requires m1;
+ requires m2;
+ exports jdk.test;
+}
--- a/jdk/test/tools/jmod/JmodTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jmod/JmodTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -470,9 +470,22 @@
public void testHelp() {
jmod("--help")
.assertSuccess()
- .resultChecker(r ->
- assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed")
- );
+ .resultChecker(r -> {
+ assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");
+ assertFalse(r.output.contains("--do-not-resolve-by-default"));
+ assertFalse(r.output.contains("--warn-if-resolved"));
+ });
+ }
+
+ @Test
+ public void testHelpExtra() {
+ jmod("--help-extra")
+ .assertSuccess()
+ .resultChecker(r -> {
+ assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");
+ assertContains(r.output, "--do-not-resolve-by-default");
+ assertContains(r.output, "--warn-if-resolved");
+ });
}
@Test
--- a/jdk/test/tools/jmod/hashes/HashesTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jmod/hashes/HashesTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -50,14 +50,13 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.module.ModuleInfo;
import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModulePath;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
@@ -103,54 +102,53 @@
@Test
public void test() throws Exception {
for (String mn : modules) {
- assertFalse(hashes(mn).isPresent());
+ assertTrue(hashes(mn) == null);
}
// hash m1 in m2
jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1");
- checkHashes(hashes("m2").get(), "m1");
+ checkHashes(hashes("m2"), "m1");
// hash m1 in m2
jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*");
- checkHashes(hashes("m2").get(), "m1");
+ checkHashes(hashes("m2"), "m1");
// create m2.jmod with no hash
jmod("m2");
// run jmod hash command to hash m1 in m2 and m3
runJmod(Arrays.asList("hash", "--module-path", jmods.toString(),
"--hash-modules", ".*"));
- checkHashes(hashes("m2").get(), "m1");
- checkHashes(hashes("m3").get(), "m1");
+ checkHashes(hashes("m2"), "m1");
+ checkHashes(hashes("m3"), "m1");
jmod("org.bar");
jmod("org.foo");
jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*");
- checkHashes(hashes("org.bar").get(), "org.foo");
+ checkHashes(hashes("org.bar"), "org.foo");
jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*");
- checkHashes(hashes("m3").get(), "org.foo", "org.bar", "m1");
+ checkHashes(hashes("m3"), "org.foo", "org.bar", "m1");
}
private void checkHashes(ModuleHashes hashes, String... hashModules) {
assertTrue(hashes.names().equals(Set.of(hashModules)));
}
- private Optional<ModuleHashes> hashes(String name) throws Exception {
- ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
- .newModulePath(Runtime.version(), true, jmods.resolve(name + ".jmod"));
+ private ModuleHashes hashes(String name) throws Exception {
+ ModuleFinder finder = new ModulePath(Runtime.version(),
+ true,
+ jmods.resolve(name + ".jmod"));
ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
ModuleReader reader = mref.open();
try (InputStream in = reader.open("module-info.class").get()) {
- ModuleDescriptor md = ModuleDescriptor.read(in);
- JavaLangModuleAccess jmla = SharedSecrets.getJavaLangModuleAccess();
- Optional<ModuleHashes> hashes = jmla.hashes(md);
+ ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
System.out.format("hashes in module %s %s%n", name,
- hashes.isPresent() ? "present" : "absent");
- if (hashes.isPresent()) {
- hashes.get().names().stream()
+ (hashes != null) ? "present" : "absent");
+ if (hashes != null) {
+ hashes.names().stream()
.sorted()
- .forEach(n -> System.out.format(" %s %s%n", n, hashes.get().hashFor(n)));
+ .forEach(n -> System.out.format(" %s %s%n", n, hashes.hashFor(n)));
}
return hashes;
} finally {
--- a/jdk/test/tools/launcher/RunpathTest.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/launcher/RunpathTest.java Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -64,7 +64,7 @@
}
void testRpath() {
- String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib/" + getJreArch() + ".*";
+ String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib.*";
elfCheck(javaCmd, expectedRpath);
}
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Mon Dec 19 16:05:38 2016 +0000
@@ -41,6 +41,8 @@
import com.sun.tools.classfile.CompilationID_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
@@ -80,9 +82,9 @@
import com.sun.tools.classfile.ModuleHashes_attribute;
import com.sun.tools.classfile.ModuleHashes_attribute.Entry;
import com.sun.tools.classfile.ModuleMainClass_attribute;
+import com.sun.tools.classfile.ModuleResolution_attribute;
import com.sun.tools.classfile.ModuleTarget_attribute;
import com.sun.tools.classfile.ModulePackages_attribute;
-import com.sun.tools.classfile.ModuleVersion_attribute;
import com.sun.tools.classfile.Opcode;
import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -670,6 +672,40 @@
}
@Override
+ public String visitModule(CONSTANT_Module_info info, Integer p) {
+ String value = slist.get(p);
+ if (value == null) {
+ try {
+ value = visit(cfpool.get(info.name_index), info.name_index);
+ slist.set(p, value);
+ xpool.add(new Element("CONSTANT_Module",
+ new String[]{"id", p.toString()},
+ value));
+ } catch (ConstantPoolException ex) {
+ ex.printStackTrace();
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public String visitPackage(CONSTANT_Package_info info, Integer p) {
+ String value = slist.get(p);
+ if (value == null) {
+ try {
+ value = visit(cfpool.get(info.name_index), info.name_index);
+ slist.set(p, value);
+ xpool.add(new Element("CONSTANT_Package",
+ new String[]{"id", p.toString()},
+ value));
+ } catch (ConstantPoolException ex) {
+ ex.printStackTrace();
+ }
+ }
+ return value;
+ }
+
+ @Override
public String visitDouble(CONSTANT_Double_info c, Integer p) {
String value = slist.get(p);
if (value == null) {
@@ -1495,20 +1531,20 @@
}
@Override
- public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
- Element e = new Element(x.getCpString(attr.attribute_name_index));
- e.add(x.getCpString(attr.os_name_index));
- e.add(x.getCpString(attr.os_arch_index));
- e.add(x.getCpString(attr.os_version_index));
+ public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) {
+ Element e = new Element("ModuleResolution");
+ e.setAttr("flags", Integer.toString(attr.resolution_flags));
e.trimToSize();
p.add(e);
return null;
}
@Override
- public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
+ public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
Element e = new Element(x.getCpString(attr.attribute_name_index));
- e.add(x.getCpString(attr.version_index));
+ e.add(x.getCpString(attr.os_name_index));
+ e.add(x.getCpString(attr.os_arch_index));
+ e.add(x.getCpString(attr.os_version_index));
e.trimToSize();
p.add(e);
return null;