--- a/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -380,3 +380,4 @@
e384420383a5b79fa0012ebcb25d8f83cff7f777 jdk-9+135
1b4b5d01aa11edf24b6fadbe3d2f3e411e3b02cd jdk-9+136
9cb87c88ed851c0575b8ead753ea238ed5b544e9 jdk-9+137
+d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138
--- a/.hgtags-top-repo Fri Sep 30 02:52:42 2016 -0700
+++ b/.hgtags-top-repo Wed Oct 05 06:28:23 2016 -0700
@@ -380,3 +380,4 @@
82b94cb5f342319d2cda77f9fa59703ad7fde576 jdk-9+135
3ec350f5f32af249b59620d7e37b54bdcd77b233 jdk-9+136
d7f519b004254b19e384131d9f0d0e40e31a0fd3 jdk-9+137
+67c4388142bdf58aec8fefa4475faaa8a5d7380c jdk-9+138
--- a/common/autoconf/buildjdk-spec.gmk.in Fri Sep 30 02:52:42 2016 -0700
+++ b/common/autoconf/buildjdk-spec.gmk.in Wed Oct 05 06:28:23 2016 -0700
@@ -33,6 +33,7 @@
CC := @BUILD_CC@
CXX := @BUILD_CXX@
LD := @BUILD_LD@
+LDCXX := @BUILD_LDCXX@
AS := @BUILD_AS@
NM := @BUILD_NM@
AR := @BUILD_AR@
--- a/common/autoconf/generated-configure.sh Fri Sep 30 02:52:42 2016 -0700
+++ b/common/autoconf/generated-configure.sh Wed Oct 05 06:28:23 2016 -0700
@@ -687,7 +687,6 @@
MSVCP_DLL
MSVCR_DLL
LIBCXX
-STATIC_CXX_SETTING
FIXPATH_DETACH_FLAG
FIXPATH
BUILD_GTEST
@@ -5092,7 +5091,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1474894604
+DATE_WHEN_GENERATED=1475218974
###############################################################################
#
@@ -53087,49 +53086,10 @@
if test "x$OPENJDK_TARGET_OS" = xlinux; then
- # Test if -lstdc++ works.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if dynamic link of stdc++ is possible" >&5
-$as_echo_n "checking if dynamic link of stdc++ is possible... " >&6; }
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- OLD_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS -lstdc++"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
- has_dynamic_libstdcxx=yes
-else
- has_dynamic_libstdcxx=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- CXXFLAGS="$OLD_CXXFLAGS"
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_dynamic_libstdcxx" >&5
-$as_echo "$has_dynamic_libstdcxx" >&6; }
-
# Test if stdc++ can be linked statically.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if static link of stdc++ is possible" >&5
$as_echo_n "checking if static link of stdc++ is possible... " >&6; }
- STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic"
+ STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc"
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -53137,9 +53097,7 @@
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
OLD_LIBS="$LIBS"
- OLD_CXX="$CXX"
LIBS="$STATIC_STDCXX_FLAGS"
- CXX="$CC"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -53159,7 +53117,6 @@
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS="$OLD_LIBS"
- CXX="$OLD_CXX"
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -53169,59 +53126,34 @@
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_static_libstdcxx" >&5
$as_echo "$has_static_libstdcxx" >&6; }
- if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then
- as_fn_error $? "Cannot link to stdc++, neither dynamically nor statically!" "$LINENO" 5
- fi
-
if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then
as_fn_error $? "Static linking of libstdc++ was not possible!" "$LINENO" 5
fi
- if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then
- as_fn_error $? "Dynamic linking of libstdc++ was not possible!" "$LINENO" 5
- fi
-
# If dynamic was requested, it's available since it would fail above otherwise.
# If dynamic wasn't requested, go with static unless it isn't available.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libstdc++" >&5
$as_echo_n "checking how to link with libstdc++... " >&6; }
- if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
- LIBCXX="$LIBCXX -lstdc++"
- # To help comparisons with old build, put stdc++ first in JVM_LIBS
- JVM_LIBS="-lstdc++ $JVM_LIBS"
- # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
- # just use the same setting as for the TARGET toolchain.
- OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS"
- LDCXX="$CXX"
- STATIC_CXX_SETTING="STATIC_CXX=false"
+ if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \
+ || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: dynamic" >&5
$as_echo "dynamic" >&6; }
else
LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS"
- JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc"
- # To help comparisons with old build, put stdc++ first in JVM_LIBS
- JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS"
+ JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
# Ideally, we should test stdc++ for the BUILD toolchain separately. For now
# just use the same setting as for the TARGET toolchain.
- OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc"
- OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS"
- LDCXX="$CC"
- STATIC_CXX_SETTING="STATIC_CXX=true"
+ OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5
$as_echo "static" >&6; }
fi
fi
-
# libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so)
if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then
LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1"
fi
- # TODO better (platform agnostic) test
- if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then
- LIBCXX="-lstdc++"
- fi
# Setup Windows runtime dlls
--- a/common/autoconf/lib-std.m4 Fri Sep 30 02:52:42 2016 -0700
+++ b/common/autoconf/lib-std.m4 Wed Oct 05 06:28:23 2016 -0700
@@ -45,84 +45,44 @@
)
if test "x$OPENJDK_TARGET_OS" = xlinux; then
- # Test if -lstdc++ works.
- AC_MSG_CHECKING([if dynamic link of stdc++ is possible])
- AC_LANG_PUSH(C++)
- OLD_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS -lstdc++"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
- [has_dynamic_libstdcxx=yes],
- [has_dynamic_libstdcxx=no])
- CXXFLAGS="$OLD_CXXFLAGS"
- AC_LANG_POP(C++)
- AC_MSG_RESULT([$has_dynamic_libstdcxx])
-
# Test if stdc++ can be linked statically.
AC_MSG_CHECKING([if static link of stdc++ is possible])
- STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic"
+ STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc"
AC_LANG_PUSH(C++)
OLD_LIBS="$LIBS"
- OLD_CXX="$CXX"
LIBS="$STATIC_STDCXX_FLAGS"
- CXX="$CC"
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
[has_static_libstdcxx=yes],
[has_static_libstdcxx=no])
LIBS="$OLD_LIBS"
- CXX="$OLD_CXX"
AC_LANG_POP(C++)
AC_MSG_RESULT([$has_static_libstdcxx])
- if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then
- AC_MSG_ERROR([Cannot link to stdc++, neither dynamically nor statically!])
- fi
-
if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then
AC_MSG_ERROR([Static linking of libstdc++ was not possible!])
fi
- if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then
- AC_MSG_ERROR([Dynamic linking of libstdc++ was not possible!])
- fi
-
# If dynamic was requested, it's available since it would fail above otherwise.
# If dynamic wasn't requested, go with static unless it isn't available.
AC_MSG_CHECKING([how to link with libstdc++])
- if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then
- LIBCXX="$LIBCXX -lstdc++"
- # To help comparisons with old build, put stdc++ first in JVM_LIBS
- JVM_LIBS="-lstdc++ $JVM_LIBS"
- # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
- # just use the same setting as for the TARGET toolchain.
- OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS"
- LDCXX="$CXX"
- STATIC_CXX_SETTING="STATIC_CXX=false"
+ if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \
+ || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then
AC_MSG_RESULT([dynamic])
else
LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS"
- JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc"
- # To help comparisons with old build, put stdc++ first in JVM_LIBS
- JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS"
+ JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
# Ideally, we should test stdc++ for the BUILD toolchain separately. For now
# just use the same setting as for the TARGET toolchain.
- OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc"
- OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS"
- LDCXX="$CC"
- STATIC_CXX_SETTING="STATIC_CXX=true"
+ OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
AC_MSG_RESULT([static])
fi
fi
- AC_SUBST(STATIC_CXX_SETTING)
# libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so)
if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then
LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1"
fi
- # TODO better (platform agnostic) test
- if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then
- LIBCXX="-lstdc++"
- fi
AC_SUBST(LIBCXX)
# Setup Windows runtime dlls
--- a/corba/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/corba/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -380,3 +380,4 @@
094d0db606db976045f594dba47d4593b715cc81 jdk-9+135
aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136
258cf18fa7fc59359b874f8743b7168dc48baf73 jdk-9+137
+27bb44be32076861a0951bcefb07a1d92509a4b6 jdk-9+138
--- a/corba/make/gensrc/Gensrc-java.corba.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/corba/make/gensrc/Gensrc-java.corba.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -38,7 +38,7 @@
SRC := $(CORBA_TOPDIR)/make/src/classes, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes))
-TOOL_LOGUTIL_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes \
+TOOL_LOGUTIL_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes \
build.tools.logutil.MC
$(eval $(call SetupJavaCompilation,BUILD_IDLJ, \
@@ -50,7 +50,7 @@
EXCLUDE_FILES := ResourceBundleUtil.java module-info.java))
# Force the language to english for predictable source code generation.
-TOOL_IDLJ_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \
+TOOL_IDLJ_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \
-Duser.language=en com.sun.tools.corba.se.idl.toJavaPortable.Compile
################################################################################
--- a/hotspot/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -540,3 +540,4 @@
3b1c4562953db47e36b237a500f368d5c9746d47 jdk-9+135
a20da289f646ee44440695b81abc0548330e4ca7 jdk-9+136
dfcbf839e299e7e2bba1da69bdb347617ea4c7e8 jdk-9+137
+fc0956308c7a586267c5dd35dff74f773aa9c3eb jdk-9+138
--- a/hotspot/make/lib/CompileGtest.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/make/lib/CompileGtest.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -55,7 +55,7 @@
# Disabling switch warning for clang because of test source.
$(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
- TOOLCHAIN := $(JVM_TOOLCHAIN), \
+ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
LIBRARY := jvm, \
OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/objs, \
@@ -95,7 +95,7 @@
################################################################################
$(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \
- TOOLCHAIN := $(JVM_TOOLCHAIN), \
+ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
PROGRAM := gtestLauncher, \
OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
EXTRA_FILES := $(GTEST_LAUNCHER_SRC), \
--- a/hotspot/make/lib/CompileJvm.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/make/lib/CompileJvm.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -143,13 +143,6 @@
JVM_PRECOMPILED_HEADER := $(HOTSPOT_TOPDIR)/src/share/vm/precompiled/precompiled.hpp
endif
-ifneq ($(filter $(OPENJDK_TARGET_OS), macosx aix solaris), )
- # On macosx, aix and solaris we have to link with the C++ compiler
- JVM_TOOLCHAIN := TOOLCHAIN_LINK_CXX
-else
- JVM_TOOLCHAIN := TOOLCHAIN_DEFAULT
-endif
-
ifeq ($(OPENJDK_TARGET_CPU), x86)
JVM_EXCLUDE_PATTERNS += x86_64
else ifeq ($(OPENJDK_TARGET_CPU), x86_64)
@@ -194,7 +187,7 @@
# Now set up the actual compilation of the main hotspot native library
$(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
- TOOLCHAIN := $(JVM_TOOLCHAIN), \
+ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
LIBRARY := jvm, \
OUTPUT_DIR := $(JVM_OUTPUTDIR), \
SRC := $(JVM_SRC_DIRS), \
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Wed Oct 05 06:28:23 2016 -0700
@@ -68,6 +68,7 @@
Type type = db.lookupType("InstanceKlass");
arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0);
methods = type.getAddressField("_methods");
+ defaultMethods = type.getAddressField("_default_methods");
methodOrdering = type.getAddressField("_method_ordering");
localInterfaces = type.getAddressField("_local_interfaces");
transitiveInterfaces = type.getAddressField("_transitive_interfaces");
@@ -128,6 +129,7 @@
private static MetadataField arrayKlasses;
private static AddressField methods;
+ private static AddressField defaultMethods;
private static AddressField methodOrdering;
private static AddressField localInterfaces;
private static AddressField transitiveInterfaces;
@@ -335,6 +337,20 @@
// Accessors for declared fields
public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); }
public MethodArray getMethods() { return new MethodArray(methods.getValue(getAddress())); }
+
+ public MethodArray getDefaultMethods() {
+ if (defaultMethods != null) {
+ Address addr = defaultMethods.getValue(getAddress());
+ if ((addr != null) && (addr.getAddressAt(0) != null)) {
+ return new MethodArray(addr);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); }
public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1358,7 +1358,7 @@
if (!Universe::is_module_initialized() &&
!ModuleEntryTable::javabase_defined() &&
mod_entry == NULL) {
- mod_entry = ModuleEntryTable::javabase_module();
+ mod_entry = ModuleEntryTable::javabase_moduleEntry();
}
// The module must be a named module
@@ -1708,7 +1708,7 @@
if (jb_module == NULL) {
vm_exit_during_initialization("Unable to create ModuleEntry for java.base");
}
- ModuleEntryTable::set_javabase_module(jb_module);
+ ModuleEntryTable::set_javabase_moduleEntry(jb_module);
}
}
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -773,6 +773,41 @@
InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, mirror, CHECK);
}
+// Set the java.lang.reflect.Module module field in the java_lang_Class mirror
+void java_lang_Class::set_mirror_module_field(KlassHandle k, Handle mirror, Handle module, TRAPS) {
+ if (module.is_null()) {
+ // During startup, the module may be NULL only if java.base has not been defined yet.
+ // Put the class on the fixup_module_list to patch later when the java.lang.reflect.Module
+ // for java.base is known.
+ assert(!Universe::is_module_initialized(), "Incorrect java.lang.reflect.Module pre module system initialization");
+ MutexLocker m1(Module_lock, THREAD);
+ // Keep list of classes needing java.base module fixup
+ if (!ModuleEntryTable::javabase_defined()) {
+ if (fixup_module_field_list() == NULL) {
+ GrowableArray<Klass*>* list =
+ new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
+ set_fixup_module_field_list(list);
+ }
+ k->class_loader_data()->inc_keep_alive();
+ fixup_module_field_list()->push(k());
+ } else {
+ // java.base was defined at some point between calling create_mirror()
+ // and obtaining the Module_lock, patch this particular class with java.base.
+ ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
+ assert(javabase_entry != NULL && javabase_entry->module() != NULL,
+ "Setting class module field, java.base should be defined");
+ Handle javabase_handle(THREAD, JNIHandles::resolve(javabase_entry->module()));
+ set_module(mirror(), javabase_handle());
+ }
+ } else {
+ assert(Universe::is_module_initialized() ||
+ (ModuleEntryTable::javabase_defined() &&
+ (module() == JNIHandles::resolve(ModuleEntryTable::javabase_moduleEntry()->module()))),
+ "Incorrect java.lang.reflect.Module specification while creating mirror");
+ set_module(mirror(), module());
+ }
+}
+
void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
Handle module, Handle protection_domain, TRAPS) {
assert(k->java_mirror() == NULL, "should only assign mirror once");
@@ -835,25 +870,13 @@
set_class_loader(mirror(), class_loader());
// set the module field in the java_lang_Class instance
- // This may be null during bootstrap but will get fixed up later on.
- set_module(mirror(), module());
+ set_mirror_module_field(k, mirror, module, THREAD);
// Setup indirection from klass->mirror last
// after any exceptions can happen during allocations.
if (!k.is_null()) {
k->set_java_mirror(mirror());
}
-
- // Keep list of classes needing java.base module fixup.
- if (!ModuleEntryTable::javabase_defined()) {
- if (fixup_module_field_list() == NULL) {
- GrowableArray<Klass*>* list =
- new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
- set_fixup_module_field_list(list);
- }
- k->class_loader_data()->inc_keep_alive();
- fixup_module_field_list()->push(k());
- }
} else {
if (fixup_mirror_list() == NULL) {
GrowableArray<Klass*>* list =
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -219,6 +219,7 @@
static void set_class_loader(oop java_class, oop class_loader);
static void set_component_mirror(oop java_class, oop comp_mirror);
static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS);
+ static void set_mirror_module_field(KlassHandle K, Handle mirror, Handle module, TRAPS);
public:
static void compute_offsets();
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -25,12 +25,85 @@
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
+#include "classfile/classLoaderData.inline.hpp"
#include "classfile/klassFactory.hpp"
+#include "classfile/sharedClassUtil.hpp"
+#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jvmtiEnvBase.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
#include "trace/traceMacros.hpp"
+// called during initial loading of a shared class
+instanceKlassHandle KlassFactory::check_shared_class_file_load_hook(
+ instanceKlassHandle ik,
+ Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain, TRAPS) {
+#if INCLUDE_CDS && INCLUDE_JVMTI
+ assert(ik.not_null(), "sanity");
+ assert(ik()->is_shared(), "expecting a shared class");
+
+ if (JvmtiExport::should_post_class_file_load_hook()) {
+ assert(THREAD->is_Java_thread(), "must be JavaThread");
+
+ // Post the CFLH
+ JvmtiCachedClassFileData* cached_class_file = NULL;
+ JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data();
+ assert(archived_class_data != NULL, "shared class has no archived class data");
+ unsigned char* ptr =
+ VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data);
+ unsigned char* end_ptr =
+ ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data);
+ unsigned char* old_ptr = ptr;
+ JvmtiExport::post_class_file_load_hook(class_name,
+ class_loader,
+ protection_domain,
+ &ptr,
+ &end_ptr,
+ &cached_class_file);
+ if (old_ptr != ptr) {
+ // JVMTI agent has modified class file data.
+ // Set new class file stream using JVMTI agent modified class file data.
+ ClassLoaderData* loader_data =
+ ClassLoaderData::class_loader_data(class_loader());
+ int path_index = ik->shared_classpath_index();
+ SharedClassPathEntry* ent =
+ (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ ClassFileStream* stream = new ClassFileStream(ptr,
+ end_ptr - ptr,
+ ent->_name,
+ ClassFileStream::verify);
+ ClassFileParser parser(stream,
+ class_name,
+ loader_data,
+ protection_domain,
+ NULL,
+ NULL,
+ ClassFileParser::BROADCAST, // publicity level
+ CHECK_NULL);
+ instanceKlassHandle new_ik = parser.create_instance_klass(true /* changed_by_loadhook */,
+ CHECK_NULL);
+ if (cached_class_file != NULL) {
+ new_ik->set_cached_class_file(cached_class_file);
+ }
+
+ if (class_loader.is_null()) {
+ ResourceMark rm;
+ ClassLoader::add_package(class_name->as_C_string(), path_index, THREAD);
+ }
+
+ return new_ik;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+
static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
@@ -97,7 +170,6 @@
const InstanceKlass* host_klass,
GrowableArray<Handle>* cp_patches,
TRAPS) {
-
assert(stream != NULL, "invariant");
assert(loader_data != NULL, "invariant");
assert(THREAD->is_Java_thread(), "must be a JavaThread");
@@ -142,5 +214,27 @@
TRACE_KLASS_CREATION(result, parser, THREAD);
+#if INCLUDE_CDS && INCLUDE_JVMTI
+ if (DumpSharedSpaces) {
+ assert(cached_class_file == NULL, "Sanity");
+ // Archive the class stream data into the optional data section
+ JvmtiCachedClassFileData *p;
+ int len;
+ const unsigned char *bytes;
+ // event based tracing might set cached_class_file
+ if ((bytes = result->get_cached_class_file_bytes()) != NULL) {
+ len = result->get_cached_class_file_len();
+ } else {
+ len = stream->length();
+ bytes = stream->buffer();
+ }
+ p = (JvmtiCachedClassFileData*)MetaspaceShared::optional_data_space_alloc(
+ offset_of(JvmtiCachedClassFileData, data) + len);
+ p->length = len;
+ memcpy(p->data, bytes, len);
+ result->set_archived_class_data(p);
+ }
+#endif
+
return result;
}
--- a/hotspot/src/share/vm/classfile/klassFactory.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/klassFactory.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -75,6 +75,12 @@
const InstanceKlass* host_klass,
GrowableArray<Handle>* cp_patches,
TRAPS);
+ public:
+ static instanceKlassHandle check_shared_class_file_load_hook(
+ instanceKlassHandle ik,
+ Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain, TRAPS);
};
#endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -92,7 +92,7 @@
// read java.base. If either of these conditions
// hold, readability has been established.
if (!this->is_named() ||
- (m == ModuleEntryTable::javabase_module())) {
+ (m == ModuleEntryTable::javabase_moduleEntry())) {
return true;
}
@@ -358,16 +358,27 @@
}
// Set java.lang.reflect.Module, version and location for java.base
- ModuleEntry* jb_module = javabase_module();
+ ModuleEntry* jb_module = javabase_moduleEntry();
assert(jb_module != NULL, "java.base ModuleEntry not defined");
- jb_module->set_module(boot_loader_data->add_handle(module_handle));
jb_module->set_version(version);
jb_module->set_location(location);
+ // Once java.base's ModuleEntry _module field is set with the known
+ // java.lang.reflect.Module, java.base is considered "defined" to the VM.
+ jb_module->set_module(boot_loader_data->add_handle(module_handle));
+
// Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object.
java_lang_reflect_Module::set_module_entry(module_handle(), jb_module);
+
+ // Patch any previously loaded classes' module field with java.base's java.lang.reflect.Module.
+ patch_javabase_entries(module_handle);
}
+// Within java.lang.Class instances there is a java.lang.reflect.Module field
+// that must be set with the defining module. During startup, prior to java.base's
+// definition, classes needing their module field set are added to the fixup_module_list.
+// Their module field is set once java.base's java.lang.reflect.Module is known to the VM.
void ModuleEntryTable::patch_javabase_entries(Handle module_handle) {
+ assert(Module_lock->owned_by_self(), "should have the Module_lock");
if (module_handle.is_null()) {
fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module");
}
@@ -389,9 +400,7 @@
for (int i = 0; i < list_length; i++) {
Klass* k = list->at(i);
assert(k->is_klass(), "List should only hold classes");
- Thread* THREAD = Thread::current();
- KlassHandle kh(THREAD, k);
- java_lang_Class::fixup_module_field(kh, module_handle);
+ java_lang_Class::fixup_module_field(KlassHandle(k), module_handle);
k->class_loader_data()->dec_keep_alive();
}
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -78,11 +78,11 @@
_must_walk_reads = false;
}
- Symbol* name() const { return literal(); }
- void set_name(Symbol* n) { set_literal(n); }
+ Symbol* name() const { return literal(); }
+ void set_name(Symbol* n) { set_literal(n); }
- jobject module() const { return _module; }
- void set_module(jobject j) { _module = j; }
+ jobject module() const { return _module; }
+ void set_module(jobject j) { _module = j; }
// The shared ProtectionDomain reference is set once the VM loads a shared class
// originated from the current Module. The referenced ProtectionDomain object is
@@ -217,13 +217,13 @@
// Special handling for unnamed module, one per class loader's ModuleEntryTable
void create_unnamed_module(ClassLoaderData* loader_data);
- ModuleEntry* unnamed_module() { return _unnamed_module; }
+ ModuleEntry* unnamed_module() { return _unnamed_module; }
// Special handling for java.base
- static ModuleEntry* javabase_module() { return _javabase_module; }
- static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; }
- static bool javabase_defined() { return ((_javabase_module != NULL) &&
- (_javabase_module->module() != NULL)); }
+ static ModuleEntry* javabase_moduleEntry() { return _javabase_module; }
+ static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; }
+ static bool javabase_defined() { return ((_javabase_module != NULL) &&
+ (_javabase_module->module() != NULL)); }
static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
static void patch_javabase_entries(Handle module_handle);
--- a/hotspot/src/share/vm/classfile/modules.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/modules.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -206,7 +206,7 @@
assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table");
// Ensure java.base's ModuleEntry has been created
- assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base");
+ assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for java.base");
bool duplicate_javabase = false;
{
@@ -226,7 +226,7 @@
for (int x = 0; x < pkg_list->length(); x++) {
// Some of java.base's packages were added early in bootstrapping, ignore duplicates.
if (package_table->lookup_only(pkg_list->at(x)) == NULL) {
- pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module());
+ pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_moduleEntry());
assert(pkg != NULL, "Unable to create a java.base package entry");
}
// Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of
@@ -255,9 +255,6 @@
log_trace(modules)("define_javabase_module(): creation of package %s for module java.base",
(pkg_list->at(x))->as_C_string());
}
-
- // Patch any previously loaded classes' module field with java.base's jlr.Module.
- ModuleEntryTable::patch_javabase_entries(module_handle);
}
void Modules::define_module(jobject module, jstring version,
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1210,16 +1210,12 @@
instanceKlassHandle SystemDictionary::load_shared_class(
Symbol* class_name, Handle class_loader, TRAPS) {
- // Don't load shared class when JvmtiExport::should_post_class_file_load_hook()
- // is enabled since posting CFLH is not supported when loading shared class.
- if (!JvmtiExport::should_post_class_file_load_hook()) {
- instanceKlassHandle ik (THREAD, find_shared_class(class_name));
- // Make sure we only return the boot class for the NULL classloader.
- if (ik.not_null() &&
- ik->is_shared_boot_class() && class_loader.is_null()) {
- Handle protection_domain;
- return load_shared_class(ik, class_loader, protection_domain, THREAD);
- }
+ instanceKlassHandle ik (THREAD, find_shared_class(class_name));
+ // Make sure we only return the boot class for the NULL classloader.
+ if (ik.not_null() &&
+ ik->is_shared_boot_class() && class_loader.is_null()) {
+ Handle protection_domain;
+ return load_shared_class(ik, class_loader, protection_domain, THREAD);
}
return instanceKlassHandle();
}
@@ -1303,11 +1299,6 @@
Handle class_loader,
Handle protection_domain, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
- if (JvmtiExport::should_post_class_file_load_hook()) {
- // Don't load shared class when JvmtiExport::should_post_class_file_load_hook()
- // is enabled since posting CFLH is not supported when loading shared class.
- return nh;
- }
if (ik.not_null()) {
Symbol* class_name = ik->name();
@@ -1358,6 +1349,14 @@
}
}
+ instanceKlassHandle new_ik = KlassFactory::check_shared_class_file_load_hook(
+ ik, class_name, class_loader, protection_domain, CHECK_(nh));
+ if (new_ik.not_null()) {
+ // The class is changed by CFLH. Return the new class. The shared class is
+ // not used.
+ return new_ik;
+ }
+
// Adjust methods to recover missing data. They need addresses for
// interpreter entry points and their default native method address
// must be reset.
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1366,22 +1366,25 @@
return false;
}
assert(prefix != NULL && prefix != BUSY, "Error");
- size_t i = 1;
oop cur = prefix;
- while (i < objsFromOverflow && cur->klass_or_null() != NULL) {
- i++; cur = cur->list_ptr_from_klass();
+ for (size_t i = 1; i < objsFromOverflow; ++i) {
+ oop next = cur->list_ptr_from_klass();
+ if (next == NULL) break;
+ cur = next;
}
+ assert(cur != NULL, "Loop postcondition");
// Reattach remaining (suffix) to overflow list
- if (cur->klass_or_null() == NULL) {
+ oop suffix = cur->list_ptr_from_klass();
+ if (suffix == NULL) {
// Write back the NULL in lieu of the BUSY we wrote
// above and it is still the same value.
if (_overflow_list == BUSY) {
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
}
} else {
- assert(cur->klass_or_null() != (Klass*)(address)BUSY, "Error");
- oop suffix = cur->list_ptr_from_klass(); // suffix will be put back on global list
+ assert(suffix != BUSY, "Error");
+ // suffix will be put back on global list
cur->set_klass_to_list_ptr(NULL); // break off suffix
// It's possible that the list is still in the empty(busy) state
// we left it in a short while ago; in that case we may be
@@ -1401,8 +1404,10 @@
// Too bad, someone else got in in between; we'll need to do a splice.
// Find the last item of suffix list
oop last = suffix;
- while (last->klass_or_null() != NULL) {
- last = last->list_ptr_from_klass();
+ while (true) {
+ oop next = last->list_ptr_from_klass();
+ if (next == NULL) break;
+ last = next;
}
// Atomically prepend suffix to current overflow list
observed_overflow_list = _overflow_list;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1479,7 +1479,7 @@
"Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio);
- expand(expand_bytes);
+ expand(expand_bytes, _workers);
// No expansion, now see if we want to shrink
} else if (capacity_after_gc > maximum_desired_capacity) {
@@ -1599,7 +1599,7 @@
word_size * HeapWordSize);
- if (expand(expand_bytes)) {
+ if (expand(expand_bytes, _workers)) {
_hrm.verify_optional();
_verifier->verify_region_sets_optional();
return attempt_allocation_at_safepoint(word_size,
@@ -1609,7 +1609,7 @@
return NULL;
}
-bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) {
+bool G1CollectedHeap::expand(size_t expand_bytes, WorkGang* pretouch_workers, double* expand_time_ms) {
size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
aligned_expand_bytes = align_size_up(aligned_expand_bytes,
HeapRegion::GrainBytes);
@@ -1626,7 +1626,7 @@
uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes);
assert(regions_to_expand > 0, "Must expand by at least one region");
- uint expanded_by = _hrm.expand_by(regions_to_expand);
+ uint expanded_by = _hrm.expand_by(regions_to_expand, pretouch_workers);
if (expand_time_ms != NULL) {
*expand_time_ms = (os::elapsedTime() - expand_heap_start_time_sec) * MILLIUNITS;
}
@@ -1927,7 +1927,7 @@
_cmThread = _cm->cmThread();
// Now expand into the initial heap size.
- if (!expand(init_byte_size)) {
+ if (!expand(init_byte_size, _workers)) {
vm_shutdown_during_initialization("Failed to allocate initial heap.");
return JNI_ENOMEM;
}
@@ -3165,7 +3165,6 @@
assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
- _cm->note_start_of_gc();
// We call this after finalize_cset() to
// ensure that the CSet has been finalized.
_cm->verify_no_cset_oops();
@@ -3241,7 +3240,7 @@
// No need for an ergo logging here,
// expansion_amount() does this when it returns a value > 0.
double expand_ms;
- if (!expand(expand_bytes, &expand_ms)) {
+ if (!expand(expand_bytes, _workers, &expand_ms)) {
// We failed to expand the heap. Cannot do anything about it.
}
g1_policy()->phase_times()->record_expand_heap_time(expand_ms);
@@ -3251,7 +3250,6 @@
// We redo the verification but now wrt to the new CSet which
// has just got initialized after the previous CSet was freed.
_cm->verify_no_cset_oops();
- _cm->note_end_of_gc();
// This timing is only used by the ergonomics to handle our pause target.
// It is unclear why this should not include the full pause. We will
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -557,7 +557,7 @@
// Returns true if the heap was expanded by the requested amount;
// false otherwise.
// (Rounds up to a HeapRegion boundary.)
- bool expand(size_t expand_bytes, double* expand_time_ms = NULL);
+ bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL);
// Returns the PLAB statistics for a given destination.
inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -133,129 +133,184 @@
}
G1CMMarkStack::G1CMMarkStack() :
- _reserved_space(),
+ _max_chunk_capacity(0),
_base(NULL),
- _capacity(0),
- _saved_index((size_t)AllBits),
+ _chunk_capacity(0),
+ _out_of_memory(false),
_should_expand(false) {
set_empty();
}
bool G1CMMarkStack::resize(size_t new_capacity) {
assert(is_empty(), "Only resize when stack is empty.");
- assert(new_capacity <= MarkStackSizeMax,
- "Trying to resize stack to " SIZE_FORMAT " elements when the maximum is " SIZE_FORMAT, new_capacity, MarkStackSizeMax);
-
- size_t reservation_size = ReservedSpace::allocation_align_size_up(new_capacity * sizeof(oop));
-
- ReservedSpace rs(reservation_size);
- if (!rs.is_reserved()) {
- log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " elements and size " SIZE_FORMAT "B.", new_capacity, reservation_size);
+ assert(new_capacity <= _max_chunk_capacity,
+ "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity);
+
+ OopChunk* new_base = MmapArrayAllocator<OopChunk, mtGC>::allocate_or_null(new_capacity);
+
+ if (new_base == NULL) {
+ log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(OopChunk));
return false;
}
-
- VirtualSpace vs;
-
- if (!vs.initialize(rs, rs.size())) {
- rs.release();
- log_warning(gc)("Failed to commit memory for new overflow mark stack of size " SIZE_FORMAT "B.", rs.size());
- return false;
+ // Release old mapping.
+ if (_base != NULL) {
+ MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
}
- assert(vs.committed_size() == rs.size(), "Failed to commit all of the mark stack.");
-
- // Release old mapping.
- _reserved_space.release();
-
- // Save new mapping for future unmapping.
- _reserved_space = rs;
-
- MemTracker::record_virtual_memory_type((address)_reserved_space.base(), mtGC);
-
- _base = (oop*) vs.low();
- _capacity = new_capacity;
+ _base = new_base;
+ _chunk_capacity = new_capacity;
set_empty();
_should_expand = false;
return true;
}
-bool G1CMMarkStack::allocate(size_t capacity) {
- return resize(capacity);
+size_t G1CMMarkStack::capacity_alignment() {
+ return (size_t)lcm(os::vm_allocation_granularity(), sizeof(OopChunk)) / sizeof(void*);
+}
+
+bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) {
+ guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized.");
+
+ size_t const OopChunkSizeInVoidStar = sizeof(OopChunk) / sizeof(void*);
+
+ _max_chunk_capacity = (size_t)align_size_up(max_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
+ size_t initial_chunk_capacity = (size_t)align_size_up(initial_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
+
+ guarantee(initial_chunk_capacity <= _max_chunk_capacity,
+ "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT,
+ _max_chunk_capacity,
+ initial_chunk_capacity);
+
+ log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
+ initial_chunk_capacity, _max_chunk_capacity);
+
+ return resize(initial_chunk_capacity);
}
void G1CMMarkStack::expand() {
// Clear expansion flag
_should_expand = false;
- if (_capacity == MarkStackSizeMax) {
- log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " elements.", _capacity);
+ if (_chunk_capacity == _max_chunk_capacity) {
+ log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity);
return;
}
- size_t old_capacity = _capacity;
+ size_t old_capacity = _chunk_capacity;
// Double capacity if possible
- size_t new_capacity = MIN2(old_capacity * 2, MarkStackSizeMax);
+ size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity);
if (resize(new_capacity)) {
- log_debug(gc)("Expanded marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
+ log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
old_capacity, new_capacity);
} else {
- log_warning(gc)("Failed to expand marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
+ log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
old_capacity, new_capacity);
}
}
G1CMMarkStack::~G1CMMarkStack() {
if (_base != NULL) {
- _base = NULL;
- _reserved_space.release();
- }
-}
-
-void G1CMMarkStack::par_push_arr(oop* buffer, size_t n) {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- size_t start = _index;
- size_t next_index = start + n;
- if (next_index > _capacity) {
- _overflow = true;
- return;
- }
- // Otherwise.
- _index = next_index;
- for (size_t i = 0; i < n; i++) {
- size_t ind = start + i;
- assert(ind < _capacity, "By overflow test above.");
- _base[ind] = buffer[i];
+ MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
}
}
-bool G1CMMarkStack::par_pop_arr(oop* buffer, size_t max, size_t* n) {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- size_t index = _index;
- if (index == 0) {
- *n = 0;
+void G1CMMarkStack::add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem) {
+ elem->next = *list;
+ *list = elem;
+}
+
+void G1CMMarkStack::add_chunk_to_chunk_list(OopChunk* elem) {
+ MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
+ add_chunk_to_list(&_chunk_list, elem);
+ _chunks_in_chunk_list++;
+}
+
+void G1CMMarkStack::add_chunk_to_free_list(OopChunk* elem) {
+ MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
+ add_chunk_to_list(&_free_list, elem);
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_list(OopChunk* volatile* list) {
+ OopChunk* result = *list;
+ if (result != NULL) {
+ *list = (*list)->next;
+ }
+ return result;
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_chunk_list() {
+ MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
+ OopChunk* result = remove_chunk_from_list(&_chunk_list);
+ if (result != NULL) {
+ _chunks_in_chunk_list--;
+ }
+ return result;
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_free_list() {
+ MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
+ return remove_chunk_from_list(&_free_list);
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::allocate_new_chunk() {
+ // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code.
+ // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding
+ // wraparound of _hwm.
+ if (_hwm >= _chunk_capacity) {
+ return NULL;
+ }
+
+ size_t cur_idx = Atomic::add(1, &_hwm) - 1;
+ if (cur_idx >= _chunk_capacity) {
+ return NULL;
+ }
+
+ OopChunk* result = ::new (&_base[cur_idx]) OopChunk;
+ result->next = NULL;
+ return result;
+}
+
+bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) {
+ // Get a new chunk.
+ OopChunk* new_chunk = remove_chunk_from_free_list();
+
+ if (new_chunk == NULL) {
+ // Did not get a chunk from the free list. Allocate from backing memory.
+ new_chunk = allocate_new_chunk();
+ }
+
+ if (new_chunk == NULL) {
+ _out_of_memory = true;
return false;
- } else {
- size_t k = MIN2(max, index);
- size_t new_ind = index - k;
- for (size_t j = 0; j < k; j++) {
- buffer[j] = _base[new_ind + j];
- }
- _index = new_ind;
- *n = k;
- return true;
}
+
+ Copy::conjoint_memory_atomic(ptr_arr, new_chunk->data, OopsPerChunk * sizeof(oop));
+
+ add_chunk_to_chunk_list(new_chunk);
+
+ return true;
}
-void G1CMMarkStack::note_start_of_gc() {
- assert(_saved_index == (size_t)AllBits, "note_start_of_gc()/end_of_gc() calls bracketed incorrectly");
- _saved_index = _index;
+bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) {
+ OopChunk* cur = remove_chunk_from_chunk_list();
+
+ if (cur == NULL) {
+ return false;
+ }
+
+ Copy::conjoint_memory_atomic(cur->data, ptr_arr, OopsPerChunk * sizeof(oop));
+
+ add_chunk_to_free_list(cur);
+ return true;
}
-void G1CMMarkStack::note_end_of_gc() {
- guarantee(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index);
-
- _saved_index = (size_t)AllBits;
+void G1CMMarkStack::set_empty() {
+ _chunks_in_chunk_list = 0;
+ _hwm = 0;
+ clear_out_of_memory();
+ _chunk_list = NULL;
+ _free_list = NULL;
}
G1CMRootRegions::G1CMRootRegions() :
@@ -483,9 +538,8 @@
}
}
- if (!_global_mark_stack.allocate(MarkStackSize)) {
+ if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) {
vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
- return;
}
_tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
@@ -1695,10 +1749,10 @@
// oop closures will set the has_overflown flag if we overflow the
// global marking stack.
- assert(_global_mark_stack.overflow() || _global_mark_stack.is_empty(),
- "mark stack should be empty (unless it overflowed)");
-
- if (_global_mark_stack.overflow()) {
+ assert(_global_mark_stack.is_out_of_memory() || _global_mark_stack.is_empty(),
+ "Mark stack should be empty (unless it is out of memory)");
+
+ if (_global_mark_stack.is_out_of_memory()) {
// This should have been done already when we tried to push an
// entry on to the global mark stack. But let's do it again.
set_has_overflown();
@@ -2343,49 +2397,54 @@
}
void G1CMTask::move_entries_to_global_stack() {
- // local array where we'll store the entries that will be popped
- // from the local queue
- oop buffer[global_stack_transfer_size];
-
- int n = 0;
+ // Local array where we'll store the entries that will be popped
+ // from the local queue.
+ oop buffer[G1CMMarkStack::OopsPerChunk];
+
+ size_t n = 0;
oop obj;
- while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) {
+ while (n < G1CMMarkStack::OopsPerChunk && _task_queue->pop_local(obj)) {
buffer[n] = obj;
++n;
}
+ if (n < G1CMMarkStack::OopsPerChunk) {
+ buffer[n] = NULL;
+ }
if (n > 0) {
- // we popped at least one entry from the local queue
-
- if (!_cm->mark_stack_push(buffer, n)) {
+ if (!_cm->mark_stack_push(buffer)) {
set_has_aborted();
}
}
- // this operation was quite expensive, so decrease the limits
+ // This operation was quite expensive, so decrease the limits.
decrease_limits();
}
-void G1CMTask::get_entries_from_global_stack() {
- // local array where we'll store the entries that will be popped
+bool G1CMTask::get_entries_from_global_stack() {
+ // Local array where we'll store the entries that will be popped
// from the global stack.
- oop buffer[global_stack_transfer_size];
- size_t n;
- _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n);
- assert(n <= global_stack_transfer_size,
- "we should not pop more than the given limit");
- if (n > 0) {
- // yes, we did actually pop at least one entry
- for (size_t i = 0; i < n; ++i) {
- bool success = _task_queue->push(buffer[i]);
- // We only call this when the local queue is empty or under a
- // given target limit. So, we do not expect this push to fail.
- assert(success, "invariant");
+ oop buffer[G1CMMarkStack::OopsPerChunk];
+
+ if (!_cm->mark_stack_pop(buffer)) {
+ return false;
+ }
+
+ // We did actually pop at least one entry.
+ for (size_t i = 0; i < G1CMMarkStack::OopsPerChunk; ++i) {
+ oop elem = buffer[i];
+ if (elem == NULL) {
+ break;
}
+ bool success = _task_queue->push(elem);
+ // We only call this when the local queue is empty or under a
+ // given target limit. So, we do not expect this push to fail.
+ assert(success, "invariant");
}
- // this operation was quite expensive, so decrease the limits
+ // This operation was quite expensive, so decrease the limits
decrease_limits();
+ return true;
}
void G1CMTask::drain_local_queue(bool partially) {
@@ -2429,20 +2488,21 @@
// Decide what the target size is, depending whether we're going to
// drain it partially (so that other tasks can steal if they run out
- // of things to do) or totally (at the very end). Notice that,
- // because we move entries from the global stack in chunks or
- // because another task might be doing the same, we might in fact
- // drop below the target. But, this is not a problem.
- size_t target_size;
+ // of things to do) or totally (at the very end).
+ // Notice that when draining the global mark stack partially, due to the racyness
+ // of the mark stack size update we might in fact drop below the target. But,
+ // this is not a problem.
+ // In case of total draining, we simply process until the global mark stack is
+ // totally empty, disregarding the size counter.
if (partially) {
- target_size = _cm->partial_mark_stack_size_target();
+ size_t const target_size = _cm->partial_mark_stack_size_target();
+ while (!has_aborted() && _cm->mark_stack_size() > target_size) {
+ if (get_entries_from_global_stack()) {
+ drain_local_queue(partially);
+ }
+ }
} else {
- target_size = 0;
- }
-
- if (_cm->mark_stack_size() > target_size) {
- while (!has_aborted() && _cm->mark_stack_size() > target_size) {
- get_entries_from_global_stack();
+ while (!has_aborted() && get_entries_from_global_stack()) {
drain_local_queue(partially);
}
}
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -149,42 +149,98 @@
//
// Stores oops in a huge buffer in virtual memory that is always fully committed.
// Resizing may only happen during a STW pause when the stack is empty.
+//
+// Memory is allocated on a "chunk" basis, i.e. a set of oops. For this, the mark
+// stack memory is split into evenly sized chunks of oops. Users can only
+// add or remove entries on that basis.
+// Chunks are filled in increasing address order. Not completely filled chunks
+// have a NULL element as a terminating element.
+//
+// Every chunk has a header containing a single pointer element used for memory
+// management. This wastes some space, but is negligible (< .1% with current sizing).
+//
+// Memory management is done using a mix of tracking a high water-mark indicating
+// that all chunks at a lower address are valid chunks, and a singly linked free
+// list connecting all empty chunks.
class G1CMMarkStack VALUE_OBJ_CLASS_SPEC {
- ReservedSpace _reserved_space; // Space currently reserved for the mark stack.
+public:
+ // Number of oops that can fit in a single chunk.
+ static const size_t OopsPerChunk = 1024 - 1 /* One reference for the next pointer */;
+private:
+ struct OopChunk {
+ OopChunk* next;
+ oop data[OopsPerChunk];
+ };
+
+ size_t _max_chunk_capacity; // Maximum number of OopChunk elements on the stack.
+
+ OopChunk* _base; // Bottom address of allocated memory area.
+ size_t _chunk_capacity; // Current maximum number of OopChunk elements.
- oop* _base; // Bottom address of allocated memory area.
- size_t _capacity; // Maximum number of elements.
- size_t _index; // One more than last occupied index.
+ char _pad0[DEFAULT_CACHE_LINE_SIZE];
+ OopChunk* volatile _free_list; // Linked list of free chunks that can be allocated by users.
+ char _pad1[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*)];
+ OopChunk* volatile _chunk_list; // List of chunks currently containing data.
+ volatile size_t _chunks_in_chunk_list;
+ char _pad2[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*) - sizeof(size_t)];
+
+ volatile size_t _hwm; // High water mark within the reserved space.
+ char _pad4[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)];
+
+ // Allocate a new chunk from the reserved memory, using the high water mark. Returns
+ // NULL if out of memory.
+ OopChunk* allocate_new_chunk();
- size_t _saved_index; // Value of _index saved at start of GC to detect mark stack modifications during that time.
+ volatile bool _out_of_memory;
- bool _overflow;
+ // Atomically add the given chunk to the list.
+ void add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem);
+ // Atomically remove and return a chunk from the given list. Returns NULL if the
+ // list is empty.
+ OopChunk* remove_chunk_from_list(OopChunk* volatile* list);
+
+ void add_chunk_to_chunk_list(OopChunk* elem);
+ void add_chunk_to_free_list(OopChunk* elem);
+
+ OopChunk* remove_chunk_from_chunk_list();
+ OopChunk* remove_chunk_from_free_list();
+
bool _should_expand;
// Resizes the mark stack to the given new capacity. Releases any previous
// memory if successful.
bool resize(size_t new_capacity);
- bool stack_modified() const { return _index != _saved_index; }
public:
G1CMMarkStack();
~G1CMMarkStack();
- bool allocate(size_t capacity);
+ // Alignment and minimum capacity of this mark stack in number of oops.
+ static size_t capacity_alignment();
+
+ // Allocate and initialize the mark stack with the given number of oops.
+ bool initialize(size_t initial_capacity, size_t max_capacity);
- // Pushes the first "n" elements of the given buffer on the stack.
- void par_push_arr(oop* buffer, size_t n);
+ // Pushes the given buffer containing at most OopsPerChunk elements on the mark
+ // stack. If less than OopsPerChunk elements are to be pushed, the array must
+ // be terminated with a NULL.
+ // Returns whether the buffer contents were successfully pushed to the global mark
+ // stack.
+ bool par_push_chunk(oop* buffer);
- // Moves up to max elements from the stack into the given buffer. Returns
- // the number of elements pushed, and false if the array has been empty.
- // Returns true if the buffer contains at least one element.
- bool par_pop_arr(oop* buffer, size_t max, size_t* n);
+ // Pops a chunk from this mark stack, copying them into the given buffer. This
+ // chunk may contain up to OopsPerChunk elements. If there are less, the last
+ // element in the array is a NULL pointer.
+ bool par_pop_chunk(oop* buffer);
- bool is_empty() const { return _index == 0; }
- size_t capacity() const { return _capacity; }
+ // Return whether the chunk list is empty. Racy due to unsynchronized access to
+ // _chunk_list.
+ bool is_empty() const { return _chunk_list == NULL; }
- bool overflow() const { return _overflow; }
- void clear_overflow() { _overflow = false; }
+ size_t capacity() const { return _chunk_capacity; }
+
+ bool is_out_of_memory() const { return _out_of_memory; }
+ void clear_out_of_memory() { _out_of_memory = false; }
bool should_expand() const { return _should_expand; }
void set_should_expand(bool value) { _should_expand = value; }
@@ -192,20 +248,15 @@
// Expand the stack, typically in response to an overflow condition
void expand();
- size_t size() const { return _index; }
-
- void set_empty() { _index = 0; clear_overflow(); }
-
- // Record the current index.
- void note_start_of_gc();
+ // Return the approximate number of oops on this mark stack. Racy due to
+ // unsynchronized access to _chunks_in_chunk_list.
+ size_t size() const { return _chunks_in_chunk_list * OopsPerChunk; }
- // Make sure that we have not added any entries to the stack during GC.
- void note_end_of_gc();
+ void set_empty();
- // Apply fn to each oop in the mark stack, up to the bound recorded
- // via one of the above "note" functions. The mark stack must not
+ // Apply Fn to every oop on the mark stack. The mark stack must not
// be modified while iterating.
- template<typename Fn> void iterate(Fn fn);
+ template<typename Fn> void iterate(Fn fn) const PRODUCT_RETURN;
};
// Root Regions are regions that are not empty at the beginning of a
@@ -278,7 +329,6 @@
friend class G1CMDrainMarkingStackClosure;
friend class G1CMBitMapClosure;
friend class G1CMConcurrentMarkingTask;
- friend class G1CMMarkStack;
friend class G1CMRemarkTask;
friend class G1CMTask;
@@ -479,22 +529,20 @@
public:
// Manipulation of the global mark stack.
// The push and pop operations are used by tasks for transfers
- // between task-local queues and the global mark stack, and use
- // locking for concurrency safety.
- bool mark_stack_push(oop* arr, size_t n) {
- _global_mark_stack.par_push_arr(arr, n);
- if (_global_mark_stack.overflow()) {
+ // between task-local queues and the global mark stack.
+ bool mark_stack_push(oop* arr) {
+ if (!_global_mark_stack.par_push_chunk(arr)) {
set_has_overflown();
return false;
}
return true;
}
- void mark_stack_pop(oop* arr, size_t max, size_t* n) {
- _global_mark_stack.par_pop_arr(arr, max, n);
+ bool mark_stack_pop(oop* arr) {
+ return _global_mark_stack.par_pop_chunk(arr);
}
size_t mark_stack_size() { return _global_mark_stack.size(); }
size_t partial_mark_stack_size_target() { return _global_mark_stack.capacity()/3; }
- bool mark_stack_overflow() { return _global_mark_stack.overflow(); }
+ bool mark_stack_overflow() { return _global_mark_stack.is_out_of_memory(); }
bool mark_stack_empty() { return _global_mark_stack.is_empty(); }
G1CMRootRegions* root_regions() { return &_root_regions; }
@@ -599,16 +647,6 @@
// read-only, so use this carefully!
void clearRangePrevBitmap(MemRegion mr);
- // Notify data structures that a GC has started.
- void note_start_of_gc() {
- _global_mark_stack.note_start_of_gc();
- }
-
- // Notify data structures that a GC is finished.
- void note_end_of_gc() {
- _global_mark_stack.note_end_of_gc();
- }
-
// Verify that there are no CSet oops on the stacks (taskqueues /
// global mark stack) and fingers (global / per-task).
// If marking is not in progress, it's a no-op.
@@ -670,10 +708,7 @@
// references reaches this limit
refs_reached_period = 384,
// Initial value for the hash seed, used in the work stealing code
- init_hash_seed = 17,
- // How many entries will be transferred between global stack and
- // local queues at once.
- global_stack_transfer_size = 1024
+ init_hash_seed = 17
};
uint _worker_id;
@@ -858,9 +893,10 @@
// It pushes an object on the local queue.
inline void push(oop obj);
- // These two move entries to/from the global stack.
+ // Move entries to the global stack.
void move_entries_to_global_stack();
- void get_entries_from_global_stack();
+ // Move entries from the global stack, return true if we were successful to do so.
+ bool get_entries_from_global_stack();
// It pops and scans objects from the local queue. If partially is
// true, then it stops when the queue size is of a given limit. If
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -89,14 +89,28 @@
#undef check_mark
+#ifndef PRODUCT
template<typename Fn>
-inline void G1CMMarkStack::iterate(Fn fn) {
+inline void G1CMMarkStack::iterate(Fn fn) const {
assert_at_safepoint(true);
- assert(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index);
- for (size_t i = 0; i < _index; ++i) {
- fn(_base[i]);
+
+ size_t num_chunks = 0;
+
+ OopChunk* cur = _chunk_list;
+ while (cur != NULL) {
+ guarantee(num_chunks <= _chunks_in_chunk_list, "Found " SIZE_FORMAT " oop chunks which is more than there should be", num_chunks);
+
+ for (size_t i = 0; i < OopsPerChunk; ++i) {
+ if (cur->data[i] == NULL) {
+ break;
+ }
+ fn(cur->data[i]);
+ }
+ cur = cur->next;
+ num_chunks++;
}
}
+#endif
// It scans an object and visits its children.
inline void G1CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -34,7 +34,6 @@
class G1ConcurrentMark;
class DirtyCardToOopClosure;
class G1CMBitMap;
-class G1CMMarkStack;
class G1ParScanThreadState;
class G1CMTask;
class ReferenceProcessor;
--- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -24,8 +24,10 @@
#include "precompiled.hpp"
#include "gc/g1/g1PageBasedVirtualSpace.hpp"
+#include "gc/shared/workgroup.hpp"
#include "oops/markOop.hpp"
#include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
#include "runtime/os.inline.hpp"
#include "services/memTracker.hpp"
#include "utilities/bitMap.inline.hpp"
@@ -177,7 +179,7 @@
guarantee(start_page < end_page,
"Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page);
- os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page));
+ os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page), _page_size);
}
bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) {
@@ -198,9 +200,6 @@
}
_committed.set_range(start_page, end_page);
- if (AlwaysPreTouch) {
- pretouch_internal(start_page, end_page);
- }
return zero_filled;
}
@@ -227,6 +226,53 @@
_committed.clear_range(start_page, end_page);
}
+class G1PretouchTask : public AbstractGangTask {
+private:
+ char* volatile _cur_addr;
+ char* const _start_addr;
+ char* const _end_addr;
+ size_t const _page_size;
+public:
+ G1PretouchTask(char* start_address, char* end_address, size_t page_size) :
+ AbstractGangTask("G1 PreTouch",
+ Universe::is_fully_initialized() ? GCId::current_raw() :
+ // During VM initialization there is
+ // no GC cycle that this task can be
+ // associated with.
+ GCId::undefined()),
+ _cur_addr(start_address),
+ _start_addr(start_address),
+ _end_addr(end_address),
+ _page_size(page_size) {
+ }
+
+ virtual void work(uint worker_id) {
+ size_t const actual_chunk_size = MAX2(chunk_size(), _page_size);
+ while (true) {
+ char* touch_addr = (char*)Atomic::add_ptr((intptr_t)actual_chunk_size, (volatile void*) &_cur_addr) - actual_chunk_size;
+ if (touch_addr < _start_addr || touch_addr >= _end_addr) {
+ break;
+ }
+ char* end_addr = touch_addr + MIN2(actual_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char)));
+ os::pretouch_memory(touch_addr, end_addr, _page_size);
+ }
+ }
+
+ static size_t chunk_size() { return PreTouchParallelChunkSize; }
+};
+
+void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) {
+ guarantee(pretouch_gang != NULL, "No pretouch gang specified.");
+
+ size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
+
+ uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
+ G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size);
+ log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
+ cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
+ pretouch_gang->run_task(&cl, num_workers);
+}
+
bool G1PageBasedVirtualSpace::contains(const void* p) const {
return _low_boundary <= (const char*) p && (const char*) p < _high_boundary;
}
--- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -30,6 +30,8 @@
#include "memory/virtualspace.hpp"
#include "utilities/bitMap.hpp"
+class WorkGang;
+
// Virtual space management helper for a virtual space with an OS page allocation
// granularity.
// (De-)Allocation requests are always OS page aligned by passing a page index
@@ -117,6 +119,8 @@
// Uncommit the given area of pages starting at start being size_in_pages large.
void uncommit(size_t start_page, size_t size_in_pages);
+ void pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang = NULL);
+
// Initialize the given reserved space with the given base address and the size
// actually used.
// Prefer to commit in page_size chunks.
--- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -66,8 +66,12 @@
guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity");
}
- virtual void commit_regions(uint start_idx, size_t num_regions) {
- bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region);
+ virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) {
+ size_t const start_page = (size_t)start_idx * _pages_per_region;
+ bool zero_filled = _storage.commit(start_page, num_regions * _pages_per_region);
+ if (AlwaysPreTouch) {
+ _storage.pretouch(start_page, num_regions * _pages_per_region, pretouch_gang);
+ }
_commit_map.set_range(start_idx, start_idx + num_regions);
fire_on_commit(start_idx, num_regions, zero_filled);
}
@@ -110,19 +114,38 @@
_refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size);
}
- virtual void commit_regions(uint start_idx, size_t num_regions) {
+ virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) {
+ size_t const NoPage = ~(size_t)0;
+
+ size_t first_committed = NoPage;
+ size_t num_committed = 0;
+
+ bool all_zero_filled = true;
+
for (uint i = start_idx; i < start_idx + num_regions; i++) {
assert(!_commit_map.at(i), "Trying to commit storage at region %u that is already committed", i);
size_t idx = region_idx_to_page_idx(i);
uint old_refcount = _refcounts.get_by_index(idx);
+
bool zero_filled = false;
if (old_refcount == 0) {
+ if (first_committed == NoPage) {
+ first_committed = idx;
+ num_committed = 1;
+ } else {
+ num_committed++;
+ }
zero_filled = _storage.commit(idx, 1);
}
+ all_zero_filled &= zero_filled;
+
_refcounts.set_by_index(idx, old_refcount + 1);
_commit_map.set_bit(i);
- fire_on_commit(i, 1, zero_filled);
}
+ if (AlwaysPreTouch && num_committed > 0) {
+ _storage.pretouch(first_committed, num_committed, pretouch_gang);
+ }
+ fire_on_commit(start_idx, num_regions, all_zero_filled);
}
virtual void uncommit_regions(uint start_idx, size_t num_regions) {
--- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -29,6 +29,8 @@
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
+class WorkGang;
+
class G1MappingChangedListener VALUE_OBJ_CLASS_SPEC {
public:
// Fired after commit of the memory, i.e. the memory this listener is registered
@@ -68,7 +70,7 @@
return _commit_map.at(idx);
}
- virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0;
+ virtual void commit_regions(uint start_idx, size_t num_regions = 1, WorkGang* pretouch_workers = NULL) = 0;
virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0;
// Creates an appropriate G1RegionToSpaceMapper for the given parameters.
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -353,35 +353,6 @@
}
HeapWord*
-HeapRegion::object_iterate_mem_careful(MemRegion mr,
- ObjectClosure* cl) {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- // We used to use "block_start_careful" here. But we're actually happy
- // to update the BOT while we do this...
- HeapWord* cur = block_start(mr.start());
- mr = mr.intersection(used_region());
- if (mr.is_empty()) return NULL;
- // Otherwise, find the obj that extends onto mr.start().
-
- assert(cur <= mr.start()
- && (oop(cur)->klass_or_null() == NULL ||
- cur + oop(cur)->size() > mr.start()),
- "postcondition of block_start");
- oop obj;
- while (cur < mr.end()) {
- obj = oop(cur);
- if (obj->klass_or_null() == NULL) {
- // Ran into an unparseable point.
- return cur;
- } else if (!g1h->is_obj_dead(obj)) {
- cl->do_object(obj);
- }
- cur += block_size(cur);
- }
- return NULL;
-}
-
-HeapWord*
HeapRegion::
oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl,
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -653,17 +653,6 @@
}
}
- // Requires that "mr" be entirely within the region.
- // Apply "cl->do_object" to all objects that intersect with "mr".
- // If the iteration encounters an unparseable portion of the region,
- // or if "cl->abort()" is true after a closure application,
- // terminate the iteration and return the address of the start of the
- // subregion that isn't done. (The two can be distinguished by querying
- // "cl->abort()".) Return of "NULL" indicates that the iteration
- // completed.
- HeapWord*
- object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl);
-
// filter_young: if true and the region is a young region then we
// skip the iteration.
// card_ptr: if not NULL, and we decide that the card is not young
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -72,22 +72,22 @@
return g1h->new_heap_region(hrm_index, mr);
}
-void HeapRegionManager::commit_regions(uint index, size_t num_regions) {
+void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkGang* pretouch_gang) {
guarantee(num_regions > 0, "Must commit more than zero regions");
guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
_num_committed += (uint)num_regions;
- _heap_mapper->commit_regions(index, num_regions);
+ _heap_mapper->commit_regions(index, num_regions, pretouch_gang);
// Also commit auxiliary data
- _prev_bitmap_mapper->commit_regions(index, num_regions);
- _next_bitmap_mapper->commit_regions(index, num_regions);
+ _prev_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang);
+ _next_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang);
- _bot_mapper->commit_regions(index, num_regions);
- _cardtable_mapper->commit_regions(index, num_regions);
+ _bot_mapper->commit_regions(index, num_regions, pretouch_gang);
+ _cardtable_mapper->commit_regions(index, num_regions, pretouch_gang);
- _card_counts_mapper->commit_regions(index, num_regions);
+ _card_counts_mapper->commit_regions(index, num_regions, pretouch_gang);
}
void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) {
@@ -117,9 +117,9 @@
_card_counts_mapper->uncommit_regions(start, num_regions);
}
-void HeapRegionManager::make_regions_available(uint start, uint num_regions) {
+void HeapRegionManager::make_regions_available(uint start, uint num_regions, WorkGang* pretouch_gang) {
guarantee(num_regions > 0, "No point in calling this for zero regions");
- commit_regions(start, num_regions);
+ commit_regions(start, num_regions, pretouch_gang);
for (uint i = start; i < start + num_regions; i++) {
if (_regions.get_by_index(i) == NULL) {
HeapRegion* new_hr = new_heap_region(i);
@@ -163,11 +163,11 @@
return MemoryUsage(0, used_sz, committed_sz, committed_sz);
}
-uint HeapRegionManager::expand_by(uint num_regions) {
- return expand_at(0, num_regions);
+uint HeapRegionManager::expand_by(uint num_regions, WorkGang* pretouch_workers) {
+ return expand_at(0, num_regions, pretouch_workers);
}
-uint HeapRegionManager::expand_at(uint start, uint num_regions) {
+uint HeapRegionManager::expand_at(uint start, uint num_regions, WorkGang* pretouch_workers) {
if (num_regions == 0) {
return 0;
}
@@ -181,7 +181,7 @@
while (expanded < num_regions &&
(num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
uint to_expand = MIN2(num_regions - expanded, num_last_found);
- make_regions_available(idx_last_found, to_expand);
+ make_regions_available(idx_last_found, to_expand, pretouch_workers);
expanded += to_expand;
cur = idx_last_found + num_last_found + 1;
}
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -34,6 +34,7 @@
class HeapRegionClosure;
class HeapRegionClaimer;
class FreeRegionList;
+class WorkGang;
class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
protected:
@@ -94,10 +95,10 @@
HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
HeapWord* heap_end() const {return _regions.end_address_mapped(); }
- void make_regions_available(uint index, uint num_regions = 1);
+ void make_regions_available(uint index, uint num_regions = 1, WorkGang* pretouch_gang = NULL);
// Pass down commit calls to the VirtualSpace.
- void commit_regions(uint index, size_t num_regions = 1);
+ void commit_regions(uint index, size_t num_regions = 1, WorkGang* pretouch_gang = NULL);
void uncommit_regions(uint index, size_t num_regions = 1);
// Notify other data structures about change in the heap layout.
@@ -209,12 +210,12 @@
// HeapRegions, or re-use existing ones. Returns the number of regions the
// sequence was expanded by. If a HeapRegion allocation fails, the resulting
// number of regions might be smaller than what's desired.
- uint expand_by(uint num_regions);
+ uint expand_by(uint num_regions, WorkGang* pretouch_workers = NULL);
// Makes sure that the regions from start to start+num_regions-1 are available
// for allocation. Returns the number of regions that were committed to achieve
// this.
- uint expand_at(uint start, uint num_regions);
+ uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers = NULL);
// Find a contiguous set of empty regions of length num. Returns the start index of
// that set, or G1_NO_HRM_INDEX.
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -304,9 +304,6 @@
inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
inline static oop class_allocate(KlassHandle klass, int size, TRAPS);
- inline static void post_allocation_install_obj_klass(KlassHandle klass,
- oop obj);
-
// Raw memory allocation facilities
// The obj and array allocate methods are covers for these methods.
// mem_allocate() should never be
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -41,14 +41,22 @@
// Inline allocation implementations.
void CollectedHeap::post_allocation_setup_common(KlassHandle klass,
- HeapWord* obj) {
- post_allocation_setup_no_klass_install(klass, obj);
- post_allocation_install_obj_klass(klass, oop(obj));
+ HeapWord* obj_ptr) {
+ post_allocation_setup_no_klass_install(klass, obj_ptr);
+ oop obj = (oop)obj_ptr;
+#if ! INCLUDE_ALL_GCS
+ obj->set_klass(klass());
+#else
+ // Need a release store to ensure array/class length, mark word, and
+ // object zeroing are visible before setting the klass non-NULL, for
+ // concurrent collectors.
+ obj->release_set_klass(klass());
+#endif
}
void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass,
- HeapWord* objPtr) {
- oop obj = (oop)objPtr;
+ HeapWord* obj_ptr) {
+ oop obj = (oop)obj_ptr;
assert(obj != NULL, "NULL object pointer");
if (UseBiasedLocking && (klass() != NULL)) {
@@ -59,18 +67,6 @@
}
}
-void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
- oop obj) {
- // These asserts are kind of complicated because of klassKlass
- // and the beginning of the world.
- assert(klass() != NULL || !Universe::is_fully_initialized(), "NULL klass");
- assert(klass() == NULL || klass()->is_klass(), "not a klass");
- assert(obj != NULL, "NULL object pointer");
- obj->set_klass(klass());
- assert(!Universe::is_fully_initialized() || obj->klass() != NULL,
- "missing klass");
-}
-
// Support for jvmti and dtrace
inline void post_allocation_notify(KlassHandle klass, oop obj, int size) {
// support low memory notifications (no-op if not enabled)
@@ -88,25 +84,26 @@
}
void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
- HeapWord* obj,
+ HeapWord* obj_ptr,
int size) {
- post_allocation_setup_common(klass, obj);
+ post_allocation_setup_common(klass, obj_ptr);
+ oop obj = (oop)obj_ptr;
assert(Universe::is_bootstrapping() ||
- !((oop)obj)->is_array(), "must not be an array");
+ !obj->is_array(), "must not be an array");
// notify jvmti and dtrace
- post_allocation_notify(klass, (oop)obj, size);
+ post_allocation_notify(klass, obj, size);
}
void CollectedHeap::post_allocation_setup_class(KlassHandle klass,
- HeapWord* obj,
+ HeapWord* obj_ptr,
int size) {
- // Set oop_size field before setting the _klass field
- // in post_allocation_setup_common() because the klass field
- // indicates that the object is parsable by concurrent GC.
- oop new_cls = (oop)obj;
+ // Set oop_size field before setting the _klass field because a
+ // non-NULL _klass field indicates that the object is parsable by
+ // concurrent GC.
+ oop new_cls = (oop)obj_ptr;
assert(size > 0, "oop_size must be positive.");
java_lang_Class::set_oop_size(new_cls, size);
- post_allocation_setup_common(klass, obj);
+ post_allocation_setup_common(klass, obj_ptr);
assert(Universe::is_bootstrapping() ||
!new_cls->is_array(), "must not be an array");
// notify jvmti and dtrace
@@ -114,15 +111,15 @@
}
void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
- HeapWord* obj,
+ HeapWord* obj_ptr,
int length) {
- // Set array length before setting the _klass field
- // in post_allocation_setup_common() because the klass field
- // indicates that the object is parsable by concurrent GC.
+ // Set array length before setting the _klass field because a
+ // non-NULL klass field indicates that the object is parsable by
+ // concurrent GC.
assert(length >= 0, "length should be non-negative");
- ((arrayOop)obj)->set_length(length);
- post_allocation_setup_common(klass, obj);
- oop new_obj = (oop)obj;
+ ((arrayOop)obj_ptr)->set_length(length);
+ post_allocation_setup_common(klass, obj_ptr);
+ oop new_obj = (oop)obj_ptr;
assert(new_obj->is_array(), "must be an array");
// notify jvmti and dtrace (must be after length is set for dtrace)
post_allocation_notify(klass, new_obj, new_obj->size());
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -62,7 +62,12 @@
AbstractGangTask(const char* name) :
_name(name),
_gc_id(GCId::current_raw())
- {}
+ {}
+
+ AbstractGangTask(const char* name, const uint gc_id) :
+ _name(name),
+ _gc_id(gc_id)
+ {}
// The abstract work method.
// The argument tells you which member of the gang you are.
--- a/hotspot/src/share/vm/memory/allocation.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/allocation.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -738,6 +738,7 @@
static size_t size_for(size_t length);
public:
+ static E* allocate_or_null(size_t length);
static E* allocate(size_t length);
static void free(E* addr, size_t length);
};
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -153,6 +153,24 @@
}
template <class E, MEMFLAGS F>
+E* MmapArrayAllocator<E, F>::allocate_or_null(size_t length) {
+ size_t size = size_for(length);
+ int alignment = os::vm_allocation_granularity();
+
+ char* addr = os::reserve_memory(size, NULL, alignment, F);
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ if (os::commit_memory(addr, size, !ExecMem, "Allocator (commit)")) {
+ return (E*)addr;
+ } else {
+ os::release_memory(addr, size);
+ return NULL;
+ }
+}
+
+template <class E, MEMFLAGS F>
E* MmapArrayAllocator<E, F>::allocate(size_t length) {
size_t size = size_for(length);
int alignment = os::vm_allocation_granularity();
--- a/hotspot/src/share/vm/memory/filemap.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -649,7 +649,7 @@
// Memory map a region in the address space.
static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
- "String1", "String2" };
+ "String1", "String2", "OptionalData" };
char* FileMapInfo::map_region(int i) {
assert(!MetaspaceShared::is_string_region(i), "sanity");
--- a/hotspot/src/share/vm/memory/filemap.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/filemap.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -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
@@ -252,10 +252,27 @@
bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
void print_shared_spaces() NOT_CDS_RETURN;
+ // The ro+rw+md+mc spaces size
+ static size_t core_spaces_size() {
+ return align_size_up((SharedReadOnlySize + SharedReadWriteSize +
+ SharedMiscDataSize + SharedMiscCodeSize),
+ os::vm_allocation_granularity());
+ }
+
+ // The estimated optional space size.
+ //
+ // Currently the optional space only has archived class bytes.
+ // The core_spaces_size is the size of all class metadata, which is a good
+ // estimate of the total class bytes to be archived. Only the portion
+ // containing data is written out to the archive and mapped at runtime.
+ // There is no memory waste due to unused portion in optional space.
+ static size_t optional_space_size() {
+ return core_spaces_size();
+ }
+
+ // Total shared_spaces size includes the ro, rw, md, mc and od spaces
static size_t shared_spaces_size() {
- return align_size_up(SharedReadOnlySize + SharedReadWriteSize +
- SharedMiscDataSize + SharedMiscCodeSize,
- os::vm_allocation_granularity());
+ return core_spaces_size() + optional_space_size();
}
// Stop CDS sharing and unmap CDS regions.
--- a/hotspot/src/share/vm/memory/metaspace.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -3172,36 +3172,28 @@
address cds_address = NULL;
FileMapInfo* mapinfo = new FileMapInfo();
- if (JvmtiExport::should_post_class_file_load_hook()) {
- // Currently CDS does not support JVMTI CFLH when loading shared class.
- // If JvmtiExport::should_post_class_file_load_hook is already enabled,
- // just disable UseSharedSpaces.
- FileMapInfo::fail_continue("Tool agent requires sharing to be disabled.");
- delete mapinfo;
- } else {
- // Open the shared archive file, read and validate the header. If
- // initialization fails, shared spaces [UseSharedSpaces] are
- // disabled and the file is closed.
- // Map in spaces now also
- if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
- cds_total = FileMapInfo::shared_spaces_size();
- cds_address = (address)mapinfo->header()->region_addr(0);
+ // Open the shared archive file, read and validate the header. If
+ // initialization fails, shared spaces [UseSharedSpaces] are
+ // disabled and the file is closed.
+ // Map in spaces now also
+ if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
+ cds_total = FileMapInfo::shared_spaces_size();
+ cds_address = (address)mapinfo->header()->region_addr(0);
#ifdef _LP64
- if (using_class_space()) {
- char* cds_end = (char*)(cds_address + cds_total);
- cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
- // If UseCompressedClassPointers is set then allocate the metaspace area
- // above the heap and above the CDS area (if it exists).
- allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
- // Map the shared string space after compressed pointers
- // because it relies on compressed class pointers setting to work
- mapinfo->map_string_regions();
- }
+ if (using_class_space()) {
+ char* cds_end = (char*)(cds_address + cds_total);
+ cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
+ // If UseCompressedClassPointers is set then allocate the metaspace area
+ // above the heap and above the CDS area (if it exists).
+ allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
+ // Map the shared string space after compressed pointers
+ // because it relies on compressed class pointers setting to work
+ mapinfo->map_string_regions();
+ }
#endif // _LP64
- } else {
- assert(!mapinfo->is_open() && !UseSharedSpaces,
- "archive file not closed or shared spaces not disabled.");
- }
+ } else {
+ assert(!mapinfo->is_open() && !UseSharedSpaces,
+ "archive file not closed or shared spaces not disabled.");
}
}
#endif // INCLUDE_CDS
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -65,6 +65,7 @@
size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
SharedMiscRegion MetaspaceShared::_mc;
SharedMiscRegion MetaspaceShared::_md;
+SharedMiscRegion MetaspaceShared::_od;
void SharedMiscRegion::initialize(ReservedSpace rs, size_t committed_byte_size, SharedSpaceType space_type) {
_vs.initialize(rs, committed_byte_size);
@@ -93,16 +94,24 @@
assert(DumpSharedSpaces, "dump time only");
_shared_rs = rs;
- // Split up and initialize the misc code and data spaces
+ size_t core_spaces_size = FileMapInfo::core_spaces_size();
size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize;
- ReservedSpace shared_ro_rw = _shared_rs->first_part(metadata_size);
- ReservedSpace misc_section = _shared_rs->last_part(metadata_size);
+
+ // Split into the core and optional sections
+ ReservedSpace core_data = _shared_rs->first_part(core_spaces_size);
+ ReservedSpace optional_data = _shared_rs->last_part(core_spaces_size);
- // Now split into misc sections.
+ // The RO/RW and the misc sections
+ ReservedSpace shared_ro_rw = core_data.first_part(metadata_size);
+ ReservedSpace misc_section = core_data.last_part(metadata_size);
+
+ // Now split the misc code and misc data sections.
ReservedSpace md_rs = misc_section.first_part(SharedMiscDataSize);
ReservedSpace mc_rs = misc_section.last_part(SharedMiscDataSize);
+
_md.initialize(md_rs, SharedMiscDataSize, SharedMiscData);
- _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscData);
+ _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscCode);
+ _od.initialize(optional_data, metadata_size, SharedOptional);
}
// Read/write a data stream for restoring/preserving metadata pointers and
@@ -521,6 +530,7 @@
GrowableArray<Klass*> *_class_promote_order;
VirtualSpace _md_vs;
VirtualSpace _mc_vs;
+ VirtualSpace _od_vs;
GrowableArray<MemRegion> *_string_regions;
public:
@@ -598,15 +608,19 @@
remove_unshareable_in_classes();
tty->print_cr("done. ");
- // Set up the share data and shared code segments.
+ // Set up the misc data, misc code and optional data segments.
_md_vs = *MetaspaceShared::misc_data_region()->virtual_space();
_mc_vs = *MetaspaceShared::misc_code_region()->virtual_space();
+ _od_vs = *MetaspaceShared::optional_data_region()->virtual_space();
char* md_low = _md_vs.low();
char* md_top = MetaspaceShared::misc_data_region()->alloc_top();
char* md_end = _md_vs.high();
char* mc_low = _mc_vs.low();
char* mc_top = MetaspaceShared::misc_code_region()->alloc_top();
char* mc_end = _mc_vs.high();
+ char* od_low = _od_vs.low();
+ char* od_top = MetaspaceShared::optional_data_region()->alloc_top();
+ char* od_end = _od_vs.high();
// Reserve space for the list of Klass*s whose vtables are used
// for patching others as needed.
@@ -661,28 +675,32 @@
const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType);
const size_t md_alloced = md_end-md_low;
const size_t mc_alloced = mc_end-mc_low;
+ const size_t od_alloced = od_end-od_low;
const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced
- + ss_bytes;
+ + ss_bytes + od_alloced;
// Occupied size of each space.
const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType);
const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType);
const size_t md_bytes = size_t(md_top - md_low);
const size_t mc_bytes = size_t(mc_top - mc_low);
+ const size_t od_bytes = size_t(od_top - od_low);
// Percent of total size
- const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes;
+ const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes + od_bytes;
const double ro_t_perc = ro_bytes / double(total_bytes) * 100.0;
const double rw_t_perc = rw_bytes / double(total_bytes) * 100.0;
const double md_t_perc = md_bytes / double(total_bytes) * 100.0;
const double mc_t_perc = mc_bytes / double(total_bytes) * 100.0;
const double ss_t_perc = ss_bytes / double(total_bytes) * 100.0;
+ const double od_t_perc = od_bytes / double(total_bytes) * 100.0;
// Percent of fullness of each space
const double ro_u_perc = ro_bytes / double(ro_alloced) * 100.0;
const double rw_u_perc = rw_bytes / double(rw_alloced) * 100.0;
const double md_u_perc = md_bytes / double(md_alloced) * 100.0;
const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0;
+ const double od_u_perc = od_bytes / double(od_alloced) * 100.0;
const double total_u_perc = total_bytes / double(total_alloced) * 100.0;
#define fmt_space "%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT
@@ -691,6 +709,7 @@
tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, p2i(md_low));
tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, p2i(mc_low));
tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low));
+ tty->print_cr(fmt_space, "od", od_bytes, od_t_perc, od_alloced, od_u_perc, p2i(od_low));
tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
total_bytes, total_alloced, total_u_perc);
@@ -734,6 +753,10 @@
SharedMiscCodeSize,
true, true);
mapinfo->write_string_regions(_string_regions);
+ mapinfo->write_region(MetaspaceShared::od, _od_vs.low(),
+ pointer_delta(od_top, _od_vs.low(), sizeof(char)),
+ pointer_delta(od_end, _od_vs.low(), sizeof(char)),
+ true, false);
}
mapinfo->close();
@@ -1049,8 +1072,6 @@
// Map shared spaces at requested addresses and return if succeeded.
-// Need to keep the bounds of the ro and rw space for the Metaspace::contains
-// call, or is_in_shared_space.
bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
size_t image_alignment = mapinfo->alignment();
@@ -1068,6 +1089,7 @@
char* _rw_base = NULL;
char* _md_base = NULL;
char* _mc_base = NULL;
+ char* _od_base = NULL;
// Map each shared region
if ((_ro_base = mapinfo->map_region(ro)) != NULL &&
@@ -1078,6 +1100,8 @@
mapinfo->verify_region_checksum(md) &&
(_mc_base = mapinfo->map_region(mc)) != NULL &&
mapinfo->verify_region_checksum(mc) &&
+ (_od_base = mapinfo->map_region(od)) != NULL &&
+ mapinfo->verify_region_checksum(od) &&
(image_alignment == (size_t)max_alignment()) &&
mapinfo->validate_classpath_entry_table()) {
// Success (no need to do anything)
@@ -1089,6 +1113,7 @@
if (_rw_base != NULL) mapinfo->unmap_region(rw);
if (_md_base != NULL) mapinfo->unmap_region(md);
if (_mc_base != NULL) mapinfo->unmap_region(mc);
+ if (_od_base != NULL) mapinfo->unmap_region(od);
#ifndef _WINDOWS
// Release the entire mapped region
shared_rs.release();
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -132,6 +132,7 @@
// Used only during dumping.
static SharedMiscRegion _md;
static SharedMiscRegion _mc;
+ static SharedMiscRegion _od;
public:
enum {
vtbl_list_size = DEFAULT_VTBL_LIST_SIZE,
@@ -148,7 +149,10 @@
max_strings = 2, // max number of string regions in string space
num_non_strings = 4, // number of non-string regions
first_string = num_non_strings, // index of first string region
- n_regions = max_strings + num_non_strings // total number of regions
+ // The optional data region is the last region.
+ // Currently it only contains class file data.
+ od = max_strings + num_non_strings,
+ n_regions = od + 1 // total number of regions
};
// Accessor functions to save shared space created for metadata, which has
@@ -222,9 +226,10 @@
static int count_class(const char* classlist_file);
static void estimate_regions_size() NOT_CDS_RETURN;
- // Allocate a block of memory from the "mc" or "md" regions.
+ // Allocate a block of memory from the "mc", "md", or "od" regions.
static char* misc_code_space_alloc(size_t num_bytes) { return _mc.alloc(num_bytes); }
static char* misc_data_space_alloc(size_t num_bytes) { return _md.alloc(num_bytes); }
+ static char* optional_data_space_alloc(size_t num_bytes) { return _od.alloc(num_bytes); }
static address cds_i2i_entry_code_buffers(size_t total_size);
@@ -243,5 +248,9 @@
assert(DumpSharedSpaces, "used during dumping only");
return &_md;
}
+ static SharedMiscRegion* optional_data_region() {
+ assert(DumpSharedSpaces, "used during dumping only");
+ return &_od;
+ }
};
#endif // SHARE_VM_MEMORY_METASPACESHARED_HPP
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -41,6 +41,7 @@
#include "memory/heapInspection.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
+#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/fieldStreams.hpp"
@@ -1972,11 +1973,6 @@
m->remove_unshareable_info();
}
- // cached_class_file might be pointing to a malloc'ed buffer allocated by
- // event-based tracing code at CDS dump time. It's not usable at runtime
- // so let's clear it.
- set_cached_class_file(NULL);
-
// do array classes also.
array_klasses_do(remove_unshareable_in_class);
}
@@ -2070,6 +2066,7 @@
}
void InstanceKlass::release_C_heap_structures() {
+ assert(!this->is_shared(), "should not be called for a shared class");
// Can't release the constant pool here because the constant pool can be
// deallocated separately from the InstanceKlass for default methods and
@@ -2250,8 +2247,8 @@
// the java.base module. If a non-java.base package is erroneously placed
// in the java.base module it will be caught later when java.base
// is defined by ModuleEntryTable::verify_javabase_packages check.
- assert(ModuleEntryTable::javabase_module() != NULL, "java.base module is NULL");
- _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_module());
+ assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "java.base module is NULL");
+ _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_moduleEntry());
} else {
assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL");
_package_entry = loader_data->packages()->lookup(pkg_name,
@@ -3653,6 +3650,15 @@
}
#if INCLUDE_JVMTI
+JvmtiCachedClassFileData* InstanceKlass::get_cached_class_file() {
+ if (MetaspaceShared::is_in_shared_space(_cached_class_file)) {
+ // Ignore the archived class stream data
+ return NULL;
+ } else {
+ return _cached_class_file;
+ }
+}
+
jint InstanceKlass::get_cached_class_file_len() {
return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file);
}
@@ -3660,4 +3666,15 @@
unsigned char * InstanceKlass::get_cached_class_file_bytes() {
return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
}
+
+#if INCLUDE_CDS
+JvmtiCachedClassFileData* InstanceKlass::get_archived_class_data() {
+ assert(this->is_shared(), "class should be shared");
+ if (MetaspaceShared::is_in_shared_space(_cached_class_file)) {
+ return _cached_class_file;
+ } else {
+ return NULL;
+ }
+}
#endif
+#endif
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -783,7 +783,7 @@
void set_cached_class_file(JvmtiCachedClassFileData *data) {
_cached_class_file = data;
}
- JvmtiCachedClassFileData * get_cached_class_file() { return _cached_class_file; }
+ JvmtiCachedClassFileData * get_cached_class_file();
jint get_cached_class_file_len();
unsigned char * get_cached_class_file_bytes();
@@ -795,6 +795,13 @@
return _jvmti_cached_class_field_map;
}
+#if INCLUDE_CDS
+ void set_archived_class_data(JvmtiCachedClassFileData* data) {
+ _cached_class_file = data;
+ }
+
+ JvmtiCachedClassFileData * get_archived_class_data();
+#endif // INCLUDE_CDS
#else // INCLUDE_JVMTI
static void purge_previous_versions(InstanceKlass* ik) { return; };
--- a/hotspot/src/share/vm/oops/klass.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/klass.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -530,7 +530,7 @@
InstanceKlass* ik = (InstanceKlass*) k;
module_entry = ik->module();
} else {
- module_entry = ModuleEntryTable::javabase_module();
+ module_entry = ModuleEntryTable::javabase_moduleEntry();
}
// Obtain java.lang.reflect.Module, if available
Handle module_handle(THREAD, ((module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL));
--- a/hotspot/src/share/vm/oops/oop.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/oop.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -87,6 +87,7 @@
inline narrowKlass* compressed_klass_addr();
inline void set_klass(Klass* k);
+ inline void release_set_klass(Klass* k);
// For klass field compression
inline int klass_gap() const;
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -129,10 +129,14 @@
return &_metadata._compressed_klass;
}
+#define CHECK_SET_KLASS(k) \
+ do { \
+ assert(Universe::is_bootstrapping() || k != NULL, "NULL Klass"); \
+ assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass"); \
+ } while (0)
+
void oopDesc::set_klass(Klass* k) {
- // since klasses are promoted no store check is needed
- assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*");
- assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*");
+ CHECK_SET_KLASS(k);
if (UseCompressedClassPointers) {
*compressed_klass_addr() = Klass::encode_klass_not_null(k);
} else {
@@ -140,6 +144,18 @@
}
}
+void oopDesc::release_set_klass(Klass* k) {
+ CHECK_SET_KLASS(k);
+ if (UseCompressedClassPointers) {
+ OrderAccess::release_store(compressed_klass_addr(),
+ Klass::encode_klass_not_null(k));
+ } else {
+ OrderAccess::release_store_ptr(klass_addr(), k);
+ }
+}
+
+#undef CHECK_SET_KLASS
+
int oopDesc::klass_gap() const {
return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes());
}
--- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -72,7 +72,7 @@
null_loader_data->add_class(ak);
// Call complete_create_array_klass after all instance variables have been initialized.
- complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_module(), CHECK_NULL);
+ complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_moduleEntry(), CHECK_NULL);
return ak;
}
@@ -347,7 +347,7 @@
// A TypeArrayKlass is an array of a primitive type, its defining module is java.base
ModuleEntry* TypeArrayKlass::module() const {
- return ModuleEntryTable::javabase_module();
+ return ModuleEntryTable::javabase_moduleEntry();
}
PackageEntry* TypeArrayKlass::package() const {
--- a/hotspot/src/share/vm/prims/unsafe.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -272,6 +272,31 @@
// Get/PutObject must be special-cased, since it works with handles.
+// We could be accessing the referent field in a reference
+// object. If G1 is enabled then we need to register non-null
+// referent with the SATB barrier.
+
+#if INCLUDE_ALL_GCS
+static bool is_java_lang_ref_Reference_access(oop o, jlong offset) {
+ if (offset == java_lang_ref_Reference::referent_offset && o != NULL) {
+ Klass* k = o->klass();
+ if (InstanceKlass::cast(k)->reference_type() != REF_NONE) {
+ assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+static void ensure_satb_referent_alive(oop o, jlong offset, oop v) {
+#if INCLUDE_ALL_GCS
+ if (UseG1GC && v != NULL && is_java_lang_ref_Reference_access(o, offset)) {
+ G1SATBCardTableModRefBS::enqueue(v);
+ }
+#endif
+}
+
// These functions allow a null base pointer with an arbitrary address.
// But if the base pointer is non-null, the offset should make some sense.
// That is, it should be in the range [0, MAX_OBJECT_SIZE].
@@ -286,34 +311,9 @@
v = *(oop*)index_oop_from_field_offset_long(p, offset);
}
- jobject ret = JNIHandles::make_local(env, v);
-
-#if INCLUDE_ALL_GCS
- // We could be accessing the referent field in a reference
- // object. If G1 is enabled then we need to register non-null
- // referent with the SATB barrier.
- if (UseG1GC) {
- bool needs_barrier = false;
+ ensure_satb_referent_alive(p, offset, v);
- if (ret != NULL) {
- if (offset == java_lang_ref_Reference::referent_offset && obj != NULL) {
- oop o = JNIHandles::resolve(obj);
- Klass* k = o->klass();
- if (InstanceKlass::cast(k)->reference_type() != REF_NONE) {
- assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
- needs_barrier = true;
- }
- }
- }
-
- if (needs_barrier) {
- oop referent = JNIHandles::resolve(ret);
- G1SATBCardTableModRefBS::enqueue(referent);
- }
- }
-#endif // INCLUDE_ALL_GCS
-
- return ret;
+ return JNIHandles::make_local(env, v);
} UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_PutObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
@@ -344,6 +344,8 @@
(void)const_cast<oop&>(v = *(volatile oop*) addr);
}
+ ensure_satb_referent_alive(p, offset, v);
+
OrderAccess::acquire();
return JNIHandles::make_local(env, v);
} UNSAFE_END
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -1596,6 +1596,10 @@
product(bool, AlwaysPreTouch, false, \
"Force all freshly committed pages to be pre-touched") \
\
+ product(size_t, PreTouchParallelChunkSize, 1 * G, \
+ "Per-thread chunk size for parallel memory pre-touch.") \
+ range(1, SIZE_MAX / 2) \
+ \
product_pd(size_t, CMSYoungGenPerWorker, \
"The maximum size of young gen chosen by default per GC worker " \
"thread available") \
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -77,6 +77,8 @@
Mutex* DirtyCardQ_FL_lock = NULL;
Monitor* DirtyCardQ_CBL_mon = NULL;
Mutex* Shared_DirtyCardQ_lock = NULL;
+Mutex* MarkStackFreeList_lock = NULL;
+Mutex* MarkStackChunkList_lock = NULL;
Mutex* ParGCRareEvent_lock = NULL;
Mutex* DerivedPointerTableGC_lock = NULL;
Mutex* Compile_lock = NULL;
@@ -194,6 +196,9 @@
def(StringDedupQueue_lock , Monitor, leaf, true, Monitor::_safepoint_check_never);
def(StringDedupTable_lock , Mutex , leaf, true, Monitor::_safepoint_check_never);
+
+ def(MarkStackFreeList_lock , Mutex , leaf , true, Monitor::_safepoint_check_never);
+ def(MarkStackChunkList_lock , Mutex , leaf , true, Monitor::_safepoint_check_never);
}
def(ParGCRareEvent_lock , Mutex , leaf , true, Monitor::_safepoint_check_sometimes);
def(DerivedPointerTableGC_lock , Mutex, leaf, true, Monitor::_safepoint_check_never);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -81,7 +81,8 @@
extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card
// queue shared by
// non-Java threads.
- // (see option ExplicitGCInvokesConcurrent)
+extern Mutex* MarkStackFreeList_lock; // Protects access to the global mark stack free list.
+extern Mutex* MarkStackChunkList_lock; // Protects access to the global mark stack chunk list.
extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops.
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued
--- a/hotspot/src/share/vm/runtime/os.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/os.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -1705,8 +1705,8 @@
return res;
}
-void os::pretouch_memory(void* start, void* end) {
- for (volatile char *p = (char*)start; p < (char*)end; p += os::vm_page_size()) {
+void os::pretouch_memory(void* start, void* end, size_t page_size) {
+ for (volatile char *p = (char*)start; p < (char*)end; p += page_size) {
*p = 0;
}
}
--- a/hotspot/src/share/vm/runtime/os.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -324,7 +324,7 @@
// to make the OS back the memory range with actual memory.
// Current implementation may not touch the last page if unaligned addresses
// are passed.
- static void pretouch_memory(void* start, void* end);
+ static void pretouch_memory(void* start, void* end, size_t page_size = vm_page_size());
enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX };
static bool protect_memory(char* addr, size_t bytes, ProtType prot,
--- a/hotspot/src/share/vm/utilities/debug.cpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/debug.cpp Wed Oct 05 06:28:23 2016 -0700
@@ -282,6 +282,12 @@
}
void report_out_of_shared_space(SharedSpaceType shared_space) {
+ if (shared_space == SharedOptional) {
+ // The estimated shared_optional_space size is large enough
+ // for all class bytes. It should not run out of space.
+ ShouldNotReachHere();
+ }
+
static const char* name[] = {
"shared read only space",
"shared read write space",
--- a/hotspot/src/share/vm/utilities/debug.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/debug.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -271,7 +271,8 @@
SharedReadOnly,
SharedReadWrite,
SharedMiscData,
- SharedMiscCode
+ SharedMiscCode,
+ SharedOptional
};
void report_out_of_shared_space(SharedSpaceType space_type);
--- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, 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
@@ -79,8 +79,8 @@
template <MEMFLAGS F> inline void HashtableBucket<F>::set_entry(BasicHashtableEntry<F>* l) {
- // Warning: Preserve store ordering. The SystemDictionary is read
- // without locks. The new SystemDictionaryEntry must be
+ // Warning: Preserve store ordering. The PackageEntryTable, ModuleEntryTable and
+ // SystemDictionary are read without locks. The new entry must be
// complete before other threads can be allowed to see it
// via a store to _buckets[index].
OrderAccess::release_store_ptr(&_entry, l);
@@ -88,8 +88,8 @@
template <MEMFLAGS F> inline BasicHashtableEntry<F>* HashtableBucket<F>::get_entry() const {
- // Warning: Preserve load ordering. The SystemDictionary is read
- // without locks. The new SystemDictionaryEntry must be
+ // Warning: Preserve load ordering. The PackageEntryTable, ModuleEntryTable and
+ // SystemDictionary are read without locks. The new entry must be
// complete before other threads can be allowed to see it
// via a store to _buckets[index].
return (BasicHashtableEntry<F>*) OrderAccess::load_ptr_acquire(&_entry);
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Wed Oct 05 06:28:23 2016 -0700
@@ -110,10 +110,6 @@
excludeTestMaxRange("OldSize");
excludeTestMaxRange("ParallelGCThreads");
- excludeTestMaxRange("CompilerThreadStackSize");
- excludeTestMaxRange("ThreadStackSize");
- excludeTestMaxRange("VMThreadStackSize");
-
/*
* Remove parameters controlling the code cache. As these
* parameters have implications on the physical memory
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,115 @@
+/*
+ * 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.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+// This class contains common test utilities for CDS testing
+public class CDSTestUtils {
+
+ // check result of 'dump' operation
+ public static void checkDump(OutputAnalyzer output, String... extraMatches)
+ throws Exception {
+
+ output.shouldContain("Loading classes to share");
+ output.shouldHaveExitValue(0);
+
+ for (String match : extraMatches) {
+ output.shouldContain(match);
+ }
+ }
+
+
+ // check the output for indication that mapping of the archive failed
+ public static boolean isUnableToMap(OutputAnalyzer output) {
+ String outStr = output.getOutput();
+ if ((output.getExitValue() == 1) && (
+ outStr.contains("Unable to reserve shared space at required address") ||
+ outStr.contains("Unable to map ReadOnly shared space at required address") ||
+ outStr.contains("Unable to map ReadWrite shared space at required address") ||
+ outStr.contains("Unable to map MiscData shared space at required address") ||
+ outStr.contains("Unable to map MiscCode shared space at required address") ||
+ outStr.contains("Unable to map shared string space at required address") ||
+ outStr.contains("Could not allocate metaspace at a compatible address") ||
+ outStr.contains("Unable to allocate shared string space: range is not within java heap") ))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ // check result of 'exec' operation, that is when JVM is run using the archive
+ public static void checkExec(OutputAnalyzer output, String... extraMatches) throws Exception {
+ if (isUnableToMap(output)) {
+ System.out.println("Unable to map shared archive: test did not complete; assumed PASS");
+ return;
+ }
+ output.shouldContain("sharing");
+ output.shouldHaveExitValue(0);
+
+ for (String match : extraMatches) {
+ output.shouldContain(match);
+ }
+ }
+
+
+ // get the file object for the test artifact
+ private static File getTestArtifactFile(String prefix, String name) {
+ File dir = new File(System.getProperty("test.classes", "."));
+ return new File(dir, prefix + name);
+ }
+
+
+ // create file containing the specified class list
+ public static File makeClassList(String testCaseName, String classes[])
+ throws Exception {
+
+ File classList = getTestArtifactFile(testCaseName, "test.classlist");
+ FileOutputStream fos = new FileOutputStream(classList);
+ PrintStream ps = new PrintStream(fos);
+
+ addToClassList(ps, classes);
+
+ ps.close();
+ fos.close();
+
+ return classList;
+ }
+
+
+ private static void addToClassList(PrintStream ps, String classes[])
+ throws IOException
+ {
+ if (classes != null) {
+ for (String s : classes) {
+ ps.println(s);
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java Wed Oct 05 06:28:23 2016 -0700
@@ -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.
+ *
+ * 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.
+ */
+
+public class Implementor implements Interface {
+ public static void main(String[] args) {
+ System.out.println("Implementor: entering main()");
+ test();
+ }
+
+ public static void test() {
+ // from interface
+ (new Implementor()).printString();
+ // from implementor
+ System.out.println(TransformUtil.ChildCheckPattern +
+ TransformUtil.BeforePattern);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+public interface Interface {
+ public static final String stringToBeTransformed =
+ TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern;
+
+ default void printString() {
+ System.out.println(stringToBeTransformed);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java Wed Oct 05 06:28:23 2016 -0700
@@ -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.
+ */
+
+public class SubClass extends SuperClazz {
+ public static void main(String[] args) {
+ System.out.println("SubClass: entering main()");
+ test();
+ }
+
+ public static void test() {
+ // The line below will be used to check for successful class transformation
+ System.out.println(TransformUtil.ChildCheckPattern +
+ TransformUtil.BeforePattern);
+ (new SubClass()).callParent();
+ }
+
+ private void callParent() {
+ super.testParent();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+
+public class SuperClazz {
+ public static void testParent() {
+ System.out.println("SuperClazz: entering testParent()");
+
+ // The line below will be used to check for successful class transformation
+ System.out.println(TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,45 @@
+/*
+ * 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 Entry - a single entry in a test table
+// that defines a test case
+// See TransformRelatedClasses.java for more details
+public class TestEntry {
+ int testCaseId;
+ boolean transformParent;
+ boolean transformChild;
+ boolean isParentExpectedShared;
+ boolean isChildExpectedShared;
+
+ public TestEntry(int testCaseId,
+ boolean transformParent, boolean transformChild,
+ boolean isParentExpectedShared, boolean isChildExpectedShared) {
+ this.testCaseId = testCaseId;
+ this.transformParent = transformParent;
+ this.transformChild = transformChild;
+ this.isParentExpectedShared = isParentExpectedShared;
+ this.isChildExpectedShared = isChildExpectedShared;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ * with CDS with Interface/Implementor pair
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ * jdk.jartool/sun.tools.jar
+ * java.management
+ * java.instrument
+ * @build TransformUtil TransformerAgent Interface Implementor
+ * @run main/othervm TransformRelatedClasses Interface Implementor
+ */
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related interface
+// and its implementor in combination with CDS.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to an interface and an implementor in a combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+
+// This is the main test class for testing transformation of related classes
+// in combination with CDS, to ensure these features work well together.
+// The relationships that can be tested using this test class are:
+// superclass/subclass, and interface/implementor relationships.
+//
+// The test uses combinatorial approach.
+// For details on test table and test cases see main() method in this class.
+//
+// This test consists of multiple classes for better flexibility and reuse,
+// and also relies on certain common utility code.
+// Here are the details on the structure of the test
+//
+// Structure of the test:
+// TransformRelatedClasses -- common main test driver
+// The TransformRelatedClasses is invoked from test driver classes:
+// TransformInterfaceAndImplementor, TransformSuperAndSubClasses
+// It is responsible for preparing test artifacts (test jar, agent jar
+// and the shared archive), running test cases and checking the results.
+// The following test classes below are launched in a sub-process with use
+// of shared archive:
+// SuperClazz, SubClass -- super/sub class pair under test
+// Interface, Implementor -- classes under test
+// This test will transform these classes, based on the test case data,
+// by changing a predefined unique string in each class.
+// For more details, see the test classes' code and comments.
+//
+// Other related classes:
+// TestEntry - a class representing a single test case, as test entry in the table
+// TransformTestCommon - common methods for transformation test cases
+//
+// Other utility/helper classes and files used in this test:
+// TransformerAgent - an agent that is used when JVM-under-test is executed
+// to transform specific strings inside specified classes
+// TransformerAgent.mf - accompanies transformer agent
+// CDSTestUtils - Test Utilities common to all CDS tests
+
+import java.io.File;
+import java.util.ArrayList;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+
+public class TransformRelatedClasses {
+ static final String archiveName = "./TransformRelatedClasses.jsa";
+ static String agentClasses[] = {
+ "TransformerAgent",
+ "TransformerAgent$SimpleTransformer",
+ "TransformUtil"
+ };
+
+ String parent;
+ String child;
+ String[] testClasses = new String[2];
+ String[] testNames = new String[2];
+ String testJar;
+ String agentJar;
+
+
+ private static void log(String msg) {
+ System.out.println("TransformRelatedClasses: " + msg);
+ }
+
+
+ // This class is intended to test 2 parent-child relationships:
+ // 1. Base Class (parent) and Derived Class (child)
+ // 2. Interface (parent) and Implementor (child)
+ // Parameters to main(): parent, child
+ public static void main(String args[]) throws Exception {
+ TransformRelatedClasses test = new TransformRelatedClasses(args[0], args[1]);
+ test.prepare();
+
+ // Test Table
+ // TestEntry: (testCaseId, transformParent, tranformChild,
+ // isParentExpectedShared, isChildExpectedShared)
+ ArrayList<TestEntry> testTable = new ArrayList<>();
+
+ // base case - no tranformation - all expected to be shared
+ testTable.add(new TestEntry(0, false, false, true, true));
+
+ // transform parent only - both parent and child should not be shared
+ testTable.add(new TestEntry(1, true, false, false, false));
+
+ // transform parent and child - both parent and child should not be shared
+ testTable.add(new TestEntry(2, true, true, false, false));
+
+ // transform child only - parent should still be shared, but not child
+ testTable.add(new TestEntry(3, false, true, true, false));
+
+ // run the tests
+ for (TestEntry entry : testTable) {
+ test.runTest(entry);
+ }
+ }
+
+
+ public TransformRelatedClasses(String parent, String child) {
+ log("Constructor: parent = " + parent + ", child = " + child);
+ this.parent = parent;
+ this.child = child;
+ testClasses[0] = parent;
+ testClasses[1] = child;
+ testNames[0] = parent.replace('.', '/');
+ testNames[1] = child.replace('.', '/');
+ }
+
+
+ // same test jar and archive can be used for all test cases
+ private void prepare() throws Exception {
+ // create agent jar
+ // Agent is the same for all test cases
+ String pathToManifest = "../../../../testlibrary/jvmti/TransformerAgent.mf";
+ agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar",
+ ClassFileInstaller.Manifest.fromSourceFile(pathToManifest),
+ agentClasses);
+
+ // create a test jar
+ testJar =
+ ClassFileInstaller.writeJar(parent + "-" + child + ".jar",
+ testClasses);
+
+ // create an archive
+ File classList = CDSTestUtils.makeClassList("transform-" + parent,
+ testNames);
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+ "-Xbootclasspath/a:" + testJar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:ExtraSharedClassListFile=" +
+ classList.getPath(),
+ "-XX:SharedArchiveFile=" + archiveName,
+ "-XX:+PrintSharedSpaces",
+ "-Xshare:dump");
+ OutputAnalyzer out = new OutputAnalyzer(pb.start());
+ CDSTestUtils.checkDump(out);
+ }
+
+
+ private void runTest(TestEntry entry) throws Exception {
+ log("runTest(): testCaseId = " + entry.testCaseId);
+
+ // execute with archive
+ String agentParam = "-javaagent:" + agentJar + "=" +
+ TransformTestCommon.getAgentParams(entry, parent, child);
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+ "-Xbootclasspath/a:" + testJar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=" + archiveName,
+ "-Xlog:class+load=info",
+ "-Xshare:on", "-showversion",
+ agentParam, child);
+ OutputAnalyzer out = new OutputAnalyzer(pb.start());
+
+ TransformTestCommon.checkResults(entry, out, parent, child);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,51 @@
+/*
+ * 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
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ * with CDS with SubClass and SuperClass
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ * jdk.jartool/sun.tools.jar
+ * java.management
+ * java.instrument
+ * @build TransformUtil TransformerAgent SubClass SuperClazz
+ * @run main/othervm TransformRelatedClasses SuperClazz SubClass
+*/
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related superclass
+// and subclass in combination with CDS.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to a parent and child in combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ * with CDS with SubClass and SuperClass, each lives in own separate package
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ * jdk.jartool/sun.tools.jar
+ * java.management
+ * java.instrument
+ * @build TransformUtil TransformerAgent SubClass SuperClazz
+ * @compile myPkg2/SubClass.java myPkg1/SuperClazz.java
+ * @run main/othervm TransformRelatedClasses myPkg1.SuperClazz myPkg2.SubClass
+*/
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related superclass
+// and subclass in combination with CDS; each class lives in its own package.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to a parent and child in combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java Wed Oct 05 06:28:23 2016 -0700
@@ -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.
+ *
+ * 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 jdk.test.lib.process.OutputAnalyzer;
+
+
+// This class contains methods common to all transformation test cases
+public class TransformTestCommon {
+
+ // get parameters to an agent depending on the test case
+ // these parameters will instruct the agent which classes should be
+ // transformed
+ public static String getAgentParams(TestEntry entry,
+ String parent, String child) {
+
+ if (entry.transformParent && entry.transformChild)
+ return parent + "," + child;
+ if (entry.transformParent)
+ return parent;
+ if (entry.transformChild)
+ return child;
+
+ return "";
+ }
+
+
+ private static void checkTransformationResults(TestEntry entry,
+ OutputAnalyzer out)
+ throws Exception {
+
+ if (entry.transformParent)
+ out.shouldContain(TransformUtil.ParentCheckPattern +
+ TransformUtil.AfterPattern);
+
+ if (entry.transformChild)
+ out.shouldContain(TransformUtil.ChildCheckPattern +
+ TransformUtil.AfterPattern);
+ }
+
+
+ private static void checkSharingByClass(TestEntry entry, OutputAnalyzer out,
+ String parent, String child)
+ throws Exception {
+
+ String parentSharedMatch = parent + " source: shared objects file";
+ String childSharedMatch = child + " source: shared objects file";
+
+ if (entry.isParentExpectedShared)
+ out.shouldContain(parentSharedMatch);
+ else
+ out.shouldNotContain(parentSharedMatch);
+
+ if (entry.isChildExpectedShared)
+ out.shouldContain(childSharedMatch);
+ else
+ out.shouldNotContain(childSharedMatch);
+ }
+
+
+ // Both parent and child classes should be passed to ClassFileTransformer.transform()
+ // exactly once.
+ private static void checkTransformationCounts(TestEntry entry, OutputAnalyzer out,
+ String parent, String child)
+ throws Exception {
+
+ String patternBase = "TransformerAgent: SimpleTransformer called for: ";
+
+ out.shouldContain(patternBase + child + "@1");
+ out.shouldContain(patternBase + parent + "@1");
+
+ out.shouldNotContain(patternBase + child + "@2");
+ out.shouldNotContain(patternBase + parent + "@2");
+ }
+
+
+ public static void checkResults(TestEntry entry, OutputAnalyzer out,
+ String parent, String child)
+ throws Exception {
+
+ // If we were not able to map an archive,
+ // then do not perform other checks, since
+ // there was no sharing at all
+ if (CDSTestUtils.isUnableToMap(out))
+ return;
+
+ String childVmName = child.replace('.', '/');
+ String parentVmName = parent.replace('.', '/');
+
+ CDSTestUtils.checkExec(out);
+ checkTransformationCounts(entry, out, parentVmName, childVmName);
+ checkTransformationResults(entry, out);
+ checkSharingByClass(entry, out, parent, child);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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 myPkg1;
+
+public class SuperClazz {
+ public static void testParent() {
+ System.out.println("SuperClazz: entering testParent()");
+
+ // The line below will be used to check for successful class transformation
+ System.out.println("parent-transform-check: this-should-be-transformed");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,56 @@
+/*
+ * 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 myPkg2;
+
+import myPkg1.SuperClazz;
+
+public class SubClass extends SuperClazz {
+ public static void main(String[] args) {
+ System.out.println("SubClass: entering main()");
+ test();
+ }
+
+ public static void test() {
+ // The line below will be used to check for successful class transformation
+ System.out.println("child-transform-check: this-should-be-transformed");
+ (new SubClass()).callParent();
+
+ // Get the system packages, which should contain myPkg1 and myPkag2
+ Package[] pkgs = Package.getPackages();
+ for (int i = 0; i < pkgs.length; i++) {
+ if (pkgs[i].getName().equals("myPkg1")) {
+ for (int j = 0; j < pkgs.length; j++) {
+ if (pkgs[j].getName().equals("myPkg2")) {
+ return; // found myPkg1 & myPkg1
+ }
+ }
+ }
+ }
+ throw new RuntimeException("Missing system package");
+ }
+
+ private void callParent() {
+ super.testParent();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformUtil.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+
+public class TransformUtil {
+ public static final String BeforePattern = "this-should-be-transformed";
+ public static final String AfterPattern = "this-has-been--transformed";
+ public static final String ParentCheckPattern = "parent-transform-check: ";
+ public static final String ChildCheckPattern = "child-transform-check: ";
+
+ /**
+ * @return the number of occurrences of the <code>from</code> string that
+ * have been replaced.
+ */
+ public static int replace(byte buff[], String from, String to) {
+ if (to.length() != from.length()) {
+ throw new RuntimeException("bad strings");
+ }
+ byte f[] = asciibytes(from);
+ byte t[] = asciibytes(to);
+ byte f0 = f[0];
+
+ int numReplaced = 0;
+ int max = buff.length - f.length;
+ for (int i = 0; i < max; ) {
+ if (buff[i] == f0 && replace(buff, f, t, i)) {
+ i += f.length;
+ numReplaced++;
+ } else {
+ i++;
+ }
+ }
+ return numReplaced;
+ }
+
+ public static boolean replace(byte buff[], byte f[], byte t[], int i) {
+ for (int x = 0; x < f.length; x++) {
+ if (buff[x+i] != f[x]) {
+ return false;
+ }
+ }
+ for (int x = 0; x < f.length; x++) {
+ buff[x+i] = t[x];
+ }
+ return true;
+ }
+
+ static byte[] asciibytes(String s) {
+ byte b[] = new byte[s.length()];
+ for (int i = 0; i < b.length; i++) {
+ b[i] = (byte)s.charAt(i);
+ }
+ return b;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,100 @@
+/*
+ * 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.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+
+// This is a test utility class used to transform
+// specified classes via initial transformation (ClassFileLoadHook).
+// Names of classes to be transformed are supplied as arguments,
+// the phrase to be transformed is a hard-coded predefined
+// fairly unique phrase.
+
+public class TransformerAgent {
+ private static String[] classesToTransform;
+
+
+ private static void log(String msg) {
+ System.out.println("TransformerAgent: " + msg);
+ }
+
+
+ // arguments are comma-separated list of classes to transform
+ public static void premain(String agentArguments, Instrumentation instrumentation) {
+ log("premain() is called, arguments = " + agentArguments);
+ classesToTransform = agentArguments.split(",");
+ instrumentation.addTransformer(new SimpleTransformer(), /*canRetransform=*/true);
+ }
+
+
+ public static void agentmain(String args, Instrumentation inst) throws Exception {
+ log("agentmain() is called");
+ premain(args, inst);
+ }
+
+
+ static class SimpleTransformer implements ClassFileTransformer {
+ public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
+ ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
+
+ log("SimpleTransformer called for: " + name + "@" + incrCounter(name));
+ if (!shouldTransform(name))
+ return null;
+
+ log("transforming: class name = " + name);
+ int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern,
+ TransformUtil.AfterPattern);
+ log("replaced the string, nrOfReplacements = " + nrOfReplacements);
+ return buffer;
+ }
+
+ // Check class name pattern, since test should only transform certain classes
+ private static boolean shouldTransform(String name) {
+ for (String match : classesToTransform) {
+ if (name.matches(match)) {
+ log("shouldTransform: match-found, match = " + match);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+
+ static HashMap<String, Integer> counterMap = new HashMap<>();
+
+ static Integer incrCounter(String className) {
+ Integer i = counterMap.get(className);
+ if (i == null) {
+ i = new Integer(1);
+ } else {
+ i = new Integer(i.intValue() + 1);
+ }
+ counterMap.put(className, i);
+ return i;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.mf Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Premain-Class: TransformerAgent
+Agent-Class: TransformerAgent
+Can-Retransform-Classes: true
+Can-Redefine-Classes: false
--- a/jaxp/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/jaxp/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -380,3 +380,4 @@
f695240370c77a25fed88225a392e7d530cb4d78 jdk-9+135
f1eafcb0eb7182b937bc93f214d8cabd01ec4d59 jdk-9+136
a8d5fe567ae72b4931040e59dd4478363f9004f5 jdk-9+137
+69c3b12ba75b2e321dee731ac545e7fbff608451 jdk-9+138
--- a/jaxws/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/jaxws/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -383,3 +383,4 @@
22631824f55128a7ab6605493b3001a37af6a168 jdk-9+135
09ec13a99f50a4a346180d1e3b0fd8bc1ee399ce jdk-9+136
297c16d401c534cb879809d2a746d21ca99d2954 jdk-9+137
+7d3a8f52b124db26ba8425c2931b748dd9d2791b jdk-9+138
--- a/jdk/make/CompileDemos.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/CompileDemos.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -338,6 +338,7 @@
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jvmti/$1, \
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/lib, \
LIBRARY := $1, \
+ STRIP_SYMBOLS := false, \
))
$1 += $$(BUILD_DEMO_JVMTI_NATIVE_$1)
@@ -453,6 +454,7 @@
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jni/Poller, \
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native, \
LIBRARY := Poller, \
+ STRIP_SYMBOLS := false, \
))
TARGETS += $(BUILD_DEMO_NATIVE_Poller)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/CompileModuleTools.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,42 @@
+#
+# 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
+# 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 $(SPEC)
+include MakeBase.gmk
+include JavaCompilation.gmk
+include SetupJavaCompilers.gmk
+
+TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
+
+$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \
+ SETUP := GENERATE_USINGJDKBYTECODE, \
+ SRC := $(JDK_TOPDIR)/make/src/classes, \
+ INCLUDES := build/tools/deps \
+ build/tools/jigsaw, \
+ BIN := $(TOOLS_CLASSES_DIR), \
+ ADD_JAVAC_FLAGS := \
+ --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
+))
--- a/jdk/make/Import.gmk Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-#
-# 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
-# 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.
-#
-
-default: all
-
-include $(SPEC)
-include MakeBase.gmk
-
-################################################################################
-
-# Put the libraries here. Different locations for different target OS types.
-ifneq ($(OPENJDK_TARGET_OS), windows)
- HOTSPOT_LIB_DIR := $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)
- BASE_INSTALL_LIBRARIES_HERE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
-else
- HOTSPOT_LIB_DIR := $(HOTSPOT_DIST)/bin
- BASE_INSTALL_LIBRARIES_HERE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
-endif
-
-################################################################################
-#
-# Import hotspot
-#
-
-# Don't import jsig library for static builds
-ifneq ($(STATIC_BUILD), true)
- JSIG_IMPORT = jsig.*
-else
- JSIG_IMPORT =
-endif
-
-HOTSPOT_BASE_IMPORT_FILES := \
- $(addprefix $(LIBRARY_PREFIX), jvm.* $(JSIG_IMPORT) jvm_db.* jvm_dtrace.*) \
- Xusage.txt \
- #
-
-$(eval $(call SetupCopyFiles,COPY_HOTSPOT_BASE, \
- SRC := $(HOTSPOT_LIB_DIR), \
- DEST := $(BASE_INSTALL_LIBRARIES_HERE), \
- FILES := $(shell $(FIND) $(HOTSPOT_LIB_DIR) -type f \
- -a \( -name DUMMY $(addprefix -o$(SPACE)-name$(SPACE), $(HOTSPOT_BASE_IMPORT_FILES)) \) )))
-
-ifeq ($(OPENJDK_TARGET_OS), windows)
- $(eval $(call SetupCopyFiles,COPY_HOTSPOT_BASE_JVMLIB, \
- SRC := $(HOTSPOT_DIST)/lib, \
- DEST := $(BASE_INSTALL_LIBRARIES_HERE), \
- FILES := $(wildcard $(HOTSPOT_DIST)/lib/*.lib)))
-endif
-
-BASE_TARGETS := $(COPY_HOTSPOT_BASE) $(COPY_HOTSPOT_BASE_JVMLIB)
-
-################################################################################
-
-ifneq ($(STATIC_BUILD), true)
- ifeq ($(OPENJDK_TARGET_OS), macosx)
- JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
- $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
- else
- JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
- $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
- endif
-
- ifneq ($(OPENJDK_TARGET_OS), windows)
- ifeq ($(call check-jvm-variant, server), true)
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
- ifneq (, $(JSIG_DEBUGINFO))
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
- endif
- endif
- ifeq ($(call check-jvm-variant, client), true)
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
- ifneq (, $(JSIG_DEBUGINFO))
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
- endif
- endif
- ifneq ($(OPENJDK_TARGET_OS), macosx)
- ifeq ($(call check-jvm-variant, minimal), true)
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
- ifneq (,$(JSIG_DEBUGINFO))
- BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
- endif
- endif
- endif
- endif
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/server/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
- $(BASE_INSTALL_LIBRARIES_HERE)/server/%.dSYM:
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
- $(BASE_INSTALL_LIBRARIES_HERE)/server/%.diz : $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(RM) $@.tmp $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(LN) -s ../$(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM
- $(RM) $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(MV) $@.tmp $@
-else
- $(BASE_INSTALL_LIBRARIES_HERE)/server/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
- $(BASE_INSTALL_LIBRARIES_HERE)/server/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(RM) $@.tmp $(basename $@).debuginfo
- $(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
- $(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
- $(RM) $(basename $@).debuginfo
- $(MV) $@.tmp $@
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/client/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
- $(BASE_INSTALL_LIBRARIES_HERE)/client/%.dSYM : $(BASE_INSTALL_LIBRARIES_HERE)/%.dSYM
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
- $(BASE_INSTALL_LIBRARIES_HERE)/client/%.diz : $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(RM) $@.tmp $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(LN) -s ../$(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM
- $(RM) $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
- $(MV) $@.tmp $@
-else
- $(BASE_INSTALL_LIBRARIES_HERE)/client/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
- $(BASE_INSTALL_LIBRARIES_HERE)/client/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(RM) $@.tmp $(basename $@).debuginfo
- $(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
- $(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
- $(RM) $(basename $@).debuginfo
- $(MV) $@.tmp $@
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/minimal/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
-ifneq ($(OPENJDK_TARGET_OS), macosx)
- $(BASE_INSTALL_LIBRARIES_HERE)/minimal/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(LN) -s ../$(@F) $@
-
- $(BASE_INSTALL_LIBRARIES_HERE)/minimal/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(RM) $@.tmp $(basename $@).debuginfo
- $(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
- $(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
- $(RM) $(basename $@).debuginfo
- $(MV) $@.tmp $@
-endif
-
-################################################################################
-
-ifeq ($(OPENJDK_TARGET_OS), windows)
- $(eval $(call SetupCopyFiles,BASE_COPY_LIBS_BIN, \
- SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
- DEST := $(JDK_OUTPUTDIR)/bin, \
- FILES := $(filter-out %.lib, $(BASE_TARGETS))))
-
- $(eval $(call SetupCopyFiles,BASE_COPY_LIBS_LIB, \
- SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
- DEST := $(JDK_OUTPUTDIR)/lib, \
- FILES := $(filter %.lib, $(BASE_TARGETS))))
-
-else
- $(eval $(call SetupCopyFiles,BASE_COPY_LIBS, \
- SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
- DEST := $(JDK_OUTPUTDIR)/lib, \
- FILES := $(BASE_TARGETS)))
-endif
-
-################################################################################
-
-all: $(BASE_TARGETS) $(BASE_COPY_LIBS_BIN) $(BASE_COPY_LIBS_LIB) \
- $(BASE_COPY_LIBS)
-
-.PHONY: default all
--- a/jdk/make/ModuleTools.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/ModuleTools.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -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
@@ -26,18 +26,14 @@
include $(SPEC)
include MakeBase.gmk
include JavaCompilation.gmk
-include SetupJavaCompilers.gmk
TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
-$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \
- SETUP := GENERATE_USINGJDKBYTECODE, \
- SRC := $(JDK_TOPDIR)/make/src/classes, \
- INCLUDES := build/tools/deps \
- build/tools/jigsaw, \
- BIN := $(TOOLS_CLASSES_DIR), \
- ADD_JAVAC_FLAGS := --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED ))
-
+# To avoid reevaluating the compilation setup for the tools each time this file
+# is included, the actual compilation is handled by CompileModuleTools.gmk. The
+# following trick is used to be able to declare a dependency on the built tools.
+BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \
+ BUILD_JIGSAW_TOOLS, $(TOOLS_CLASSES_DIR))
TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
build.tools.jigsaw.GenGraphs
@@ -45,3 +41,8 @@
TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
--add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
build.tools.jigsaw.ModuleSummary
+
+TOOL_ADD_PACKAGES_ATTRIBUTE := $(BUILD_JAVA) $(JAVA_FLAGS_SMALL) \
+ -cp $(TOOLS_CLASSES_DIR) \
+ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
+ build.tools.jigsaw.AddPackagesAttribute
--- a/jdk/make/lib/CoreLibraries.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/lib/CoreLibraries.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -236,10 +236,6 @@
##########################################################################################
-ifeq ($(OPENJDK_TARGET_OS), aix)
- LIBJIMAGE_TOOLCHAIN := TOOLCHAIN_LINK_CXX
-endif # OPENJDK_TARGET_OS aix
-
JIMAGELIB_CPPFLAGS := \
-I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
-I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava \
@@ -249,7 +245,7 @@
$(eval $(call SetupNativeCompilation,BUILD_LIBJIMAGE, \
LIBRARY := jimage, \
- TOOLCHAIN := $(LIBJIMAGE_TOOLCHAIN), \
+ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
OPTIMIZATION := LOW, \
SRC := $(JDK_TOPDIR)/src/java.base/share/native/libjimage \
--- a/jdk/make/rmic/RmicCommon.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/rmic/RmicCommon.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -37,7 +37,7 @@
RMIC_MAIN_CLASS := sun.rmi.rmic.Main
endif
-RMIC := $(JAVA) $(INTERIM_OVERRIDE_MODULES_ARGS) $(RMIC_MAIN_CLASS)
+RMIC := $(JAVA_SMALL) $(INTERIM_OVERRIDE_MODULES_ARGS) $(RMIC_MAIN_CLASS)
CLASSES_DIR := $(JDK_OUTPUTDIR)/modules
# NOTE: If the smart javac dependency management is reintroduced, these classes risk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,89 @@
+/*
+ * 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 build.tools.jigsaw;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.internal.module.ModuleInfoExtender;
+
+/**
+ * Adds the Packages class file attribute to each module-info.class in an
+ * exploded build.
+ */
+
+public class AddPackagesAttribute {
+
+ public static void main(String[] args) throws IOException {
+
+ if (args.length != 1) {
+ System.err.println("Usage AddPackagesAttribute exploded-java-home");
+ System.exit(-1);
+ }
+
+ String home = args[0];
+ Path dir = Paths.get(home, "modules");
+
+ ModuleFinder finder = ModuleFinder.of(dir);
+
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+ for (Path entry : stream) {
+ Path mi = entry.resolve("module-info.class");
+ if (Files.isRegularFile(mi)) {
+ String mn = entry.getFileName().toString();
+ Optional<ModuleReference> omref = finder.find(mn);
+ if (omref.isPresent()) {
+ Set<String> packages = omref.get().descriptor().conceals();
+ addPackagesAttribute(mi, packages);
+ }
+ }
+ }
+ }
+ }
+
+ static void addPackagesAttribute(Path mi, Set<String> packages) throws IOException {
+ byte[] bytes;
+ try (InputStream in = Files.newInputStream(mi)) {
+ ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
+ extender.conceals(packages);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ extender.write(baos);
+ bytes = baos.toByteArray();
+ }
+
+ Files.write(mi, bytes);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,631 @@
+/*
+ * 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 java.io;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+
+/**
+ * Filter classes, array lengths, and graph metrics during deserialization.
+ * If set on an {@link ObjectInputStream}, the {@link #checkInput checkInput(FilterInfo)}
+ * method is called to validate classes, the length of each array,
+ * the number of objects being read from the stream, the depth of the graph,
+ * and the total number of bytes read from the stream.
+ * <p>
+ * A filter can be set via {@link ObjectInputStream#setObjectInputFilter setObjectInputFilter}
+ * for an individual ObjectInputStream.
+ * A filter can be set via {@link Config#setSerialFilter(ObjectInputFilter) Config.setSerialFilter}
+ * to affect every {@code ObjectInputStream} that does not otherwise set a filter.
+ * <p>
+ * A filter determines whether the arguments are {@link Status#ALLOWED ALLOWED}
+ * or {@link Status#REJECTED REJECTED} and should return the appropriate status.
+ * If the filter cannot determine the status it should return
+ * {@link Status#UNDECIDED UNDECIDED}.
+ * Filters should be designed for the specific use case and expected types.
+ * A filter designed for a particular use may be passed a class that is outside
+ * of the scope of the filter. If the purpose of the filter is to black-list classes
+ * then it can reject a candidate class that matches and report UNDECIDED for others.
+ * A filter may be called with class equals {@code null}, {@code arrayLength} equal -1,
+ * the depth, number of references, and stream size and return a status
+ * that reflects only one or only some of the values.
+ * This allows a filter to specific about the choice it is reporting and
+ * to use other filters without forcing either allowed or rejected status.
+ *
+ * <p>
+ * Typically, a custom filter should check if a process-wide filter
+ * is configured and defer to it if so. For example,
+ * <pre>{@code
+ * ObjectInputFilter.Status checkInput(FilterInfo info) {
+ * ObjectInputFilter serialFilter = ObjectInputFilter.Config.getSerialFilter();
+ * if (serialFilter != null) {
+ * ObjectInputFilter.Status status = serialFilter.checkInput(info);
+ * if (status != ObjectInputFilter.Status.UNDECIDED) {
+ * // The process-wide filter overrides this filter
+ * return status;
+ * }
+ * }
+ * if (info.serialClass() != null &&
+ * Remote.class.isAssignableFrom(info.serialClass())) {
+ * return Status.REJECTED; // Do not allow Remote objects
+ * }
+ * return Status.UNDECIDED;
+ * }
+ *}</pre>
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a
+ * method in this interface and its nested classes will cause a
+ * {@link NullPointerException} to be thrown.
+ *
+ * @see ObjectInputStream#setObjectInputFilter(ObjectInputFilter)
+ * @since 9
+ */
+@FunctionalInterface
+public interface ObjectInputFilter {
+
+ /**
+ * Check the class, array length, number of object references, depth,
+ * stream size, and other available filtering information.
+ * Implementations of this method check the contents of the object graph being created
+ * during deserialization. The filter returns {@link Status#ALLOWED Status.ALLOWED},
+ * {@link Status#REJECTED Status.REJECTED}, or {@link Status#UNDECIDED Status.UNDECIDED}.
+ *
+ * @param filterInfo provides information about the current object being deserialized,
+ * if any, and the status of the {@link ObjectInputStream}
+ * @return {@link Status#ALLOWED Status.ALLOWED} if accepted,
+ * {@link Status#REJECTED Status.REJECTED} if rejected,
+ * {@link Status#UNDECIDED Status.UNDECIDED} if undecided.
+ * @since 9
+ */
+ Status checkInput(FilterInfo filterInfo);
+
+ /**
+ * FilterInfo provides access to information about the current object
+ * being deserialized and the status of the {@link ObjectInputStream}.
+ * @since 9
+ */
+ interface FilterInfo {
+ /**
+ * The class of an object being deserialized.
+ * For arrays, it is the array type.
+ * For example, the array class name of a 2 dimensional array of strings is
+ * "{@code [[Ljava.lang.String;}".
+ * To check the array's element type, iteratively use
+ * {@link Class#getComponentType() Class.getComponentType} while the result
+ * is an array and then check the class.
+ * The {@code serialClass is null} in the case where a new object is not being
+ * created and to give the filter a chance to check the depth, number of
+ * references to existing objects, and the stream size.
+ *
+ * @return class of an object being deserialized; may be null
+ */
+ Class<?> serialClass();
+
+ /**
+ * The number of array elements when deserializing an array of the class.
+ *
+ * @return the non-negative number of array elements when deserializing
+ * an array of the class, otherwise -1
+ */
+ long arrayLength();
+
+ /**
+ * The current depth.
+ * The depth starts at {@code 1} and increases for each nested object and
+ * decrements when each nested object returns.
+ *
+ * @return the current depth
+ */
+ long depth();
+
+ /**
+ * The current number of object references.
+ *
+ * @return the non-negative current number of object references
+ */
+ long references();
+
+ /**
+ * The current number of bytes consumed.
+ * @implSpec {@code streamBytes} is implementation specific
+ * and may not be directly related to the object in the stream
+ * that caused the callback.
+ *
+ * @return the non-negative current number of bytes consumed
+ */
+ long streamBytes();
+ }
+
+ /**
+ * The status of a check on the class, array length, number of references,
+ * depth, and stream size.
+ *
+ * @since 9
+ */
+ enum Status {
+ /**
+ * The status is undecided, not allowed and not rejected.
+ */
+ UNDECIDED,
+ /**
+ * The status is allowed.
+ */
+ ALLOWED,
+ /**
+ * The status is rejected.
+ */
+ REJECTED;
+ }
+
+ /**
+ * A utility class to set and get the process-wide filter or create a filter
+ * from a pattern string. If a process-wide filter is set, it will be
+ * used for each {@link ObjectInputStream} that does not set its own filter.
+ * <p>
+ * When setting the filter, it should be stateless and idempotent,
+ * reporting the same result when passed the same arguments.
+ * <p>
+ * The filter is configured using the {@link java.security.Security}
+ * property {@code jdk.serialFilter} and can be overridden by
+ * the System property {@code jdk.serialFilter}.
+ *
+ * The syntax is the same as for the {@link #createFilter(String) createFilter} method.
+ *
+ * @since 9
+ */
+ final class Config {
+ /* No instances. */
+ private Config() {}
+
+ /**
+ * Lock object for process-wide filter.
+ */
+ private final static Object serialFilterLock = new Object();
+
+ /**
+ * Debug: Logger
+ */
+ private final static System.Logger configLog;
+
+ /**
+ * Logger for debugging.
+ */
+ static void filterLog(System.Logger.Level level, String msg, Object... args) {
+ if (configLog != null) {
+ configLog.log(level, msg, args);
+ }
+ }
+
+ /**
+ * The name for the process-wide deserialization filter.
+ * Used as a system property and a java.security.Security property.
+ */
+ private final static String SERIAL_FILTER_PROPNAME = "jdk.serialFilter";
+
+ /**
+ * The process-wide filter; may be null.
+ * Lookup the filter in java.security.Security or
+ * the system property.
+ */
+ private final static ObjectInputFilter configuredFilter;
+
+ static {
+ configuredFilter = AccessController
+ .doPrivileged((PrivilegedAction<ObjectInputFilter>) () -> {
+ String props = System.getProperty(SERIAL_FILTER_PROPNAME);
+ if (props == null) {
+ props = Security.getProperty(SERIAL_FILTER_PROPNAME);
+ }
+ if (props != null) {
+ System.Logger log =
+ System.getLogger("java.io.serialization");
+ log.log(System.Logger.Level.INFO,
+ "Creating serialization filter from {0}", props);
+ try {
+ return createFilter(props);
+ } catch (RuntimeException re) {
+ log.log(System.Logger.Level.ERROR,
+ "Error configuring filter: {0}", re);
+ }
+ }
+ return null;
+ });
+ configLog = (configuredFilter != null) ? System.getLogger("java.io.serialization") : null;
+ }
+
+ /**
+ * Current configured filter.
+ */
+ private static ObjectInputFilter serialFilter = configuredFilter;
+
+ /**
+ * Returns the process-wide serialization filter or {@code null} if not configured.
+ *
+ * @return the process-wide serialization filter or {@code null} if not configured
+ */
+ public static ObjectInputFilter getSerialFilter() {
+ synchronized (serialFilterLock) {
+ return serialFilter;
+ }
+ }
+
+ /**
+ * Set the process-wide filter if it has not already been configured or set.
+ *
+ * @param filter the serialization filter to set as the process-wide filter; not null
+ * @throws SecurityException if there is security manager and the
+ * {@code SerializablePermission("serialFilter")} is not granted
+ * @throws IllegalStateException if the filter has already been set {@code non-null}
+ */
+ public static void setSerialFilter(ObjectInputFilter filter) {
+ Objects.requireNonNull(filter, "filter");
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
+ }
+ synchronized (serialFilterLock) {
+ if (serialFilter != null) {
+ throw new IllegalStateException("Serial filter can only be set once");
+ }
+ serialFilter = filter;
+ }
+ }
+
+ /**
+ * Returns an ObjectInputFilter from a string of patterns.
+ * <p>
+ * Patterns are separated by ";" (semicolon). Whitespace is significant and
+ * is considered part of the pattern.
+ * If a pattern includes an equals assignment, "{@code =}" it sets a limit.
+ * If a limit appears more than once the last value is used.
+ * <ul>
+ * <li>maxdepth={@code value} - the maximum depth of a graph</li>
+ * <li>maxrefs={@code value} - the maximum number of internal references</li>
+ * <li>maxbytes={@code value} - the maximum number of bytes in the input stream</li>
+ * <li>maxarray={@code value} - the maximum array length allowed</li>
+ * </ul>
+ * <p>
+ * Other patterns match or reject class or package name
+ * as returned from {@link Class#getName() Class.getName()} and
+ * if an optional module name is present
+ * {@link java.lang.reflect.Module#getName() class.getModule().getName()}.
+ * Note that for arrays the element type is used in the pattern,
+ * not the array type.
+ * <ul>
+ * <li>If the pattern starts with "!", the class is rejected if the remaining pattern is matched;
+ * otherwise the class is allowed if the pattern matches.
+ * <li>If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
+ * if the module name matches the module name of the class then
+ * the remaining pattern is matched with the class name.
+ * If there is no "/", the module name is not compared.
+ * <li>If the pattern ends with ".**" it matches any class in the package and all subpackages.
+ * <li>If the pattern ends with ".*" it matches any class in the package.
+ * <li>If the pattern ends with "*", it matches any class with the pattern as a prefix.
+ * <li>If the pattern is equal to the class name, it matches.
+ * <li>Otherwise, the pattern is not matched.
+ * </ul>
+ * <p>
+ * The resulting filter performs the limit checks and then
+ * tries to match the class, if any. If any of the limits are exceeded,
+ * the filter returns {@link Status#REJECTED Status.REJECTED}.
+ * If the class is an array type, the class to be matched is the element type.
+ * Arrays of any number of dimensions are treated the same as the element type.
+ * For example, a pattern of "{@code !example.Foo}",
+ * rejects creation of any instance or array of {@code example.Foo}.
+ * The first pattern that matches, working from left to right, determines
+ * the {@link Status#ALLOWED Status.ALLOWED}
+ * or {@link Status#REJECTED Status.REJECTED} result.
+ * If nothing matches, the result is {@link Status#UNDECIDED Status.UNDECIDED}.
+ *
+ * @param pattern the pattern string to parse; not null
+ * @return a filter to check a class being deserialized; may be null;
+ * {@code null} if no patterns
+ * @throws IllegalArgumentException
+ * if a limit is missing the name, or the long value
+ * is not a number or is negative,
+ * or the module name is missing if the pattern contains "/"
+ * or if the package is missing for ".*" and ".**"
+ */
+ public static ObjectInputFilter createFilter(String pattern) {
+ Objects.requireNonNull(pattern, "pattern");
+ return Global.createFilter(pattern);
+ }
+
+ /**
+ * Implementation of ObjectInputFilter that performs the checks of
+ * the process-wide serialization filter. If configured, it will be
+ * used for all ObjectInputStreams that do not set their own filters.
+ *
+ */
+ final static class Global implements ObjectInputFilter {
+ /**
+ * The pattern used to create the filter.
+ */
+ private final String pattern;
+ /**
+ * The list of class filters.
+ */
+ private final List<Function<Class<?>, Status>> filters;
+ /**
+ * Maximum allowed bytes in the stream.
+ */
+ private long maxStreamBytes;
+ /**
+ * Maximum depth of the graph allowed.
+ */
+ private long maxDepth;
+ /**
+ * Maximum number of references in a graph.
+ */
+ private long maxReferences;
+ /**
+ * Maximum length of any array.
+ */
+ private long maxArrayLength;
+
+ /**
+ * Returns an ObjectInputFilter from a string of patterns.
+ *
+ * @param pattern the pattern string to parse
+ * @return a filter to check a class being deserialized; not null
+ * @throws IllegalArgumentException if the parameter is malformed
+ * if the pattern is missing the name, the long value
+ * is not a number or is negative.
+ */
+ static ObjectInputFilter createFilter(String pattern) {
+ Global filter = new Global(pattern);
+ return filter.isEmpty() ? null : filter;
+ }
+
+ /**
+ * Construct a new filter from the pattern String.
+ *
+ * @param pattern a pattern string of filters
+ * @throws IllegalArgumentException if the pattern is malformed
+ */
+ private Global(String pattern) {
+ this.pattern = pattern;
+
+ maxArrayLength = Long.MAX_VALUE; // Default values are unlimited
+ maxDepth = Long.MAX_VALUE;
+ maxReferences = Long.MAX_VALUE;
+ maxStreamBytes = Long.MAX_VALUE;
+
+ String[] patterns = pattern.split(";");
+ filters = new ArrayList<>(patterns.length);
+ for (int i = 0; i < patterns.length; i++) {
+ String p = patterns[i];
+ int nameLen = p.length();
+ if (nameLen == 0) {
+ continue;
+ }
+ if (parseLimit(p)) {
+ // If the pattern contained a limit setting, i.e. type=value
+ continue;
+ }
+ boolean negate = p.charAt(0) == '!';
+ int poffset = negate ? 1 : 0;
+
+ // isolate module name, if any
+ int slash = p.indexOf('/', poffset);
+ if (slash == poffset) {
+ throw new IllegalArgumentException("module name is missing in: \"" + pattern + "\"");
+ }
+ final String moduleName = (slash >= 0) ? p.substring(poffset, slash) : null;
+ poffset = (slash >= 0) ? slash + 1 : poffset;
+
+ final Function<Class<?>, Status> patternFilter;
+ if (p.endsWith("*")) {
+ // Wildcard cases
+ if (p.endsWith(".*")) {
+ // Pattern is a package name with a wildcard
+ final String pkg = p.substring(poffset, nameLen - 1);
+ if (pkg.length() < 2) {
+ throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
+ }
+ if (negate) {
+ // A Function that fails if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> matchesPackage(c, pkg) ? Status.REJECTED : Status.UNDECIDED;
+ } else {
+ // A Function that succeeds if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> matchesPackage(c, pkg) ? Status.ALLOWED : Status.UNDECIDED;
+ }
+ } else if (p.endsWith(".**")) {
+ // Pattern is a package prefix with a double wildcard
+ final String pkgs = p.substring(poffset, nameLen - 2);
+ if (pkgs.length() < 2) {
+ throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
+ }
+ if (negate) {
+ // A Function that fails if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> c.getName().startsWith(pkgs) ? Status.REJECTED : Status.UNDECIDED;
+ } else {
+ // A Function that succeeds if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> c.getName().startsWith(pkgs) ? Status.ALLOWED : Status.UNDECIDED;
+ }
+ } else {
+ // Pattern is a classname (possibly empty) with a trailing wildcard
+ final String className = p.substring(poffset, nameLen - 1);
+ if (negate) {
+ // A Function that fails if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> c.getName().startsWith(className) ? Status.REJECTED : Status.UNDECIDED;
+ } else {
+ // A Function that succeeds if the class starts with the pattern, otherwise don't care
+ patternFilter = c -> c.getName().startsWith(className) ? Status.ALLOWED : Status.UNDECIDED;
+ }
+ }
+ } else {
+ final String name = p.substring(poffset);
+ if (name.isEmpty()) {
+ throw new IllegalArgumentException("class or package missing in: \"" + pattern + "\"");
+ }
+ // Pattern is a class name
+ if (negate) {
+ // A Function that fails if the class equals the pattern, otherwise don't care
+ patternFilter = c -> c.getName().equals(name) ? Status.REJECTED : Status.UNDECIDED;
+ } else {
+ // A Function that succeeds if the class equals the pattern, otherwise don't care
+ patternFilter = c -> c.getName().equals(name) ? Status.ALLOWED : Status.UNDECIDED;
+ }
+ }
+ // If there is a moduleName, combine the module name check with the package/class check
+ if (moduleName == null) {
+ filters.add(patternFilter);
+ } else {
+ filters.add(c -> moduleName.equals(c.getModule().getName()) ? patternFilter.apply(c) : Status.UNDECIDED);
+ }
+ }
+ }
+
+ /**
+ * Returns if this filter has any checks.
+ * @return {@code true} if the filter has any checks, {@code false} otherwise
+ */
+ private boolean isEmpty() {
+ return filters.isEmpty() &&
+ maxArrayLength == Long.MAX_VALUE &&
+ maxDepth == Long.MAX_VALUE &&
+ maxReferences == Long.MAX_VALUE &&
+ maxStreamBytes == Long.MAX_VALUE;
+ }
+
+ /**
+ * Parse out a limit for one of maxarray, maxdepth, maxbytes, maxreferences.
+ *
+ * @param pattern a string with a type name, '=' and a value
+ * @return {@code true} if a limit was parsed, else {@code false}
+ * @throws IllegalArgumentException if the pattern is missing
+ * the name, the Long value is not a number or is negative.
+ */
+ private boolean parseLimit(String pattern) {
+ int eqNdx = pattern.indexOf('=');
+ if (eqNdx < 0) {
+ // not a limit pattern
+ return false;
+ }
+ String valueString = pattern.substring(eqNdx + 1);
+ if (pattern.startsWith("maxdepth=")) {
+ maxDepth = parseValue(valueString);
+ } else if (pattern.startsWith("maxarray=")) {
+ maxArrayLength = parseValue(valueString);
+ } else if (pattern.startsWith("maxrefs=")) {
+ maxReferences = parseValue(valueString);
+ } else if (pattern.startsWith("maxbytes=")) {
+ maxStreamBytes = parseValue(valueString);
+ } else {
+ throw new IllegalArgumentException("unknown limit: " + pattern.substring(0, eqNdx));
+ }
+ return true;
+ }
+
+ /**
+ * Parse the value of a limit and check that it is non-negative.
+ * @param string inputstring
+ * @return the parsed value
+ * @throws IllegalArgumentException if parsing the value fails or the value is negative
+ */
+ private static long parseValue(String string) throws IllegalArgumentException {
+ // Parse a Long from after the '=' to the end
+ long value = Long.parseLong(string);
+ if (value < 0) {
+ throw new IllegalArgumentException("negative limit: " + string);
+ }
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Status checkInput(FilterInfo filterInfo) {
+ if (filterInfo.references() < 0
+ || filterInfo.depth() < 0
+ || filterInfo.streamBytes() < 0
+ || filterInfo.references() > maxReferences
+ || filterInfo.depth() > maxDepth
+ || filterInfo.streamBytes() > maxStreamBytes) {
+ return Status.REJECTED;
+ }
+
+ Class<?> clazz = filterInfo.serialClass();
+ if (clazz != null) {
+ if (clazz.isArray()) {
+ if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > maxArrayLength) {
+ // array length is too big
+ return Status.REJECTED;
+ }
+ do {
+ // Arrays are decided based on the component type
+ clazz = clazz.getComponentType();
+ } while (clazz.isArray());
+ }
+
+ if (clazz.isPrimitive()) {
+ // Primitive types are undecided; let someone else decide
+ return Status.UNDECIDED;
+ } else {
+ // Find any filter that allowed or rejected the class
+ final Class<?> cl = clazz;
+ Optional<Status> status = filters.stream()
+ .map(f -> f.apply(cl))
+ .filter(p -> p != Status.UNDECIDED)
+ .findFirst();
+ return status.orElse(Status.UNDECIDED);
+ }
+ }
+ return Status.UNDECIDED;
+ }
+
+ /**
+ * Returns {@code true} if the class is in the package.
+ *
+ * @param c a class
+ * @param pkg a package name (including the trailing ".")
+ * @return {@code true} if the class is in the package,
+ * otherwise {@code false}
+ */
+ private static boolean matchesPackage(Class<?> c, String pkg) {
+ String n = c.getName();
+ return n.startsWith(pkg) && n.lastIndexOf('.') == pkg.length() - 1;
+ }
+
+ /**
+ * Returns the pattern used to create this filter.
+ * @return the pattern used to create this filter
+ */
+ @Override
+ public String toString() {
+ return pattern;
+ }
+ }
+ }
+}
--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Wed Oct 05 06:28:23 2016 -0700
@@ -26,6 +26,7 @@
package java.io;
import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.System.Logger;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
@@ -37,10 +38,12 @@
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+
import static java.io.ObjectStreamClass.processQueue;
-import jdk.internal.misc.JavaObjectInputStreamAccess;
+
import jdk.internal.misc.ObjectStreamClassValidator;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.Unsafe;
@@ -172,6 +175,16 @@
* protected) or that there are get and set methods that can be used to restore
* the state.
*
+ * <p>The contents of the stream can be filtered during deserialization.
+ * If a {@linkplain #setObjectInputFilter(ObjectInputFilter) filter is set}
+ * on an ObjectInputStream, the {@link ObjectInputFilter} can check that
+ * the classes, array lengths, number of references in the stream, depth, and
+ * number of bytes consumed from the input stream are allowed and
+ * if not, can terminate deserialization.
+ * A {@linkplain ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter) process-wide filter}
+ * can be configured that is applied to each {@code ObjectInputStream} unless replaced
+ * using {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter}.
+ *
* <p>Any exception that occurs while deserializing an object will be caught by
* the ObjectInputStream and abort the reading process.
*
@@ -240,12 +253,32 @@
new ReferenceQueue<>();
}
+ /*
+ * Separate class to defer initialization of logging until needed.
+ */
+ private static class Logging {
+ /*
+ * Logger for ObjectInputFilter results.
+ * Setup the filter logger if it is set to DEBUG or TRACE.
+ * (Assuming it will not change).
+ */
+ static final System.Logger filterLogger;
+
+ static {
+ Logger filterLog = System.getLogger("java.io.serialization");
+ filterLogger = (filterLog.isLoggable(Logger.Level.DEBUG)
+ || filterLog.isLoggable(Logger.Level.TRACE)) ? filterLog : null;
+ }
+ }
+
/** filter stream for handling block data conversion */
private final BlockDataInputStream bin;
/** validation callback list */
private final ValidationList vlist;
/** recursion depth */
- private int depth;
+ private long depth;
+ /** Total number of references to any type of object, class, enum, proxy, etc. */
+ private long totalObjectRefs;
/** whether stream is closed */
private boolean closed;
@@ -269,11 +302,20 @@
private SerialCallbackContext curContext;
/**
+ * Filter of class descriptors and classes read from the stream;
+ * may be null.
+ */
+ private ObjectInputFilter serialFilter;
+
+ /**
* Creates an ObjectInputStream that reads from the specified InputStream.
* A serialization stream header is read from the stream and verified.
* This constructor will block until the corresponding ObjectOutputStream
* has written and flushed the header.
*
+ * <p>The serialization filter is initialized to the value of
+ * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}.
+ *
* <p>If a security manager is installed, this constructor will check for
* the "enableSubclassImplementation" SerializablePermission when invoked
* directly or indirectly by the constructor of a subclass which overrides
@@ -295,6 +337,7 @@
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
+ serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
@@ -305,6 +348,9 @@
* ObjectInputStream to not have to allocate private data just used by this
* implementation of ObjectInputStream.
*
+ * <p>The serialization filter is initialized to the value of
+ * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}.
+ *
* <p>If there is a security manager installed, this method first calls the
* security manager's <code>checkPermission</code> method with the
* <code>SerializablePermission("enableSubclassImplementation")</code>
@@ -325,6 +371,7 @@
bin = null;
handles = null;
vlist = null;
+ serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = true;
}
@@ -332,7 +379,7 @@
* Read an object from the ObjectInputStream. The class of the object, the
* signature of the class, and the values of the non-transient and
* non-static fields of the class and all of its supertypes are read.
- * Default deserializing for a class can be overriden using the writeObject
+ * Default deserializing for a class can be overridden using the writeObject
* and readObject methods. Objects referenced by this object are read
* transitively so that a complete equivalent graph of objects is
* reconstructed by readObject.
@@ -343,6 +390,10 @@
* priorities. The callbacks are registered by objects (in the readObject
* special methods) as they are individually restored.
*
+ * <p>The serialization filter, when not {@code null}, is invoked for
+ * each object (regular or class) read to reconstruct the root object.
+ * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
+ *
* <p>Exceptions are thrown for problems with the InputStream and for
* classes that should not be deserialized. All exceptions are fatal to
* the InputStream and leave it in an indeterminate state; it is up to the
@@ -438,6 +489,10 @@
* invocation of readObject or readUnshared on the ObjectInputStream,
* even if the underlying data stream has been manipulated.
*
+ * <p>The serialization filter, when not {@code null}, is invoked for
+ * each object (regular or class) read to reconstruct the root object.
+ * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
+ *
* <p>ObjectInputStream subclasses which override this method can only be
* constructed in security contexts possessing the
* "enableSubclassImplementation" SerializablePermission; any attempt to
@@ -1094,6 +1149,134 @@
}
/**
+ * Returns the serialization filter for this stream.
+ * The serialization filter is the most recent filter set in
+ * {@link #setObjectInputFilter setObjectInputFilter} or
+ * the initial process-wide filter from
+ * {@link ObjectInputFilter.Config#getSerialFilter() ObjectInputFilter.Config.getSerialFilter}.
+ *
+ * @return the serialization filter for the stream; may be null
+ * @since 9
+ */
+ public final ObjectInputFilter getObjectInputFilter() {
+ return serialFilter;
+ }
+
+ /**
+ * Set the serialization filter for the stream.
+ * The filter's {@link ObjectInputFilter#checkInput checkInput} method is called
+ * for each class and reference in the stream.
+ * The filter can check any or all of the class, the array length, the number
+ * of references, the depth of the graph, and the size of the input stream.
+ * <p>
+ * If the filter returns {@link ObjectInputFilter.Status#REJECTED Status.REJECTED},
+ * {@code null} or throws a {@link RuntimeException},
+ * the active {@code readObject} or {@code readUnshared}
+ * throws {@link InvalidClassException}, otherwise deserialization
+ * continues uninterrupted.
+ * <p>
+ * The serialization filter is initialized to the value of
+ * {@link ObjectInputFilter.Config#getSerialFilter() ObjectInputFilter.Config.getSerialFilter}
+ * when the {@code ObjectInputStream} is constructed and can be set
+ * to a custom filter only once.
+ *
+ * @implSpec
+ * The filter, when not {@code null}, is invoked during {@link #readObject readObject}
+ * and {@link #readUnshared readUnshared} for each object
+ * (regular or class) in the stream including the following:
+ * <ul>
+ * <li>each object reference previously deserialized from the stream
+ * (class is {@code null}, arrayLength is -1),
+ * <li>each regular class (class is not {@code null}, arrayLength is -1),
+ * <li>each interface of a dynamic proxy and the dynamic proxy class itself
+ * (class is not {@code null}, arrayLength is -1),
+ * <li>each array is filtered using the array type and length of the array
+ * (class is the array type, arrayLength is the requested length),
+ * <li>each object replaced by its class' {@code readResolve} method
+ * is filtered using the replacement object's class, if not {@code null},
+ * and if it is an array, the arrayLength, otherwise -1,
+ * <li>and each object replaced by {@link #resolveObject resolveObject}
+ * is filtered using the replacement object's class, if not {@code null},
+ * and if it is an array, the arrayLength, otherwise -1.
+ * </ul>
+ *
+ * When the {@link ObjectInputFilter#checkInput checkInput} method is invoked
+ * it is given access to the current class, the array length,
+ * the current number of references already read from the stream,
+ * the depth of nested calls to {@link #readObject readObject} or
+ * {@link #readUnshared readUnshared},
+ * and the implementation dependent number of bytes consumed from the input stream.
+ * <p>
+ * Each call to {@link #readObject readObject} or
+ * {@link #readUnshared readUnshared} increases the depth by 1
+ * before reading an object and decreases by 1 before returning
+ * normally or exceptionally.
+ * The depth starts at {@code 1} and increases for each nested object and
+ * decrements when each nested call returns.
+ * The count of references in the stream starts at {@code 1} and
+ * is increased before reading an object.
+ *
+ * @param filter the filter, may be null
+ * @throws SecurityException if there is security manager and the
+ * {@code SerializablePermission("serialFilter")} is not granted
+ * @throws IllegalStateException if the {@linkplain #getObjectInputFilter() current filter}
+ * is not {@code null} and is not the process-wide filter
+ * @since 9
+ */
+ public final void setObjectInputFilter(ObjectInputFilter filter) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
+ }
+ // Allow replacement of the process-wide filter if not already set
+ if (serialFilter != null &&
+ serialFilter != ObjectInputFilter.Config.getSerialFilter()) {
+ throw new IllegalStateException("filter can not be set more than once");
+ }
+ this.serialFilter = filter;
+ }
+
+ /**
+ * Invoke the serialization filter if non-null.
+ * If the filter rejects or an exception is thrown, throws InvalidClassException.
+ *
+ * @param clazz the class; may be null
+ * @param arrayLength the array length requested; use {@code -1} if not creating an array
+ * @throws InvalidClassException if it rejected by the filter or
+ * a {@link RuntimeException} is thrown
+ */
+ private void filterCheck(Class<?> clazz, int arrayLength)
+ throws InvalidClassException {
+ if (serialFilter != null) {
+ RuntimeException ex = null;
+ ObjectInputFilter.Status status;
+ try {
+ status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
+ totalObjectRefs, depth, bin.getBytesRead()));
+ } catch (RuntimeException e) {
+ // Preventive interception of an exception to log
+ status = ObjectInputFilter.Status.REJECTED;
+ ex = e;
+ }
+ if (Logging.filterLogger != null) {
+ // Debug logging of filter checks that fail; Tracing for those that succeed
+ Logging.filterLogger.log(status == null || status == ObjectInputFilter.Status.REJECTED
+ ? Logger.Level.DEBUG
+ : Logger.Level.TRACE,
+ "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
+ status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
+ Objects.toString(ex, "n/a"));
+ }
+ if (status == null ||
+ status == ObjectInputFilter.Status.REJECTED) {
+ InvalidClassException ice = new InvalidClassException("filter status: " + status);
+ ice.initCause(ex);
+ throw ice;
+ }
+ }
+ }
+
+ /**
* Provide access to the persistent fields read from the input stream.
*/
public abstract static class GetField {
@@ -1280,7 +1463,7 @@
*/
private static Boolean auditSubclass(Class<?> subcl) {
return AccessController.doPrivileged(
- new PrivilegedAction<>() {
+ new PrivilegedAction<Boolean>() {
public Boolean run() {
for (Class<?> cl = subcl;
cl != ObjectInputStream.class;
@@ -1340,6 +1523,7 @@
}
depth++;
+ totalObjectRefs++;
try {
switch (tc) {
case TC_NULL:
@@ -1416,6 +1600,15 @@
}
Object rep = resolveObject(obj);
if (rep != obj) {
+ // The type of the original object has been filtered but resolveObject
+ // may have replaced it; filter the replacement's type
+ if (rep != null) {
+ if (rep.getClass().isArray()) {
+ filterCheck(rep.getClass(), Array.getLength(rep));
+ } else {
+ filterCheck(rep.getClass(), -1);
+ }
+ }
handles.setObject(passHandle, rep);
}
return rep;
@@ -1486,6 +1679,7 @@
throw new InvalidObjectException(
"cannot read back reference to unshared object");
}
+ filterCheck(null, -1); // just a check for number of references, depth, no class
return obj;
}
@@ -1590,6 +1784,10 @@
ReflectUtil.checkProxyPackageAccess(
getClass().getClassLoader(),
cl.getInterfaces());
+ // Filter the interfaces
+ for (Class<?> clazz : cl.getInterfaces()) {
+ filterCheck(clazz, -1);
+ }
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
@@ -1598,6 +1796,9 @@
desc.initProxy(cl, resolveEx, readClassDesc(false));
+ // Call filterCheck on the definition
+ filterCheck(desc.forClass(), -1);
+
handles.finish(descHandle);
passHandle = descHandle;
return desc;
@@ -1645,8 +1846,12 @@
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
+ // Call filterCheck on the definition
+ filterCheck(desc.forClass(), -1);
+
handles.finish(descHandle);
passHandle = descHandle;
+
return desc;
}
@@ -1687,6 +1892,8 @@
ObjectStreamClass desc = readClassDesc(false);
int len = bin.readInt();
+ filterCheck(desc.forClass(), len);
+
Object array = null;
Class<?> cl, ccl = null;
if ((cl = desc.forClass()) != null) {
@@ -1835,6 +2042,14 @@
rep = cloneArray(rep);
}
if (rep != obj) {
+ // Filter the replacement object
+ if (rep != null) {
+ if (rep.getClass().isArray()) {
+ filterCheck(rep.getClass(), Array.getLength(rep));
+ } else {
+ filterCheck(rep.getClass(), -1);
+ }
+ }
handles.setObject(passHandle, obj = rep);
}
}
@@ -2360,7 +2575,7 @@
try {
while (list != null) {
AccessController.doPrivileged(
- new PrivilegedExceptionAction<>()
+ new PrivilegedExceptionAction<Void>()
{
public Void run() throws InvalidObjectException {
list.obj.validateObject();
@@ -2384,6 +2599,51 @@
}
/**
+ * Hold a snapshot of values to be passed to an ObjectInputFilter.
+ */
+ static class FilterValues implements ObjectInputFilter.FilterInfo {
+ final Class<?> clazz;
+ final long arrayLength;
+ final long totalObjectRefs;
+ final long depth;
+ final long streamBytes;
+
+ public FilterValues(Class<?> clazz, long arrayLength, long totalObjectRefs,
+ long depth, long streamBytes) {
+ this.clazz = clazz;
+ this.arrayLength = arrayLength;
+ this.totalObjectRefs = totalObjectRefs;
+ this.depth = depth;
+ this.streamBytes = streamBytes;
+ }
+
+ @Override
+ public Class<?> serialClass() {
+ return clazz;
+ }
+
+ @Override
+ public long arrayLength() {
+ return arrayLength;
+ }
+
+ @Override
+ public long references() {
+ return totalObjectRefs;
+ }
+
+ @Override
+ public long depth() {
+ return depth;
+ }
+
+ @Override
+ public long streamBytes() {
+ return streamBytes;
+ }
+ }
+
+ /**
* Input stream supporting single-byte peek operations.
*/
private static class PeekInputStream extends InputStream {
@@ -2392,6 +2652,8 @@
private final InputStream in;
/** peeked byte */
private int peekb = -1;
+ /** total bytes read from the stream */
+ private long totalBytesRead = 0;
/**
* Creates new PeekInputStream on top of given underlying stream.
@@ -2405,7 +2667,12 @@
* that it does not consume the read value.
*/
int peek() throws IOException {
- return (peekb >= 0) ? peekb : (peekb = in.read());
+ if (peekb >= 0) {
+ return peekb;
+ }
+ peekb = in.read();
+ totalBytesRead += peekb >= 0 ? 1 : 0;
+ return peekb;
}
public int read() throws IOException {
@@ -2414,21 +2681,27 @@
peekb = -1;
return v;
} else {
- return in.read();
+ int nbytes = in.read();
+ totalBytesRead += nbytes >= 0 ? 1 : 0;
+ return nbytes;
}
}
public int read(byte[] b, int off, int len) throws IOException {
+ int nbytes;
if (len == 0) {
return 0;
} else if (peekb < 0) {
- return in.read(b, off, len);
+ nbytes = in.read(b, off, len);
+ totalBytesRead += nbytes >= 0 ? nbytes : 0;
+ return nbytes;
} else {
b[off++] = (byte) peekb;
len--;
peekb = -1;
- int n = in.read(b, off, len);
- return (n >= 0) ? (n + 1) : 1;
+ nbytes = in.read(b, off, len);
+ totalBytesRead += nbytes >= 0 ? nbytes : 0;
+ return (nbytes >= 0) ? (nbytes + 1) : 1;
}
}
@@ -2453,7 +2726,9 @@
skipped++;
n--;
}
- return skipped + in.skip(n);
+ n = skipped + in.skip(n);
+ totalBytesRead += n;
+ return n;
}
public int available() throws IOException {
@@ -2463,6 +2738,10 @@
public void close() throws IOException {
in.close();
}
+
+ public long getBytesRead() {
+ return totalBytesRead;
+ }
}
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
@@ -3346,6 +3625,14 @@
throw new UTFDataFormatException();
}
}
+
+ /**
+ * Returns the number of bytes read from the input stream.
+ * @return the number of bytes read from the input stream
+ */
+ long getBytesRead() {
+ return in.getBytesRead();
+ }
}
/**
--- a/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java Wed Oct 05 06:28:23 2016 -0700
@@ -199,6 +199,16 @@
*/
static final SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new SerializablePermission("enableSubclassImplementation");
+
+ /**
+ * Enable setting the process-wide serial filter.
+ *
+ * @see java.io.ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter)
+ * @since 9
+ */
+ static final SerializablePermission SERIAL_FILTER_PERMISSION =
+ new SerializablePermission("serialFilter");
+
/**
* A Stream Protocol Version. <p>
*
--- a/jdk/src/java.base/share/classes/java/io/SerializablePermission.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/SerializablePermission.java Wed Oct 05 06:28:23 2016 -0700
@@ -40,7 +40,7 @@
* The target name is the name of the Serializable permission (see below).
*
* <P>
- * The following table lists all the possible SerializablePermission target names,
+ * The following table lists the standard {@code SerializablePermission} target names,
* and for each provides a description of what the permission allows
* and a discussion of the risks of granting code the permission.
*
@@ -73,6 +73,13 @@
* malignant data.</td>
* </tr>
*
+ * <tr>
+ * <td>serialFilter</td>
+ * <td>Setting a filter for ObjectInputStreams.</td>
+ * <td>Code could remove a configured filter and remove protections
+ * already established.</td>
+ * </tr>
+ *
* </table>
*
* @see java.security.BasicPermission
--- a/jdk/src/java.base/share/classes/java/lang/String.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/String.java Wed Oct 05 06:28:23 2016 -0700
@@ -1516,11 +1516,12 @@
* @return a hash code value for this object.
*/
public int hashCode() {
- if (hash == 0 && value.length > 0) {
- hash = isLatin1() ? StringLatin1.hashCode(value)
- : StringUTF16.hashCode(value);
+ int h = hash;
+ if (h == 0 && value.length > 0) {
+ hash = h = isLatin1() ? StringLatin1.hashCode(value)
+ : StringUTF16.hashCode(value);
}
- return hash;
+ return h;
}
/**
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Wed Oct 05 06:28:23 2016 -0700
@@ -56,6 +56,8 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
import jdk.internal.module.ConfigurableModuleFinder;
import jdk.internal.perf.PerfCounter;
@@ -294,11 +296,11 @@
// -- jmod files --
- private Set<String> jmodPackages(ZipFile zf) {
- return zf.stream()
- .filter(e -> e.getName().startsWith("classes/") &&
- e.getName().endsWith(".class"))
- .map(e -> toPackageName(e.getName().substring(8)))
+ private Set<String> jmodPackages(JmodFile jf) {
+ return jf.stream()
+ .filter(e -> e.section() == Section.CLASSES)
+ .map(JmodFile.Entry::name)
+ .map(this::toPackageName)
.filter(pkg -> pkg.length() > 0) // module-info
.collect(Collectors.toSet());
}
@@ -311,14 +313,10 @@
* @throws InvalidModuleDescriptorException
*/
private ModuleReference readJMod(Path file) throws IOException {
- try (ZipFile zf = new ZipFile(file.toString())) {
- ZipEntry ze = zf.getEntry("classes/" + MODULE_INFO);
- if (ze == null) {
- throw new IOException(MODULE_INFO + " is missing: " + file);
- }
+ try (JmodFile jf = new JmodFile(file)) {
ModuleDescriptor md;
- try (InputStream in = zf.getInputStream(ze)) {
- md = ModuleDescriptor.read(in, () -> jmodPackages(zf));
+ try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+ md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
}
return ModuleReferences.newJModModule(md, file);
}
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Wed Oct 05 06:28:23 2016 -0700
@@ -93,23 +93,19 @@
/**
* Create a multicast socket.
*
- * <p>If there is a security manager,
- * its {@code checkListen} method is first called
- * with 0 as its argument to ensure the operation is allowed.
- * This could result in a SecurityException.
+ * <p>
+ * If there is a security manager, its {@code checkListen} method is first
+ * called with 0 as its argument to ensure the operation is allowed. This
+ * could result in a SecurityException.
* <p>
* When the socket is created the
- * {@link DatagramSocket#setReuseAddress(boolean)} method is
- * called to enable the SO_REUSEADDR socket option. When
- * {@link StandardSocketOptions#SO_REUSEPORT SO_REUSEPORT} is
- * supported then
- * {@link DatagramSocketImpl#setOption(SocketOption, Object)}
- * is called to enable the socket option.
+ * {@link DatagramSocket#setReuseAddress(boolean)} method is called to
+ * enable the SO_REUSEADDR socket option.
*
- * @exception IOException if an I/O exception occurs
- * while creating the MulticastSocket
- * @exception SecurityException if a security manager exists and its
- * {@code checkListen} method doesn't allow the operation.
+ * @exception IOException if an I/O exception occurs while creating the
+ * MulticastSocket
+ * @exception SecurityException if a security manager exists and its
+ * {@code checkListen} method doesn't allow the operation.
* @see SecurityManager#checkListen
* @see java.net.DatagramSocket#setReuseAddress(boolean)
* @see java.net.DatagramSocketImpl#setOption(SocketOption, Object)
@@ -174,17 +170,13 @@
// Enable SO_REUSEADDR before binding
setReuseAddress(true);
- // Enable SO_REUSEPORT if supported before binding
- if (supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
- this.setOption(StandardSocketOptions.SO_REUSEPORT, true);
- }
-
if (bindaddr != null) {
try {
bind(bindaddr);
} finally {
- if (!isBound())
+ if (!isBound()) {
close();
+ }
}
}
}
--- a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -968,7 +968,7 @@
* Decimal : min = 0. max = 3.
*
*/
- private void checkAndSetFastPathStatus() {
+ private boolean checkAndSetFastPathStatus() {
boolean fastPathWasOn = isFastPath;
@@ -998,12 +998,27 @@
} else
isFastPath = false;
+ resetFastPathData(fastPathWasOn);
+ fastPathCheckNeeded = false;
+
+ /*
+ * Returns true after successfully checking the fast path condition and
+ * setting the fast path data. The return value is used by the
+ * fastFormat() method to decide whether to call the resetFastPathData
+ * method to reinitialize fast path data or is it already initialized
+ * in this method.
+ */
+ return true;
+ }
+
+ private void resetFastPathData(boolean fastPathWasOn) {
// Since some instance properties may have changed while still falling
// in the fast-path case, we need to reinitialize fastPathData anyway.
if (isFastPath) {
// We need to instantiate fastPathData if not already done.
- if (fastPathData == null)
+ if (fastPathData == null) {
fastPathData = new FastPathData();
+ }
// Sets up the locale specific constants used when formatting.
// '0' is our default representation of zero.
@@ -1011,22 +1026,27 @@
fastPathData.groupingChar = symbols.getGroupingSeparator();
// Sets up fractional constants related to currency/decimal pattern.
- fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
- fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
+ fastPathData.fractionalMaxIntBound = (isCurrencyFormat)
+ ? 99 : 999;
+ fastPathData.fractionalScaleFactor = (isCurrencyFormat)
+ ? 100.0d : 1000.0d;
// Records the need for adding prefix or suffix
- fastPathData.positiveAffixesRequired =
- (positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
- fastPathData.negativeAffixesRequired =
- (negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
+ fastPathData.positiveAffixesRequired
+ = (positivePrefix.length() != 0)
+ || (positiveSuffix.length() != 0);
+ fastPathData.negativeAffixesRequired
+ = (negativePrefix.length() != 0)
+ || (negativeSuffix.length() != 0);
// Creates a cached char container for result, with max possible size.
int maxNbIntegralDigits = 10;
int maxNbGroups = 3;
- int containerSize =
- Math.max(positivePrefix.length(), negativePrefix.length()) +
- maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
- Math.max(positiveSuffix.length(), negativeSuffix.length());
+ int containerSize
+ = Math.max(positivePrefix.length(), negativePrefix.length())
+ + maxNbIntegralDigits + maxNbGroups + 1
+ + maximumFractionDigits
+ + Math.max(positiveSuffix.length(), negativeSuffix.length());
fastPathData.fastPathContainer = new char[containerSize];
@@ -1038,17 +1058,18 @@
// Sets up fixed index positions for integral and fractional digits.
// Sets up decimal point in cached result container.
- int longestPrefixLength =
- Math.max(positivePrefix.length(), negativePrefix.length());
- int decimalPointIndex =
- maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
-
- fastPathData.integralLastIndex = decimalPointIndex - 1;
+ int longestPrefixLength
+ = Math.max(positivePrefix.length(),
+ negativePrefix.length());
+ int decimalPointIndex
+ = maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
+
+ fastPathData.integralLastIndex = decimalPointIndex - 1;
fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
- fastPathData.fastPathContainer[decimalPointIndex] =
- isCurrencyFormat ?
- symbols.getMonetaryDecimalSeparator() :
- symbols.getDecimalSeparator();
+ fastPathData.fastPathContainer[decimalPointIndex]
+ = isCurrencyFormat
+ ? symbols.getMonetaryDecimalSeparator()
+ : symbols.getDecimalSeparator();
} else if (fastPathWasOn) {
// Previous state was fast-path and is no more.
@@ -1059,8 +1080,6 @@
fastPathData.charsPositivePrefix = null;
fastPathData.charsNegativePrefix = null;
}
-
- fastPathCheckNeeded = false;
}
/**
@@ -1554,9 +1573,11 @@
* @return the formatted result for {@code d} as a string.
*/
String fastFormat(double d) {
+ boolean isDataSet = false;
// (Re-)Evaluates fast-path status if needed.
- if (fastPathCheckNeeded)
- checkAndSetFastPathStatus();
+ if (fastPathCheckNeeded) {
+ isDataSet = checkAndSetFastPathStatus();
+ }
if (!isFastPath )
// DecimalFormat instance is not in a fast-path state.
@@ -1580,9 +1601,21 @@
if (d > MAX_INT_AS_DOUBLE)
// Filters out values that are outside expected fast-path range
return null;
- else
+ else {
+ if (!isDataSet) {
+ /*
+ * If the fast path data is not set through
+ * checkAndSetFastPathStatus() and fulfil the
+ * fast path conditions then reset the data
+ * directly through resetFastPathData()
+ */
+ resetFastPathData(isFastPath);
+ }
fastDoubleFormat(d, negative);
+ }
+
+
// Returns a new string from updated fastPathContainer.
return new String(fastPathData.fastPathContainer,
fastPathData.firstUsedIndex,
--- a/jdk/src/java.base/share/classes/java/util/Locale.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java Wed Oct 05 06:28:23 2016 -0700
@@ -1027,7 +1027,7 @@
* not contain ALL valid codes that can be used to create Locales.
* </ul>
*
- * @return Am array of ISO 639 two-letter language codes.
+ * @return An array of ISO 639 two-letter language codes.
*/
public static String[] getISOLanguages() {
if (isoLanguages == null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,206 @@
+/*
+ * 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.jmod;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Helper class to read JMOD file
+ */
+public class JmodFile implements AutoCloseable {
+ // jmod magic number and version number
+ public static final int JMOD_MAJOR_VERSION = 0x01;
+ public static final int JMOD_MINOR_VERSION = 0x00;
+ public static final byte[] JMOD_MAGIC_NUMBER = {
+ 0x4A, 0x4D, /* JM */
+ JMOD_MAJOR_VERSION, JMOD_MINOR_VERSION, /* version 1.0 */
+ };
+
+ public static void checkMagic(Path file) throws IOException {
+ try (InputStream in = Files.newInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(in)) {
+ // validate the header
+ byte[] magic = new byte[4];
+ bis.read(magic);
+ if (magic[0] != JMOD_MAGIC_NUMBER[0] ||
+ magic[1] != JMOD_MAGIC_NUMBER[1]) {
+ throw new IOException("Invalid jmod file: " + file.toString());
+ }
+ if (magic[2] > JMOD_MAJOR_VERSION ||
+ (magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {
+ throw new IOException("Unsupported jmod version: " +
+ magic[2] + "." + magic[3] + " in " + file.toString());
+ }
+ }
+ }
+
+ /**
+ * JMOD sections
+ */
+ public static enum Section {
+ NATIVE_LIBS("native"),
+ NATIVE_CMDS("bin"),
+ CLASSES("classes"),
+ CONFIG("conf");
+
+ private final String jmodDir;
+ private Section(String jmodDir) {
+ this.jmodDir = jmodDir;
+ }
+
+ /**
+ * Returns the directory name in the JMOD file corresponding to
+ * this section
+ */
+ public String jmodDir() { return jmodDir; }
+
+ }
+
+ /**
+ * JMOD file entry.
+ *
+ * Each entry corresponds to a ZipEntry whose name is:
+ * Section::jmodDir + '/' + name
+ */
+ public static class Entry {
+ private final ZipEntry zipEntry;
+ private final Section section;
+ private final String name;
+
+ private Entry(ZipEntry e) {
+ String name = e.getName();
+ int i = name.indexOf('/');
+ if (i <= 1) {
+ throw new RuntimeException("invalid jmod entry: " + name);
+ }
+
+ this.zipEntry = e;
+ this.section = section(name);
+ this.name = name.substring(i+1);
+ }
+
+ /**
+ * Returns the section of this entry.
+ */
+ public Section section() {
+ return section;
+ }
+
+ /**
+ * Returns the name of this entry.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the size of this entry.
+ */
+ public long size() {
+ return zipEntry.getSize();
+ }
+
+ public ZipEntry zipEntry() {
+ return zipEntry;
+ }
+
+ @Override
+ public String toString() {
+ return section.jmodDir() + "/" + name;
+ }
+
+ static Section section(String name) {
+ int i = name.indexOf('/');
+ String s = name.substring(0, i);
+ switch (s) {
+ case "native":
+ return Section.NATIVE_LIBS;
+ case "bin":
+ return Section.NATIVE_CMDS;
+ case "classes":
+ return Section.CLASSES;
+ case "conf":
+ return Section.CONFIG;
+ default:
+ throw new IllegalArgumentException("invalid section: " + s);
+ }
+ }
+ }
+
+ private final Path file;
+ private final ZipFile zipfile;
+
+ /**
+ * Constructs a {@code JmodFile} from a given path.
+ */
+ public JmodFile(Path file) throws IOException {
+ checkMagic(file);
+ this.file = file;
+ this.zipfile = new ZipFile(file.toFile());
+ }
+
+ /**
+ * Opens an {@code InputStream} for reading the named entry of the given
+ * section in this jmod file.
+ *
+ * @throws IOException if the named entry is not found, or I/O error
+ * occurs when reading it
+ */
+ public InputStream getInputStream(Section section, String name)
+ throws IOException
+ {
+
+ String entry = section.jmodDir() + "/" + name;
+ ZipEntry e = zipfile.getEntry(entry);
+ if (e == null) {
+ throw new IOException(name + " not found: " + file);
+ }
+ return zipfile.getInputStream(e);
+ }
+
+ /**
+ * Returns a stream of non-directory entries in this jmod file.
+ */
+ public Stream<Entry> stream() {
+ return zipfile.stream()
+ .filter(e -> !e.isDirectory())
+ .map(Entry::new);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (zipfile != null) {
+ zipfile.close();
+ }
+ }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Wed Oct 05 06:28:23 2016 -0700
@@ -163,6 +163,16 @@
* be discarded.
*/
public void write(OutputStream out) throws IOException {
+ // emit to the output stream
+ out.write(toByteArray());
+ }
+
+ /**
+ * Returns the bytes of the modified module-info.class.
+ * Once this method has been called then the Extender object should
+ * be discarded.
+ */
+ public byte[] toByteArray() throws IOException {
ClassWriter cw
= new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
@@ -197,8 +207,7 @@
// add any attributes that didn't replace previous attributes
cv.finish();
- // emit to the output stream
- out.write(cw.toByteArray());
+ return cw.toByteArray();
}
/**
--- a/jdk/src/java.base/share/classes/module-info.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/module-info.java Wed Oct 05 06:28:23 2016 -0700
@@ -124,6 +124,9 @@
jdk.jlink;
exports jdk.internal.jimage.decompressor to
jdk.jlink;
+ exports jdk.internal.jmod to
+ jdk.compiler,
+ jdk.jlink;
exports jdk.internal.logger to
java.logging;
exports jdk.internal.org.objectweb.asm to
--- a/jdk/src/java.base/share/conf/security/java.security Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/conf/security/java.security Wed Oct 05 06:28:23 2016 -0700
@@ -894,3 +894,44 @@
disallowReferenceUriSchemes file http https,\
noDuplicateIds,\
noRetrievalMethodLoops
+
+#
+# Serialization process-wide filter
+#
+# A filter, if configured, is used by java.io.ObjectInputStream during
+# deserialization to check the contents of the stream.
+# A filter is configured as a sequence of patterns, each pattern is either
+# matched against the name of a class in the stream or defines a limit.
+# Patterns are separated by ";" (semicolon).
+# Whitespace is significant and is considered part of the pattern.
+#
+# If a pattern includes a "=", it sets a limit.
+# If a limit appears more than once the last value is used.
+# Limits are checked before classes regardless of the order in the sequence of patterns.
+# If any of the limits are exceeded, the filter status is REJECTED.
+#
+# maxdepth=value - the maximum depth of a graph
+# maxrefs=value - the maximum number of internal references
+# maxbytes=value - the maximum number of bytes in the input stream
+# maxarray=value - the maximum array length allowed
+#
+# Other patterns, from left to right, match the class or package name as
+# returned from Class.getName.
+# If the class is an array type, the class or package to be matched is the element type.
+# Arrays of any number of dimensions are treated the same as the element type.
+# For example, a pattern of "!example.Foo", rejects creation of any instance or
+# array of example.Foo.
+#
+# If the pattern starts with "!", the status is REJECTED if the remaining pattern
+# is matched; otherwise the status is ALLOWED if the pattern matches.
+# If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
+# if the module name matches the module name of the class then
+# the remaining pattern is matched with the class name.
+# If there is no "/", the module name is not compared.
+# If the pattern ends with ".**" it matches any class in the package and all subpackages.
+# If the pattern ends with ".*" it matches any class in the package.
+# If the pattern ends with "*", it matches any class with the pattern as a prefix.
+# If the pattern is equal to the class name, it matches.
+# Otherwise, the status is UNDECIDED.
+#
+#jdk.serialFilter=pattern;pattern
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -116,7 +116,7 @@
synchronized (this) {
if (iterator != null)
throw new IllegalStateException("Iterator already obtained");
- iterator = new UnixDirectoryIterator(ds);
+ iterator = new UnixDirectoryIterator();
return iterator;
}
}
@@ -130,17 +130,14 @@
* Iterator implementation
*/
private class UnixDirectoryIterator implements Iterator<Path> {
- private final DirectoryStream<Path> stream;
-
// true when at EOF
private boolean atEof;
// next entry to return
private Path nextEntry;
- UnixDirectoryIterator(DirectoryStream<Path> stream) {
+ UnixDirectoryIterator() {
atEof = false;
- this.stream = stream;
}
// Return true if file name is "." or ".."
--- a/jdk/src/java.desktop/share/classes/java/beans/MetaData.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/java/beans/MetaData.java Wed Oct 05 06:28:23 2016 -0700
@@ -510,102 +510,6 @@
return new Expression(oldInstance, Collections.class, "synchronizedSortedMap", new Object[]{map});
}
}
-
- static final class CheckedCollection_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
- List<?> list = new ArrayList<>((Collection<?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedCollection", new Object[]{list, type});
- }
- }
-
- static final class CheckedList_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
- List<?> list = new LinkedList<>((Collection<?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
- }
- }
-
- static final class CheckedRandomAccessList_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
- List<?> list = new ArrayList<>((Collection<?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
- }
- }
-
- static final class CheckedSet_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
- Set<?> set = new HashSet<>((Set<?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedSet", new Object[]{set, type});
- }
- }
-
- static final class CheckedSortedSet_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
- SortedSet<?> set = new TreeSet<>((SortedSet<?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedSortedSet", new Object[]{set, type});
- }
- }
-
- static final class CheckedMap_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");
- Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");
- Map<?,?> map = new HashMap<>((Map<?,?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedMap", new Object[]{map, keyType, valueType});
- }
- }
-
- static final class CheckedSortedMap_PersistenceDelegate extends java_util_Collections {
- protected Expression instantiate(Object oldInstance, Encoder out) {
- Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");
- Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");
- SortedMap<?,?> map = new TreeMap<>((SortedMap<?,?>) oldInstance);
- return new Expression(oldInstance, Collections.class, "checkedSortedMap", new Object[]{map, keyType, valueType});
- }
- }
-}
-
-/**
- * The persistence delegate for {@code java.util.EnumMap} classes.
- *
- * @author Sergey A. Malenkov
- */
-static final class java_util_EnumMap_PersistenceDelegate extends PersistenceDelegate {
- protected boolean mutatesTo(Object oldInstance, Object newInstance) {
- return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
- }
-
- protected Expression instantiate(Object oldInstance, Encoder out) {
- return new Expression(oldInstance, EnumMap.class, "new", new Object[] {getType(oldInstance)});
- }
-
- private static Object getType(Object instance) {
- return MetaData.getPrivateFieldValue(instance, "java.util.EnumMap.keyType");
- }
-}
-
-/**
- * The persistence delegate for {@code java.util.EnumSet} classes.
- *
- * @author Sergey A. Malenkov
- */
-static final class java_util_EnumSet_PersistenceDelegate extends PersistenceDelegate {
- protected boolean mutatesTo(Object oldInstance, Object newInstance) {
- return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
- }
-
- protected Expression instantiate(Object oldInstance, Encoder out) {
- return new Expression(oldInstance, EnumSet.class, "noneOf", new Object[] {getType(oldInstance)});
- }
-
- private static Object getType(Object instance) {
- return MetaData.getPrivateFieldValue(instance, "java.util.EnumSet.elementType");
- }
}
// Collection
@@ -1313,9 +1217,6 @@
internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate());
internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate());
-
- internalPersistenceDelegates.put("java.util.JumboEnumSet", new java_util_EnumSet_PersistenceDelegate());
- internalPersistenceDelegates.put("java.util.RegularEnumSet", new java_util_EnumSet_PersistenceDelegate());
}
@SuppressWarnings("rawtypes")
--- a/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Wed Oct 05 06:28:23 2016 -0700
@@ -24,9 +24,11 @@
*/
package java.rmi.server;
+import java.io.ObjectInputFilter;
import java.rmi.*;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.server.UnicastServerRef2;
+import sun.rmi.transport.LiveRef;
/**
* Used for exporting a remote object with JRMP and obtaining a stub
@@ -38,11 +40,11 @@
* generated stubs is deprecated. This includes the API in this class that
* requires the use of static stubs, as well as the runtime support for
* loading static stubs. Generating stubs dynamically is preferred, using one
- * of the five non-deprecated ways of exporting objects as listed below. Do
+ * of the non-deprecated ways of exporting objects as listed below. Do
* not run {@code rmic} to generate static stub classes. It is unnecessary, and
* it is also deprecated.</em>
*
- * <p>There are six ways to export remote objects:
+ * <p>There are eight ways to export remote objects:
*
* <ol>
*
@@ -67,12 +69,19 @@
* {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory)
* exportObject(Remote, port, csf, ssf)} method.
*
+ * <li>Calling the
+ * {@link #exportObject(Remote, int, ObjectInputFilter) exportObject(Remote, port, filter)} method.
+ *
+ * <li>Calling the
+ * {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory, ObjectInputFilter)
+ * exportObject(Remote, port, csf, ssf, filter)} method.
+ *
* </ol>
*
* <p>The fourth technique, {@link #exportObject(Remote)},
* always uses statically generated stubs and is deprecated.
*
- * <p>The other five techniques all use the following approach: if the
+ * <p>The other techniques all use the following approach: if the
* {@code java.rmi.server.ignoreStubClasses} property is {@code true}
* (case insensitive) or if a static stub cannot be found, stubs are generated
* dynamically using {@link java.lang.reflect.Proxy Proxy} objects. Otherwise,
@@ -130,6 +139,22 @@
*
* </ul>
*
+ * <p>
+ * Exported remote objects receive method invocations from the stubs
+ * as described in the RMI specification. Each invocation's operation and
+ * parameters are unmarshaled using a custom {@link java.io.ObjectInputStream}.
+ * If an {@link ObjectInputFilter} is provided and is not {@code null} when the object
+ * is exported, it is used to filter the parameters as they are unmarshaled from the stream.
+ * The filter is used for all invocations and all parameters regardless of
+ * the method being invoked or the parameter values.
+ * If no filter is provided or is {@code null} for the exported object then the
+ * {@code ObjectInputStream} default filter, if any, is used. The default filter is
+ * configured with {@link ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter)
+ * ObjectInputFilter.Config.setSerialFilter}.
+ * If the filter rejects any of the parameters, the {@code InvalidClassException}
+ * thrown by {@code ObjectInputStream} is reported as the cause of an
+ * {@link UnmarshalException}.
+ *
* @implNote
* Depending upon which constructor or static method is used for exporting an
* object, {@link RMISocketFactory} may be used for creating sockets.
@@ -347,6 +372,58 @@
}
/**
+ * Exports the remote object to make it available to receive incoming
+ * calls, using the particular supplied port
+ * and {@linkplain ObjectInputFilter filter}.
+ *
+ * <p>The object is exported with a server socket
+ * created using the {@link RMISocketFactory} class.
+ *
+ * @param obj the remote object to be exported
+ * @param port the port to export the object on
+ * @param filter an ObjectInputFilter applied when deserializing invocation arguments;
+ * may be {@code null}
+ * @return remote object stub
+ * @exception RemoteException if export fails
+ * @since 9
+ */
+ public static Remote exportObject(Remote obj, int port,
+ ObjectInputFilter filter)
+ throws RemoteException
+ {
+ return exportObject(obj, new UnicastServerRef(new LiveRef(port), filter));
+ }
+
+ /**
+ * Exports the remote object to make it available to receive incoming
+ * calls, using a transport specified by the given socket factory
+ * and {@linkplain ObjectInputFilter filter}.
+ *
+ * <p>Either socket factory may be {@code null}, in which case
+ * the corresponding client or server socket creation method of
+ * {@link RMISocketFactory} is used instead.
+ *
+ * @param obj the remote object to be exported
+ * @param port the port to export the object on
+ * @param csf the client-side socket factory for making calls to the
+ * remote object
+ * @param ssf the server-side socket factory for receiving remote calls
+ * @param filter an ObjectInputFilter applied when deserializing invocation arguments;
+ * may be {@code null}
+ * @return remote object stub
+ * @exception RemoteException if export fails
+ * @since 9
+ */
+ public static Remote exportObject(Remote obj, int port,
+ RMIClientSocketFactory csf,
+ RMIServerSocketFactory ssf,
+ ObjectInputFilter filter)
+ throws RemoteException
+ {
+ return exportObject(obj, new UnicastServerRef2(port, csf, ssf, filter));
+ }
+
+ /**
* Removes the remote object, obj, from the RMI runtime. If
* successful, the object can no longer accept incoming RMI calls.
* If the force parameter is true, the object is forcibly unexported
--- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Wed Oct 05 06:28:23 2016 -0700
@@ -27,6 +27,8 @@
import java.io.IOException;
import java.io.ObjectInput;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectStreamClass;
import java.lang.reflect.InvocationTargetException;
@@ -62,6 +64,10 @@
* UnicastServerRef implements the remote reference layer server-side
* behavior for remote objects exported with the "UnicastRef" reference
* type.
+ * If an {@link ObjectInputFilter ObjectInputFilter} is supplied it is
+ * invoked during deserialization to filter the arguments,
+ * otherwise the default filter of {@link ObjectInputStream ObjectInputStream}
+ * applies.
*
* @author Ann Wollrath
* @author Roger Riggs
@@ -103,6 +109,9 @@
*/
private transient Skeleton skel;
+ // The ObjectInputFilter for checking the invocation arguments
+ private final transient ObjectInputFilter filter;
+
/** maps method hash to Method object for each remote method */
private transient Map<Long,Method> hashToMethod_Map = null;
@@ -121,16 +130,29 @@
/**
* Create a new (empty) Unicast server remote reference.
+ * The filter is null to defer to the default ObjectInputStream filter, if any.
*/
public UnicastServerRef() {
+ this.filter = null;
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef.
+ * The filter is null to defer to the default ObjectInputStream filter, if any.
*/
public UnicastServerRef(LiveRef ref) {
super(ref);
+ this.filter = null;
+ }
+
+ /**
+ * Construct a Unicast server remote reference for a specified
+ * liveRef and filter.
+ */
+ public UnicastServerRef(LiveRef ref, ObjectInputFilter filter) {
+ super(ref);
+ this.filter = filter;
}
/**
@@ -139,6 +161,7 @@
*/
public UnicastServerRef(int port) {
super(new LiveRef(port));
+ this.filter = null;
}
/**
@@ -363,9 +386,23 @@
}
}
+ /**
+ * Sets a filter for invocation arguments, if a filter has been set.
+ * Called by dispatch before the arguments are read.
+ */
protected void unmarshalCustomCallData(ObjectInput in)
- throws IOException, ClassNotFoundException
- {}
+ throws IOException, ClassNotFoundException {
+ if (filter != null &&
+ in instanceof ObjectInputStream) {
+ // Set the filter on the stream
+ ObjectInputStream ois = (ObjectInputStream) in;
+
+ AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+ ois.setObjectInputFilter(filter);
+ return null;
+ });
+ }
+ }
/**
* Handle server-side dispatch using the RMI 1.1 stub/skeleton
--- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java Wed Oct 05 06:28:23 2016 -0700
@@ -25,12 +25,13 @@
package sun.rmi.server;
-import java.io.IOException;
+import java.io.ObjectInputFilter;
import java.io.ObjectOutput;
-import java.rmi.*;
-import java.rmi.server.*;
-import sun.rmi.transport.*;
-import sun.rmi.transport.tcp.*;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteRef;
+
+import sun.rmi.transport.LiveRef;
/**
* Server-side ref for a remote impl that uses a custom socket factory.
@@ -59,6 +60,16 @@
}
/**
+ * Construct a Unicast server remote reference for a specified
+ * liveRef and filter.
+ */
+ public UnicastServerRef2(LiveRef ref,
+ ObjectInputFilter filter)
+ {
+ super(ref, filter);
+ }
+
+ /**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
@@ -70,6 +81,18 @@
}
/**
+ * Construct a Unicast server remote reference to be exported
+ * on the specified port.
+ */
+ public UnicastServerRef2(int port,
+ RMIClientSocketFactory csf,
+ RMIServerSocketFactory ssf,
+ ObjectInputFilter filter)
+ {
+ super(new LiveRef(port, csf, ssf), filter);
+ }
+
+ /**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out)
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Wed Oct 05 06:28:23 2016 -0700
@@ -103,6 +103,18 @@
basename = en.baseName;
entryname = en.entryName;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Entry)) return false;
+ return this.file.equals(((Entry)o).file);
+ }
+
+ @Override
+ public int hashCode() {
+ return file.hashCode();
+ }
}
class EntryName {
@@ -124,10 +136,10 @@
if (name.startsWith("./")) {
name = name.substring(2);
}
- this.baseName = name;
- this.entryName = (version > BASE_VERSION)
- ? VERSIONS_DIR + version + "/" + this.baseName
- : this.baseName;
+ baseName = name;
+ entryName = (version > BASE_VERSION)
+ ? VERSIONS_DIR + version + "/" + baseName
+ : baseName;
}
}
@@ -137,7 +149,7 @@
Map<String, Entry> entryMap = new HashMap<>();
// All entries need to be added/updated.
- Map<String, Entry> entries = new LinkedHashMap<>();
+ Set<Entry> entries = new LinkedHashSet<>();
// All packages.
Set<String> packages = new HashSet<>();
@@ -855,8 +867,7 @@
moduleInfoPaths.put(entryName, f.toPath());
if (isUpdate)
entryMap.put(entryName, entry);
- } else if (!entries.containsKey(entryName)) {
- entries.put(entryName, entry);
+ } else if (entries.add(entry)) {
jarEntries.add(entryName);
if (entry.basename.endsWith(".class") && !entryName.startsWith(VERSIONS_DIR))
packages.add(toPackageName(entry.basename));
@@ -864,8 +875,7 @@
entryMap.put(entryName, entry);
}
} else if (f.isDirectory()) {
- if (!entries.containsKey(entryName)) {
- entries.put(entryName, entry);
+ if (entries.add(entry)) {
if (isUpdate) {
entryMap.put(entryName, entry);
}
@@ -923,8 +933,7 @@
in.transferTo(zos);
zos.closeEntry();
}
- for (String entryname : entries.keySet()) {
- Entry entry = entries.get(entryname);
+ for (Entry entry : entries) {
addFile(zos, entry);
}
zos.close();
@@ -1049,7 +1058,7 @@
Entry ent = entryMap.get(name);
addFile(zos, ent);
entryMap.remove(name);
- entries.remove(name);
+ entries.remove(ent);
}
jarEntries.add(name);
@@ -1059,8 +1068,8 @@
}
// add the remaining new files
- for (String entryname : entries.keySet()) {
- addFile(zos, entries.get(entryname));
+ for (Entry entry : entries) {
+ addFile(zos, entry);
}
if (!foundManifest) {
if (newManifest != null) {
@@ -1248,6 +1257,9 @@
* Adds a new file entry to the ZIP output stream.
*/
void addFile(ZipOutputStream zos, Entry entry) throws IOException {
+ // skip the generation of directory entries for META-INF/versions/*/
+ if (entry.basename.isEmpty()) return;
+
File file = entry.file;
String name = entry.entryname;
boolean isDir = entry.isDir;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java Wed Oct 05 06:28:23 2016 -0700
@@ -55,6 +55,13 @@
private final Archive archive;
private final String path;
+ /**
+ * Constructs an entry of the given archive
+ * @param archive archive
+ * @param path
+ * @param name an entry name that does not contain the module name
+ * @param type
+ */
public Entry(Archive archive, String path, String name, EntryType type) {
this.archive = Objects.requireNonNull(archive);
this.path = Objects.requireNonNull(path);
@@ -62,25 +69,29 @@
this.type = Objects.requireNonNull(type);
}
- public Archive archive() {
+ public final Archive archive() {
return archive;
}
- public String path() {
- return path;
- }
-
- public EntryType type() {
+ public final EntryType type() {
return type;
}
- /*
+ /**
* Returns the name of this entry.
*/
- public String name() {
+ public final String name() {
return name;
}
+ /**
+ * Returns the name representing a ResourcePoolEntry in the form of:
+ * /$MODULE/$ENTRY_NAME
+ */
+ public final String getResourcePoolEntryName() {
+ return "/" + archive.moduleName() + "/" + name;
+ }
+
@Override
public String toString() {
return "type " + type.name() + " path " + path;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Wed Oct 05 06:28:23 2016 -0700
@@ -50,7 +50,7 @@
FileEntry(Path path, String name) {
super(DirArchive.this, getPathName(path), name,
- Archive.Entry.EntryType.CLASS_OR_RESOURCE);
+ Archive.Entry.EntryType.CLASS_OR_RESOURCE);
this.path = path;
try {
size = Files.size(path);
@@ -124,13 +124,7 @@
return null;
}
String name = getPathName(p).substring(chop);
- if (name.startsWith("_")) {
- return null;
- }
log.accept(moduleName + "/" + name);
- if (name.equals(MODULE_INFO)) {
- name = moduleName + "/" + MODULE_INFO;
- }
return new FileEntry(p, name);
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java Wed Oct 05 06:28:23 2016 -0700
@@ -40,6 +40,7 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+
import jdk.tools.jlink.internal.Archive.Entry;
import jdk.tools.jlink.internal.Archive.Entry.EntryType;
import jdk.tools.jlink.internal.ResourcePoolManager.CompressedModuleData;
@@ -122,10 +123,6 @@
});
}
- public static boolean isClassPackage(String path) {
- return path.endsWith(".class") && !path.endsWith("module-info.class");
- }
-
public static void recreateJimage(Path jimageFile,
Set<Archive> archives,
ImagePluginStack pluginSupport)
@@ -265,26 +262,13 @@
return writer.getString(id);
}
});
+
for (Archive archive : archives) {
String mn = archive.moduleName();
- for (Entry entry : entriesForModule.get(mn)) {
- String path;
- if (entry.type() == EntryType.CLASS_OR_RESOURCE) {
- // Removal of "classes/" radical.
- path = entry.name();
- if (path.endsWith("module-info.class")) {
- path = "/" + path;
- } else {
- path = "/" + mn + "/" + path;
- }
- } else {
- // Entry.path() contains the kind of file native, conf, bin, ...
- // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
- path = "/" + mn + "/" + entry.path();
- }
-
- resources.add(new ArchiveEntryResourcePoolEntry(mn, path, entry));
- }
+ entriesForModule.get(mn).stream()
+ .map(e -> new ArchiveEntryResourcePoolEntry(mn,
+ e.getResourcePoolEntryName(), e))
+ .forEach(resources::add);
}
return resources;
}
@@ -320,6 +304,20 @@
return result.toArray(array);
}
+ /**
+ * Returns the path of the resource.
+ */
+ public static String resourceName(String path) {
+ Objects.requireNonNull(path);
+ String s = path.substring(1);
+ int index = s.indexOf("/");
+ return s.substring(index + 1);
+ }
+
+ public static String toPackage(String name) {
+ return toPackage(name, false);
+ }
+
private static String toPackage(String name, boolean log) {
int index = name.lastIndexOf('/');
if (index > 0) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Wed Oct 05 06:28:23 2016 -0700
@@ -43,7 +43,7 @@
/**
* An entry located in a jar file.
*/
- private class JarEntry extends Entry {
+ public class JarEntry extends Entry {
private final long size;
private final ZipEntry entry;
@@ -70,12 +70,10 @@
}
}
- private static final String MODULE_INFO = "module-info.class";
-
private final Path file;
private final String moduleName;
// currently processed ZipFile
- private ZipFile zipFile;
+ protected ZipFile zipFile;
protected JarArchive(String mn, Path file) {
Objects.requireNonNull(mn);
@@ -110,21 +108,7 @@
abstract String getFileName(String entryName);
- private Entry toEntry(ZipEntry ze) {
- String name = ze.getName();
- String fn = getFileName(name);
-
- if (ze.isDirectory() || fn.startsWith("_")) {
- return null;
- }
-
- EntryType rt = toEntryType(name);
-
- if (fn.equals(MODULE_INFO)) {
- fn = moduleName + "/" + MODULE_INFO;
- }
- return new JarEntry(ze.getName(), fn, rt, zipFile, ze);
- }
+ abstract Entry toEntry(ZipEntry ze);
@Override
public void close() throws IOException {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java Wed Oct 05 06:28:23 2016 -0700
@@ -25,34 +25,106 @@
package jdk.tools.jlink.internal;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Objects;
+import java.util.stream.Stream;
+
+import jdk.internal.jmod.JmodFile;
import jdk.tools.jlink.internal.Archive.Entry.EntryType;
/**
* An Archive backed by a jmod file.
*/
-public class JmodArchive extends JarArchive {
-
+public class JmodArchive implements Archive {
private static final String JMOD_EXT = ".jmod";
- private static final String MODULE_NAME = "module";
- private static final String MODULE_INFO = "module-info.class";
- private static final String CLASSES = "classes";
- private static final String NATIVE_LIBS = "native";
- private static final String NATIVE_CMDS = "bin";
- private static final String CONFIG = "conf";
+
+ /**
+ * An entry located in a jmod file.
+ */
+ public class JmodEntry extends Entry {
+ private final JmodFile.Entry entry;
+
+ JmodEntry(String path, String name, EntryType type,
+ JmodFile.Entry entry) {
+ super(JmodArchive.this, path, name, type);
+ this.entry = Objects.requireNonNull(entry);
+ }
+
+ /**
+ * Returns the number of uncompressed bytes for this entry.
+ */
+ @Override
+ public long size() {
+ return entry.size();
+ }
+
+ @Override
+ public InputStream stream() throws IOException {
+ return jmodFile.getInputStream(entry.section(), entry.name());
+ }
+ }
+
+ private final Path file;
+ private final String moduleName;
+ private JmodFile jmodFile;
public JmodArchive(String mn, Path jmod) {
- super(mn, jmod);
- String filename = Objects.requireNonNull(jmod.getFileName()).toString();
+ Objects.requireNonNull(mn);
+ Objects.requireNonNull(jmod.getFileName());
+ String filename = jmod.toString();
if (!filename.endsWith(JMOD_EXT)) {
throw new UnsupportedOperationException("Unsupported format: " + filename);
}
+ this.moduleName = mn;
+ this.file = jmod;
+ }
+
+ @Override
+ public String moduleName() {
+ return moduleName;
+ }
+
+ @Override
+ public Path getPath() {
+ return file;
+ }
+
+ @Override
+ public Stream<Entry> entries() {
+ ensureOpen();
+ return jmodFile.stream()
+ .map(this::toEntry);
}
@Override
- EntryType toEntryType(String entryName) {
- String section = getSection(entryName.replace('\\', '/'));
+ public void open() throws IOException {
+ if (jmodFile != null) {
+ jmodFile.close();
+ }
+ this.jmodFile = new JmodFile(file);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (jmodFile != null) {
+ jmodFile.close();
+ }
+ }
+
+ private void ensureOpen() {
+ if (jmodFile == null) {
+ try {
+ open();
+ } catch(IOException ioe){
+ throw new UncheckedIOException(ioe);
+ }
+ }
+ }
+
+ private EntryType toEntryType(JmodFile.Section section) {
switch (section) {
case CLASSES:
return EntryType.CLASS_OR_RESOURCE;
@@ -62,26 +134,23 @@
return EntryType.NATIVE_CMD;
case CONFIG:
return EntryType.CONFIG;
- case MODULE_NAME:
- return EntryType.MODULE_NAME;
default:
throw new InternalError("unexpected entry: " + section);
}
}
- private static String getSection(String entryName) {
- int i = entryName.indexOf('/');
- // Unnamed section.
- String section = "";
- if (i > 0) {
- section = entryName.substring(0, entryName.indexOf('/'));
+ private Entry toEntry(JmodFile.Entry entry) {
+ EntryType type = toEntryType(entry.section());
+ String name = entry.name();
+ String path = entry.section().jmodDir() + "/" + name;
+
+ // Entry.path() contains the kind of file native, conf, bin, ...
+ // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
+ String resourceName = name;
+ if (type != EntryType.CLASS_OR_RESOURCE) {
+ resourceName = path;
}
- return section;
- }
- @Override
- String getFileName(String entryName) {
- entryName = entryName.replace('\\', '/');
- return entryName.substring(entryName.indexOf('/') + 1);
+ return new JmodEntry(path, resourceName, type, entry);
}
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Wed Oct 05 06:28:23 2016 -0700
@@ -27,6 +27,8 @@
import java.nio.file.Path;
import java.util.Objects;
+import java.util.zip.ZipEntry;
+
import jdk.tools.jlink.internal.Archive.Entry.EntryType;
/**
@@ -35,6 +37,7 @@
public class ModularJarArchive extends JarArchive {
private static final String JAR_EXT = ".jar";
+ private static final String MODULE_INFO = "module-info.class";
public ModularJarArchive(String mn, Path jmod) {
super(mn, jmod);
@@ -50,6 +53,17 @@
}
@Override
+ Entry toEntry(ZipEntry ze) {
+ if (ze.isDirectory()) {
+ return null;
+ }
+
+ String name = ze.getName();
+ EntryType type = toEntryType(name);
+ return new JarEntry(ze.getName(), getFileName(name), type, zipFile, ze);
+ }
+
+ @Override
String getFileName(String entryName) {
return entryName;
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Wed Oct 05 06:28:23 2016 -0700
@@ -27,15 +27,12 @@
import java.lang.module.ModuleDescriptor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.Function;
import java.util.stream.Stream;
import jdk.internal.jimage.decompressor.CompressedResourceHeader;
import jdk.tools.jlink.plugin.ResourcePool;
@@ -44,7 +41,6 @@
import jdk.tools.jlink.plugin.ResourcePoolModule;
import jdk.tools.jlink.plugin.ResourcePoolModuleView;
import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
/**
* A manager for pool of resources.
@@ -100,17 +96,17 @@
@Override
public Set<String> packages() {
Set<String> pkgs = new HashSet<>();
- moduleContent.values().stream().filter(m -> m.type().
- equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)).forEach(res -> {
- // Module metadata only contains packages with .class files
- if (ImageFileCreator.isClassPackage(res.path())) {
- String[] split = ImageFileCreator.splitPath(res.path());
- String pkg = split[1];
- if (pkg != null && !pkg.isEmpty()) {
- pkgs.add(pkg);
+ moduleContent.values().stream()
+ .filter(m -> m.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
+ .forEach(res -> {
+ String name = ImageFileCreator.resourceName(res.path());
+ if (name.endsWith(".class") && !name.endsWith("module-info.class")) {
+ String pkg = ImageFileCreator.toPackage(name);
+ if (!pkg.isEmpty()) {
+ pkgs.add(pkg);
+ }
}
- }
- });
+ });
return pkgs;
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java Wed Oct 05 06:28:23 2016 -0700
@@ -307,9 +307,10 @@
private boolean filterOutUnsupportedTags(byte[] b) {
List<Locale> locales;
+ List<String> originalTags = Arrays.asList(new String(b).split(" "));
try {
- locales = Arrays.asList(new String(b).split(" ")).stream()
+ locales = originalTags.stream()
.filter(tag -> !tag.isEmpty())
.map(IncludeLocalesPlugin::tagToLocale)
.collect(Collectors.toList());
@@ -319,6 +320,9 @@
}
byte[] filteredBytes = filterLocales(locales).stream()
+ // Make sure the filtered language tags do exist in the
+ // original supported tags for compatibility codes, e.g., "iw"
+ .filter(originalTags::contains)
.collect(Collectors.joining(" "))
.getBytes();
@@ -331,6 +335,11 @@
return true;
}
+ /*
+ * Filter list of locales according to the secified priorityList. Note
+ * that returned list of language tags may include extra ones, such as
+ * compatibility ones (e.g., "iw" -> "iw", "he").
+ */
private List<String> filterLocales(List<Locale> locales) {
List<String> ret =
Locale.filter(priorityList, locales, Locale.FilteringMode.EXTENDED_FILTERING).stream()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,116 @@
+/*
+ * 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.tools.jmod;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static jdk.internal.jmod.JmodFile.*;
+
+/**
+ * Output stream to write to JMOD file
+ */
+class JmodOutputStream extends OutputStream implements AutoCloseable {
+ /**
+ * This method creates (or overrides, if exists) the JMOD file,
+ * returning the the output stream to write to the JMOD file.
+ */
+ static JmodOutputStream newOutputStream(Path file) throws IOException {
+ OutputStream out = Files.newOutputStream(file);
+ BufferedOutputStream bos = new BufferedOutputStream(out);
+ return new JmodOutputStream(bos);
+ }
+
+ private final ZipOutputStream zos;
+ private JmodOutputStream(OutputStream out) {
+ this.zos = new ZipOutputStream(out);
+ try {
+ out.write(JMOD_MAGIC_NUMBER);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * Writes the input stream to the named entry of the given section.
+ */
+ public void writeEntry(InputStream in, Section section, String name)
+ throws IOException
+ {
+ ZipEntry ze = newEntry(section, name);
+ zos.putNextEntry(ze);
+ in.transferTo(zos);
+ zos.closeEntry();
+ }
+
+ /**
+ * Writes the given bytes to the named entry of the given section.
+ */
+ public void writeEntry(byte[] bytes, Section section, String path)
+ throws IOException
+ {
+ ZipEntry ze = newEntry(section, path);
+ zos.putNextEntry(ze);
+ zos.write(bytes);
+ zos.closeEntry();
+ }
+
+ /**
+ * Writes the given entry to the given input stream.
+ */
+ public void writeEntry(InputStream in, Entry e) throws IOException {
+ zos.putNextEntry(e.zipEntry());
+ zos.write(in.readAllBytes());
+ zos.closeEntry();
+ }
+
+ private ZipEntry newEntry(Section section, String path) {
+ String prefix = section.jmodDir();
+ String name = Paths.get(prefix, path).toString()
+ .replace(File.separatorChar, '/');
+ return new ZipEntry(name);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ zos.write(b);
+ }
+
+ @Override
+ public void close() throws IOException {
+ zos.close();
+ }
+}
+
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Wed Oct 05 06:28:23 2016 -0700
@@ -25,8 +25,6 @@
package jdk.tools.jmod;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -60,7 +58,6 @@
import java.text.MessageFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -80,15 +77,16 @@
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
import jdk.internal.joptsimple.BuiltinHelpFormatter;
import jdk.internal.joptsimple.NonOptionArgumentSpec;
import jdk.internal.joptsimple.OptionDescriptor;
@@ -250,23 +248,14 @@
}
private boolean describe() throws IOException {
- ZipFile zip = null;
- try {
- try {
- zip = new ZipFile(options.jmodFile.toFile());
- } catch (IOException x) {
- throw new IOException("error opening jmod file", x);
+ try (JmodFile jf = new JmodFile(options.jmodFile)) {
+ try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+ ModuleDescriptor md = ModuleDescriptor.read(in);
+ printModuleDescriptor(md);
+ return true;
+ } catch (IOException e) {
+ throw new CommandException("err.module.descriptor.not.found");
}
-
- try (InputStream in = Files.newInputStream(options.jmodFile)) {
- boolean found = printModuleDescriptor(in);
- if (!found)
- throw new CommandException("err.module.descriptor.not.found");
- return found;
- }
- } finally {
- if (zip != null)
- zip.close();
}
}
@@ -278,65 +267,52 @@
private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
- private boolean printModuleDescriptor(InputStream in)
+ private void printModuleDescriptor(ModuleDescriptor md)
throws IOException
{
- final String mi = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
- try (BufferedInputStream bis = new BufferedInputStream(in);
- ZipInputStream zis = new ZipInputStream(bis)) {
-
- ZipEntry e;
- while ((e = zis.getNextEntry()) != null) {
- if (e.getName().equals(mi)) {
- ModuleDescriptor md = ModuleDescriptor.read(zis);
- StringBuilder sb = new StringBuilder();
- sb.append("\n").append(md.toNameAndVersion());
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n").append(md.toNameAndVersion());
- md.requires().stream()
- .sorted(Comparator.comparing(Requires::name))
- .forEach(r -> {
- sb.append("\n requires ");
- if (!r.modifiers().isEmpty())
- sb.append(toString(r.modifiers())).append(" ");
- sb.append(r.name());
- });
+ md.requires().stream()
+ .sorted(Comparator.comparing(Requires::name))
+ .forEach(r -> {
+ sb.append("\n requires ");
+ if (!r.modifiers().isEmpty())
+ sb.append(toString(r.modifiers())).append(" ");
+ sb.append(r.name());
+ });
- md.uses().stream().sorted()
- .forEach(s -> sb.append("\n uses ").append(s));
+ md.uses().stream().sorted()
+ .forEach(s -> sb.append("\n uses ").append(s));
- md.exports().stream()
- .sorted(Comparator.comparing(Exports::source))
- .forEach(p -> sb.append("\n exports ").append(p));
+ md.exports().stream()
+ .sorted(Comparator.comparing(Exports::source))
+ .forEach(p -> sb.append("\n exports ").append(p));
+
+ md.conceals().stream().sorted()
+ .forEach(p -> sb.append("\n conceals ").append(p));
- md.conceals().stream().sorted()
- .forEach(p -> sb.append("\n conceals ").append(p));
+ md.provides().values().stream()
+ .sorted(Comparator.comparing(Provides::service))
+ .forEach(p -> sb.append("\n provides ").append(p.service())
+ .append(" with ")
+ .append(toString(p.providers())));
- md.provides().values().stream()
- .sorted(Comparator.comparing(Provides::service))
- .forEach(p -> sb.append("\n provides ").append(p.service())
- .append(" with ")
- .append(toString(p.providers())));
+ md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
- md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
-
- md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v));
-
- md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v));
+ md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v));
- md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
+ md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v));
+
+ 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))));
+ 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))));
- out.println(sb.toString());
- return true;
- }
- }
- }
- return false;
+ out.println(sb.toString());
}
private boolean create() throws IOException {
@@ -347,9 +323,8 @@
Path target = options.jmodFile;
Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
try {
- try (OutputStream out = Files.newOutputStream(tempTarget);
- BufferedOutputStream bos = new BufferedOutputStream(out)) {
- jmod.write(bos);
+ try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) {
+ jmod.write(jos);
}
Files.move(tempTarget, target);
} catch (Exception e) {
@@ -383,19 +358,16 @@
/**
* Writes the jmod to the given output stream.
*/
- void write(OutputStream out) throws IOException {
- try (ZipOutputStream zos = new ZipOutputStream(out)) {
-
- // module-info.class
- writeModuleInfo(zos, findPackages(classpath));
+ void write(JmodOutputStream out) throws IOException {
+ // module-info.class
+ writeModuleInfo(out, findPackages(classpath));
- // classes
- processClasses(zos, classpath);
+ // classes
+ processClasses(out, classpath);
- processSection(zos, Section.NATIVE_CMDS, cmds);
- processSection(zos, Section.NATIVE_LIBS, libs);
- processSection(zos, Section.CONFIG, configs);
- }
+ processSection(out, Section.NATIVE_CMDS, cmds);
+ processSection(out, Section.NATIVE_LIBS, libs);
+ processSection(out, Section.CONFIG, configs);
}
/**
@@ -441,7 +413,7 @@
* then the corresponding class file attributes are added to the
* module-info here.
*/
- void writeModuleInfo(ZipOutputStream zos, Set<String> packages)
+ void writeModuleInfo(JmodOutputStream out, Set<String> packages)
throws IOException
{
Supplier<InputStream> miSupplier = newModuleInfoSupplier();
@@ -492,11 +464,7 @@
}
// write the (possibly extended or modified) module-info.class
- String e = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
- ZipEntry ze = new ZipEntry(e);
- zos.putNextEntry(ze);
- extender.write(zos);
- zos.closeEntry();
+ out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
}
}
@@ -627,7 +595,7 @@
return "";
}
- void processClasses(ZipOutputStream zos, List<Path> classpaths)
+ void processClasses(JmodOutputStream zos, List<Path> classpaths)
throws IOException
{
if (classpaths == null)
@@ -645,7 +613,7 @@
}
}
- void processSection(ZipOutputStream zos, Section section, List<Path> paths)
+ void processSection(JmodOutputStream zos, Section section, List<Path> paths)
throws IOException
{
if (paths == null)
@@ -655,11 +623,9 @@
processSection(zos, section, p);
}
- void processSection(ZipOutputStream zos, Section section, Path top)
+ void processSection(JmodOutputStream out, Section section, Path top)
throws IOException
{
- final String prefix = section.jmodDir();
-
Files.walkFileTree(top, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
@@ -667,13 +633,19 @@
{
Path relPath = top.relativize(file);
if (relPath.toString().equals(MODULE_INFO)
- && !Section.CLASSES.equals(section))
+ && !Section.CLASSES.equals(section))
warning("warn.ignore.entry", MODULE_INFO, section);
if (!relPath.toString().equals(MODULE_INFO)
- && !matches(relPath, excludes)) {
+ && !matches(relPath, excludes)) {
try (InputStream in = Files.newInputStream(file)) {
- writeZipEntry(zos, in, prefix, relPath.toString());
+ out.writeEntry(in, section, relPath.toString());
+ } catch (IOException x) {
+ if (x.getMessage().contains("duplicate entry")) {
+ warning("warn.ignore.duplicate.entry", relPath.toString(), section);
+ return FileVisitResult.CONTINUE;
+ }
+ throw x;
}
}
return FileVisitResult.CONTINUE;
@@ -691,36 +663,17 @@
return false;
}
- void writeZipEntry(ZipOutputStream zos, InputStream in, String prefix, String other)
- throws IOException
- {
- String name = Paths.get(prefix, other).toString()
- .replace(File.separatorChar, '/');
- ZipEntry ze = new ZipEntry(name);
- try {
- zos.putNextEntry(ze);
- in.transferTo(zos);
- zos.closeEntry();
- } catch (ZipException x) {
- if (x.getMessage().contains("duplicate entry")) {
- warning("warn.ignore.duplicate.entry", name, prefix);
- return;
- }
- throw x;
- }
- }
-
class JarEntryConsumer implements Consumer<JarEntry>, Predicate<JarEntry> {
- final ZipOutputStream zos;
+ final JmodOutputStream out;
final JarFile jarfile;
- JarEntryConsumer(ZipOutputStream zos, JarFile jarfile) {
- this.zos = zos;
+ JarEntryConsumer(JmodOutputStream out, JarFile jarfile) {
+ this.out = out;
this.jarfile = jarfile;
}
@Override
public void accept(JarEntry je) {
try (InputStream in = jarfile.getInputStream(je)) {
- writeZipEntry(zos, in, Section.CLASSES.jmodDir(), je.getName());
+ out.writeEntry(in, Section.CLASSES, je.getName());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -947,29 +900,11 @@
{
Path target = moduleNameToPath.get(name);
Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
- ZipFile zip = new ZipFile(target.toFile());
try {
- try (OutputStream out = Files.newOutputStream(tempTarget);
- ZipOutputStream zos = new ZipOutputStream(out)) {
- zip.stream().forEach(e -> {
- try {
- InputStream in = zip.getInputStream(e);
- if (e.getName().equals(MODULE_INFO) ||
- e.getName().equals(Section.CLASSES.jmodDir() + "/" + MODULE_INFO)) {
- ZipEntry ze = new ZipEntry(e.getName());
- ze.setTime(System.currentTimeMillis());
- zos.putNextEntry(ze);
- recordHashes(in, zos, moduleHashes);
- zos.closeEntry();
- } else {
- zos.putNextEntry(e);
- zos.write(in.readAllBytes());
- zos.closeEntry();
- }
- } catch (IOException x) {
- throw new UncheckedIOException(x);
- }
- });
+ if (target.getFileName().toString().endsWith(".jmod")) {
+ updateJmodFile(target, tempTarget, moduleHashes);
+ } else {
+ updateModularJar(target, tempTarget, moduleHashes);
}
} catch (IOException|RuntimeException e) {
if (Files.exists(tempTarget)) {
@@ -980,13 +915,67 @@
}
}
throw e;
- } finally {
- zip.close();
}
+
out.println(getMessage("module.hashes.recorded", name));
Files.move(tempTarget, target, StandardCopyOption.REPLACE_EXISTING);
}
+ private void updateModularJar(Path target, Path tempTarget,
+ ModuleHashes moduleHashes)
+ throws IOException
+ {
+ try (JarFile jf = new JarFile(target.toFile());
+ OutputStream out = Files.newOutputStream(tempTarget);
+ JarOutputStream jos = new JarOutputStream(out))
+ {
+ jf.stream().forEach(e -> {
+ try (InputStream in = jf.getInputStream(e)) {
+ if (e.getName().equals(MODULE_INFO)) {
+ // what about module-info.class in versioned entries?
+ ZipEntry ze = new ZipEntry(e.getName());
+ ze.setTime(System.currentTimeMillis());
+ jos.putNextEntry(ze);
+ recordHashes(in, jos, moduleHashes);
+ jos.closeEntry();
+ } else {
+ jos.putNextEntry(e);
+ jos.write(in.readAllBytes());
+ jos.closeEntry();
+ }
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+ }
+ }
+
+ private void updateJmodFile(Path target, Path tempTarget,
+ ModuleHashes moduleHashes)
+ throws IOException
+ {
+
+ try (JmodFile jf = new JmodFile(target);
+ JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget))
+ {
+ jf.stream().forEach(e -> {
+ try (InputStream in = jf.getInputStream(e.section(), e.name())) {
+ if (e.name().equals(MODULE_INFO)) {
+ // replace module-info.class
+ ModuleInfoExtender extender =
+ ModuleInfoExtender.newExtender(in);
+ extender.hashes(moduleHashes);
+ jos.writeEntry(extender.toByteArray(), e.section(), e.name());
+ } else {
+ jos.writeEntry(in, e);
+ }
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+ }
+ }
+
private Path moduleToPath(String name) {
ModuleReference mref = moduleFinder.find(name).orElseThrow(
() -> new InternalError("Selected module " + name + " not on module path"));
@@ -1001,22 +990,6 @@
}
}
- enum Section {
- NATIVE_LIBS("native"),
- NATIVE_CMDS("bin"),
- CLASSES("classes"),
- CONFIG("conf"),
- UNKNOWN("unknown");
-
- private final String jmodDir;
-
- Section(String jmodDir) {
- this.jmodDir = jmodDir;
- }
-
- String jmodDir() { return jmodDir; }
- }
-
static class ClassPathConverter implements ValueConverter<Path> {
static final ValueConverter<Path> INSTANCE = new ClassPathConverter();
--- a/jdk/test/ProblemList.txt Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/ProblemList.txt Wed Oct 05 06:28:23 2016 -0700
@@ -134,6 +134,8 @@
java/lang/instrument/BootClassPath/BootClassPathTest.sh 8072130 macosx-all
+java/lang/instrument/DaemonThread/TestDaemonThread.java 8167001 generic-all
+
java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all
java/lang/management/MemoryMXBean/PendingAllGC.sh 8158760 generic-all
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java Wed Oct 05 06:28:23 2016 -0700
@@ -36,7 +36,6 @@
* @author Yun Ke
* @author Bill Situ
* @author Yu-Ching (Valerie) PENG
- * @run main TestCipherKeyWrapperPBEKey
*/
public class TestCipherPBECons {
--- a/jdk/test/java/beans/XMLEncoder/EnumPrivate.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2007, 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.
- */
-
-enum EnumPrivate {
- A0,B0,C0,D0,E0,F0,G0,H0,I0,J0,K0,L0,M0,N0,O0,P0,Q0,R0,S0,T0,U0,V0,W0,X0,Y0,Z0,
- A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,
- A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2,N2,O2,P2,Q2,R2,S2,T2,U2,V2,W2,X2,Y2,Z2,
- A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3,O3,P3,Q3,R3,S3,T3,U3,V3,W3,X3,Y3,Z3,
- A4,B4,C4,D4,E4,F4,G4,H4,I4,J4,K4,L4,M4,N4,O4,P4,Q4,R4,S4,T4,U4,V4,W4,X4,Y4,Z4,
- A5,B5,C5,D5,E5,F5,G5,H5,I5,J5,K5,L5,M5,N5,O5,P5,Q5,R5,S5,T5,U5,V5,W5,X5,Y5,Z5,
- A6,B6,C6,D6,E6,F6,G6,H6,I6,J6,K6,L6,M6,N6,O6,P6,Q6,R6,S6,T6,U6,V6,W6,X6,Y6,Z6,
- A7,B7,C7,D7,E7,F7,G7,H7,I7,J7,K7,L7,M7,N7,O7,P7,Q7,R7,S7,T7,U7,V7,W7,X7,Y7,Z7,
- A8,B8,C8,D8,E8,F8,G8,H8,I8,J8,K8,L8,M8,N8,O8,P8,Q8,R8,S8,T8,U8,V8,W8,X8,Y8,Z8,
- A9,B9,C9,D9,E9,F9,G9,H9,I9,J9,K9,L9,M9,N9,O9,P9,Q9,R9,S9,T9,U9,V9,W9,X9,Y9,Z9,
-}
--- a/jdk/test/java/beans/XMLEncoder/EnumPublic.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2007, 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.
- */
-
-public enum EnumPublic {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedCollection.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedCollection encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedCollection extends AbstractTest<Collection<String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedCollection().test(true);
- }
-
- protected Collection<String> getObject() {
- List<String> list = Collections.singletonList("string");
- return Collections.checkedCollection(list, String.class);
- }
-
- protected Collection<String> getAnotherObject() {
- List<String> list = Collections.emptyList();
- return Collections.checkedCollection(list, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedList.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedList encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedList extends AbstractTest<List<String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedList().test(true);
- }
-
- protected List<String> getObject() {
- List<String> list = Collections.singletonList("string");
- return Collections.checkedList(list, String.class);
- }
-
- protected List<String> getAnotherObject() {
- List<String> list = Collections.emptyList();
- return Collections.checkedList(list, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedMap.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.Map;
-
-public final class java_util_Collections_CheckedMap extends AbstractTest<Map<String, String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedMap().test(true);
- }
-
- protected Map<String, String> getObject() {
- Map<String, String> map = Collections.singletonMap("key", "value");
- return Collections.checkedMap(map, String.class, String.class);
- }
-
- protected Map<String, String> getAnotherObject() {
- Map<String, String> map = Collections.emptyMap();
- return Collections.checkedMap(map, String.class, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedRandomAccessList.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedRandomAccessList encoding
- * @author Sergey Malenkov
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedRandomAccessList extends AbstractTest<List<String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedRandomAccessList().test(true);
- }
-
- protected List<String> getObject() {
- List<String> list = new ArrayList<String>();
- list.add("string");
- return Collections.checkedList(list, String.class);
- }
-
- protected List<String> getAnotherObject() {
- List<String> list = new ArrayList<String>();
- return Collections.checkedList(list, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSet.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.Set;
-
-public final class java_util_Collections_CheckedSet extends AbstractTest<Set<String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedSet().test(true);
- }
-
- protected Set<String> getObject() {
- Set<String> set = Collections.singleton("string");
- return Collections.checkedSet(set, String.class);
- }
-
- protected Set<String> getAnotherObject() {
- Set<String> set = Collections.emptySet();
- return Collections.checkedSet(set, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedMap.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedSortedMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-public final class java_util_Collections_CheckedSortedMap extends AbstractTest<SortedMap<String, String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedSortedMap().test(true);
- }
-
- protected SortedMap<String, String> getObject() {
- SortedMap<String, String> map = new TreeMap<String, String>();
- map.put("key", "value");
- return Collections.checkedSortedMap(map, String.class, String.class);
- }
-
- protected SortedMap<String, String> getAnotherObject() {
- SortedMap<String, String> map = new TreeMap<String, String>();
- return Collections.checkedSortedMap(map, String.class, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedSet.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6505888
- * @summary Tests CheckedSortedSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-public final class java_util_Collections_CheckedSortedSet extends AbstractTest<SortedSet<String>> {
- public static void main(String[] args) {
- new java_util_Collections_CheckedSortedSet().test(true);
- }
-
- protected SortedSet<String> getObject() {
- SortedSet<String> set = new TreeSet<String>();
- set.add("string");
- return Collections.checkedSortedSet(set, String.class);
- }
-
- protected SortedSet<String> getAnotherObject() {
- SortedSet<String> set = new TreeSet<String>();
- return Collections.checkedSortedSet(set, String.class);
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_EnumMap.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6536295
- * @summary Tests EnumMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumMap;
-import java.util.Map;
-
-public final class java_util_EnumMap extends AbstractTest<Map<EnumPublic, String>> {
- public static void main(String[] args) {
- new java_util_EnumMap().test(true);
- }
-
- protected Map<EnumPublic, String> getObject() {
- return new EnumMap<EnumPublic, String>(EnumPublic.class);
- }
-
- protected Map<EnumPublic, String> getAnotherObject() {
- Map<EnumPublic, String> map = new EnumMap<EnumPublic, String>(EnumPublic.class);
- map.put(EnumPublic.A, "value");
- map.put(EnumPublic.Z, null);
- return map;
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_JumboEnumSet.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6536295
- * @summary Tests JumboEnumSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumSet;
-import java.util.Set;
-
-public final class java_util_JumboEnumSet extends AbstractTest<Set<EnumPrivate>> {
- public static void main(String[] args) {
- new java_util_JumboEnumSet().test(true);
- }
-
- protected Set<EnumPrivate> getObject() {
- return EnumSet.noneOf(EnumPrivate.class);
- }
-
- protected Set<EnumPrivate> getAnotherObject() {
- Set<EnumPrivate> set = EnumSet.noneOf(EnumPrivate.class);
- set.add(EnumPrivate.A0);
- set.add(EnumPrivate.Z9);
- return set;
- }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_RegularEnumSet.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6536295
- * @summary Tests RegularEnumSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumSet;
-import java.util.Set;
-
-public final class java_util_RegularEnumSet extends AbstractTest<Set<EnumPublic>> {
- public static void main(String[] args) {
- new java_util_RegularEnumSet().test(true);
- }
-
- protected Set<EnumPublic> getObject() {
- return EnumSet.noneOf(EnumPublic.class);
- }
-
- protected Set<EnumPublic> getAnotherObject() {
- Set<EnumPublic> set = EnumSet.noneOf(EnumPublic.class);
- set.add(EnumPublic.A);
- set.add(EnumPublic.Z);
- return set;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/CheckInputOrderTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,93 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.Security;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+/* @test
+ * @build CheckInputOrderTest SerialFilterTest
+ * @run testng/othervm CheckInputOrderTest
+ *
+ * @summary Test that when both global filter and specific filter are set,
+ * global filter will not affect specific filter.
+ */
+
+public class CheckInputOrderTest implements Serializable {
+ private static final long serialVersionUID = 12345678901L;
+
+ @DataProvider(name="Patterns")
+ Object[][] patterns() {
+ return new Object[][] {
+ new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long;maxarray=0", false },
+ new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long", true },
+ new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxdepth=0", false },
+ new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxbytes=0", false },
+ new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxrefs=0", false },
+
+ new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long", true },
+
+ new Object[] { Long.MAX_VALUE, "!java.**;java.lang.*;java.lang.Long", false },
+ new Object[] { Long.MAX_VALUE, "java.**;!java.lang.*;java.lang.Long", true },
+
+ new Object[] { Long.MAX_VALUE, "!java.lang.*;java.**;java.lang.Long", false },
+ new Object[] { Long.MAX_VALUE, "java.lang.*;!java.**;java.lang.Long", true },
+
+ new Object[] { Long.MAX_VALUE, "!java.lang.Long;java.**;java.lang.*", false },
+ new Object[] { Long.MAX_VALUE, "java.lang.Long;java.**;!java.lang.*", true },
+
+ new Object[] { Long.MAX_VALUE, "java.lang.Long;!java.**;java.lang.*", false },
+ new Object[] { Long.MAX_VALUE, "java.lang.Long;java.lang.Number;!java.**;java.lang.*", true },
+ };
+ }
+
+ /**
+ * Test:
+ * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
+ * "global filter reject" + "specific ObjectInputStream filter allow" => should allow
+ */
+ @Test(dataProvider="Patterns")
+ public void testRejectedInGlobal(Object toDeserialized, String pattern, boolean allowed) throws Exception {
+ byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ois.setObjectInputFilter(filter);
+ Object o = ois.readObject();
+ assertTrue(allowed, "filter should have thrown an exception");
+ } catch (InvalidClassException ice) {
+ assertFalse(allowed, "filter should have thrown an exception");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,100 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.security.AccessControlException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/* @test
+ * @build FilterWithSecurityManagerTest SerialFilterTest
+ * @run testng/othervm FilterWithSecurityManagerTest
+ * @run testng/othervm/policy=security.policy.without.globalFilter
+ * -Djava.security.manager=default FilterWithSecurityManagerTest
+ * @run testng/othervm/policy=security.policy
+ * -Djava.security.manager=default
+ * -Djdk.serialFilter=java.lang.Integer FilterWithSecurityManagerTest
+ *
+ * @summary Test that setting specific filter is checked by security manager,
+ * setting process-wide filter is checked by security manager.
+ */
+
+@Test
+public class FilterWithSecurityManagerTest {
+
+ byte[] bytes;
+ boolean setSecurityManager;
+ ObjectInputFilter filter;
+
+ @BeforeClass
+ public void setup() throws Exception {
+ setSecurityManager = System.getSecurityManager() != null;
+ Object toDeserialized = Long.MAX_VALUE;
+ bytes = SerialFilterTest.writeObjects(toDeserialized);
+ filter = ObjectInputFilter.Config.createFilter("java.lang.Long");
+ }
+
+ /**
+ * Test that setting process-wide filter is checked by security manager.
+ */
+ @Test
+ public void testGlobalFilter() throws Exception {
+ if (ObjectInputFilter.Config.getSerialFilter() == null) {
+ return;
+ }
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ObjectInputFilter.Config.setSerialFilter(filter);
+ assertFalse(setSecurityManager,
+ "When SecurityManager exists, without "
+ + "java.security.SerializablePermission(serialFilter) Exception should be thrown");
+ Object o = ois.readObject();
+ } catch (AccessControlException ex) {
+ assertTrue(setSecurityManager);
+ assertTrue(ex.getMessage().contains("java.io.SerializablePermission"));
+ assertTrue(ex.getMessage().contains("serialFilter"));
+ }
+ }
+
+ /**
+ * Test that setting specific filter is checked by security manager.
+ */
+ @Test(dependsOnMethods = { "testGlobalFilter" })
+ public void testSpecificFilter() throws Exception {
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ois.setObjectInputFilter(filter);
+ Object o = ois.readObject();
+ } catch (AccessControlException ex) {
+ assertTrue(setSecurityManager);
+ assertTrue(ex.getMessage().contains("java.io.SerializablePermission"));
+ assertTrue(ex.getMessage().contains("serialFilter"));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/GlobalFilterTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,218 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+
+import java.io.SerializablePermission;
+import java.security.Security;
+import java.util.Objects;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/* @test
+ * @build GlobalFilterTest SerialFilterTest
+ * @run testng/othervm GlobalFilterTest
+ * @run testng/othervm -Djdk.serialFilter=java.** GlobalFilterTest
+ * @run testng/othervm/policy=security.policy GlobalFilterTest
+ * @run testng/othervm/policy=security.policy
+ * -Djava.security.properties=${test.src}/java.security-extra1
+ * -Djava.security.debug=properties GlobalFilterTest
+ *
+ * @summary Test Global Filters
+ */
+@Test
+public class GlobalFilterTest {
+
+ /**
+ * DataProvider of patterns and objects derived from the configured process-wide filter.
+ * @return Array of arrays of pattern, object, allowed boolean, and API factory
+ */
+ @DataProvider(name="globalPatternElements")
+ Object[][] globalPatternElements() {
+ String globalFilter =
+ System.getProperty("jdk.serialFilter",
+ Security.getProperty("jdk.serialFilter"));
+ if (globalFilter == null) {
+ return new Object[0][];
+ }
+
+ String[] patterns = globalFilter.split(";");
+ Object[][] objects = new Object[patterns.length][];
+
+ for (int i = 0; i < patterns.length; i++) {
+ Object o;
+ boolean allowed;
+ String pattern = patterns[i].trim();
+ if (pattern.contains("=")) {
+ allowed = false;
+ o = SerialFilterTest.genTestObject(pattern, false);
+ } else {
+ allowed = !pattern.startsWith("!");
+ o = (allowed)
+ ? SerialFilterTest.genTestObject(pattern, true)
+ : SerialFilterTest.genTestObject(pattern.substring(1), false);
+
+ Assert.assertNotNull(o, "fail generation failed");
+ }
+ objects[i] = new Object[3];
+ objects[i][0] = pattern;
+ objects[i][1] = allowed;
+ objects[i][2] = o;
+ }
+ return objects;
+ }
+
+ /**
+ * Test that the process-wide filter is set when the properties are set
+ * and has the toString matching the configured pattern.
+ */
+ @Test()
+ static void globalFilter() {
+ String pattern =
+ System.getProperty("jdk.serialFilter",
+ Security.getProperty("jdk.serialFilter"));
+ ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter();
+ System.out.printf("global pattern: %s, filter: %s%n", pattern, filter);
+ Assert.assertEquals(pattern, Objects.toString(filter, null),
+ "process-wide filter pattern does not match");
+ }
+
+ /**
+ * If the Global filter is already set, it should always refuse to be
+ * set again.
+ * If there is a security manager, setting the serialFilter should fail
+ * without the appropriate permission.
+ * If there is no security manager then setting it should work.
+ */
+ @Test()
+ static void setGlobalFilter() {
+ SecurityManager sm = System.getSecurityManager();
+ ObjectInputFilter filter = new SerialFilterTest.Validator();
+ ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
+ if (global != null) {
+ // once set, can never be re-set
+ try {
+ ObjectInputFilter.Config.setSerialFilter(filter);
+ Assert.fail("set only once process-wide filter");
+ } catch (IllegalStateException ise) {
+ if (sm != null) {
+ Assert.fail("wrong exception when security manager is set", ise);
+ }
+ } catch (SecurityException se) {
+ if (sm == null) {
+ Assert.fail("wrong exception when security manager is not set", se);
+ }
+ }
+ } else {
+ if (sm == null) {
+ // no security manager
+ try {
+ ObjectInputFilter.Config.setSerialFilter(filter);
+ // Note once set, it can not be reset; so other tests
+ System.out.printf("Global Filter set to Validator%n");
+ } catch (SecurityException se) {
+ Assert.fail("setGlobalFilter should not get SecurityException", se);
+ }
+ try {
+ // Try to set it again, expecting it to throw
+ ObjectInputFilter.Config.setSerialFilter(filter);
+ Assert.fail("set only once process-wide filter");
+ } catch (IllegalStateException ise) {
+ // Normal case
+ }
+ } else {
+ // Security manager
+ SecurityException expectSE = null;
+ try {
+ sm.checkPermission(new SerializablePermission("serialFilter"));
+ } catch (SecurityException se1) {
+ expectSE = se1;
+ }
+ SecurityException actualSE = null;
+ try {
+ ObjectInputFilter.Config.setSerialFilter(filter);
+ } catch (SecurityException se2) {
+ actualSE = se2;
+ }
+ if (expectSE == null | actualSE == null) {
+ Assert.assertEquals(expectSE, actualSE, "SecurityException");
+ } else {
+ Assert.assertEquals(expectSE.getClass(), actualSE.getClass(),
+ "SecurityException class");
+ }
+ }
+ }
+ }
+
+ /**
+ * For each pattern in the process-wide filter test a generated object
+ * against the default process-wide filter.
+ *
+ * @param pattern a pattern extracted from the configured global pattern
+ */
+ @Test(dataProvider = "globalPatternElements")
+ static void globalFilterElements(String pattern, boolean allowed,Object obj) {
+ testGlobalPattern(pattern, obj, allowed);
+ }
+
+ /**
+ * Serialize and deserialize an object using the default process-wide filter
+ * and check allowed or reject.
+ *
+ * @param pattern the pattern
+ * @param object the test object
+ * @param allowed the expected result from ObjectInputStream (exception or not)
+ */
+ static void testGlobalPattern(String pattern, Object object, boolean allowed) {
+ try {
+// System.out.printf("global %s pattern: %s, obj: %s%n", (allowed ? "allowed" : "not allowed"), pattern, object);
+ byte[] bytes = SerialFilterTest.writeObjects(object);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ Object o = ois.readObject();
+ } catch (EOFException eof) {
+ // normal completion
+ } catch (ClassNotFoundException cnf) {
+ Assert.fail("Deserializing", cnf);
+ }
+ Assert.assertTrue(allowed, "filter should have thrown an exception");
+ } catch (IllegalArgumentException iae) {
+ Assert.fail("bad format pattern", iae);
+ } catch (InvalidClassException ice) {
+ Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice);
+ } catch (IOException ioe) {
+ Assert.fail("Unexpected IOException", ioe);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/MixedFiltersTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,137 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.Security;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/* @test
+ * @build MixedFiltersTest SerialFilterTest
+ * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5 MixedFiltersTest
+ * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest
+ *
+ * @summary Test that when both global filter and specific filter are set,
+ * global filter will not affect specific filter.
+ */
+
+public class MixedFiltersTest implements Serializable {
+
+ private static final long serialVersionUID = 1234567890L;
+
+
+ boolean globalRejected;
+
+ @BeforeClass
+ public void setup() {
+ String pattern = System.getProperty("jdk.serialFilter",
+ Security.getProperty("jdk.serialFilter"));
+ globalRejected = pattern.startsWith("!");
+ }
+
+ @DataProvider(name="RejectedInGlobal")
+ Object[][] rejectedInGlobal() {
+ if (!globalRejected) {
+ return new Object[0][];
+ }
+ return new Object[][] {
+ new Object[] { Long.MAX_VALUE, "java.**" },
+ new Object[] { Long.MAX_VALUE, "java.lang.Long" },
+ new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "java.lang.**" },
+ new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=100" },
+ new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=100" },
+ new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=1000" },
+ new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=100" },
+ };
+ }
+
+ /**
+ * Test:
+ * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
+ * "global filter reject" + "specific ObjectInputStream filter allow" => should allow
+ */
+ @Test(dataProvider="RejectedInGlobal")
+ public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception {
+ byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ Object o = ois.readObject();
+ fail("filter should have thrown an exception");
+ } catch (InvalidClassException expected) { }
+
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ois.setObjectInputFilter(filter);
+ Object o = ois.readObject();
+ }
+ }
+
+ @DataProvider(name="AllowedInGlobal")
+ Object[][] allowedInGlobal() {
+ if (globalRejected) {
+ return new Object[0][];
+ }
+
+ return new Object[][] {
+ new Object[] { Long.MAX_VALUE, "!java.**" },
+ new Object[] { Long.MAX_VALUE, "!java.lang.Long" },
+ new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "!java.lang.**" },
+ new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=5" },
+ new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=5" },
+ new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=5" },
+ new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=5" },
+ };
+ }
+
+ /**
+ * Test:
+ * "global filter allow" + "specific ObjectInputStream filter is empty" => should allow
+ * "global filter allow" + "specific ObjectInputStream filter reject" => should reject
+ */
+ @Test(dataProvider="AllowedInGlobal")
+ public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception {
+ byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ Object o = ois.readObject();
+ }
+
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ois.setObjectInputFilter(filter);
+ Object o = ois.readObject();
+ assertTrue(false, "filter should have thrown an exception");
+ } catch (InvalidClassException expected) { }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,752 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.concurrent.atomic.LongAdder;
+
+import javax.lang.model.SourceVersion;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/* @test
+ * @build SerialFilterTest
+ * @run testng/othervm SerialFilterTest
+ *
+ * @summary Test ObjectInputFilters
+ */
+@Test
+public class SerialFilterTest implements Serializable {
+
+ private static final long serialVersionUID = -6999613679881262446L;
+
+ /**
+ * Enable three arg lambda.
+ * @param <T> The pattern
+ * @param <U> The test object
+ * @param <V> Boolean for if the filter should allow or reject
+ */
+ interface TriConsumer< T, U, V> {
+ void accept(T t, U u, V v);
+ }
+
+ /**
+ * Misc object to use that should always be accepted.
+ */
+ private static final Object otherObject = Integer.valueOf(0);
+
+ /**
+ * DataProvider for the individual patterns to test.
+ * Expand the patterns into cases for each of the Std and Compatibility APIs.
+ * @return an array of arrays of the parameters including factories
+ */
+ @DataProvider(name="Patterns")
+ static Object[][] patterns() {
+ Object[][] patterns = new Object[][]{
+ {"java.util.Hashtable"},
+ {"java.util.Hash*"},
+ {"javax.lang.model.*"},
+ {"javax.lang.**"},
+ {"*"},
+ {"maxarray=47"},
+ {"maxdepth=5"},
+ {"maxrefs=10"},
+ {"maxbytes=100"},
+ {"maxbytes=72"},
+ {"maxbytes=+1024"},
+ {"java.base/java.util.Hashtable"},
+ };
+ return patterns;
+ }
+
+ @DataProvider(name="InvalidPatterns")
+ static Object[][] invalidPatterns() {
+ return new Object [][] {
+ {"maxrefs=-1"},
+ {"maxdepth=-1"},
+ {"maxbytes=-1"},
+ {"maxarray=-1"},
+ {"xyz=0"},
+ {"xyz=-1"},
+ {"maxrefs=0xabc"},
+ {"maxrefs=abc"},
+ {"maxrefs="},
+ {"maxrefs=+"},
+ {".*"},
+ {".**"},
+ {"!"},
+ {"/java.util.Hashtable"},
+ {"java.base/"},
+ {"/"},
+ };
+ }
+
+ @DataProvider(name="Limits")
+ static Object[][] limits() {
+ // The numbers are arbitrary > 1
+ return new Object[][]{
+ {"maxrefs", 10},
+ {"maxdepth", 5},
+ {"maxbytes", 100},
+ {"maxarray", 16},
+ };
+ }
+
+ /**
+ * DataProvider of individual objects. Used to check the information
+ * available to the filter.
+ * @return Arrays of parameters with objects
+ */
+ @DataProvider(name="Objects")
+ static Object[][] objects() {
+ byte[] byteArray = new byte[0];
+ Object[] objArray = new Object[7];
+ objArray[objArray.length - 1] = objArray;
+
+ Class<?> serClass = null;
+ String className = "java.util.concurrent.atomic.LongAdder$SerializationProxy";
+ try {
+ serClass = Class.forName(className);
+ } catch (Exception e) {
+ Assert.fail("missing class: " + className, e);
+ }
+
+ Class<?>[] interfaces = {Runnable.class};
+ Runnable proxy = (Runnable) Proxy.newProxyInstance(null,
+ interfaces, (p, m, args) -> p);
+
+ Runnable runnable = (Runnable & Serializable) SerialFilterTest::noop;
+ Object[][] objects = {
+ { null, 0, -1, 0, 0, 0,
+ new HashSet<>()}, // no callback, no values
+ { objArray, 3, 7, 8, 2, 55,
+ new HashSet<>(Arrays.asList(objArray.getClass()))},
+ { Object[].class, 1, -1, 1, 1, 40,
+ new HashSet<>(Arrays.asList(Object[].class))},
+ { new SerialFilterTest(), 1, -1, 1, 1, 37,
+ new HashSet<>(Arrays.asList(SerialFilterTest.class))},
+ { new LongAdder(), 2, -1, 1, 1, 93,
+ new HashSet<>(Arrays.asList(LongAdder.class, serClass))},
+ { new byte[14], 2, 14, 1, 1, 27,
+ new HashSet<>(Arrays.asList(byteArray.getClass()))},
+ { runnable, 13, 0, 10, 2, 514,
+ new HashSet<>(Arrays.asList(java.lang.invoke.SerializedLambda.class,
+ SerialFilterTest.class,
+ objArray.getClass()))},
+ { deepHashSet(10), 48, -1, 49, 11, 619,
+ new HashSet<>(Arrays.asList(HashSet.class))},
+ { proxy.getClass(), 3, -1, 1, 1, 114,
+ new HashSet<>(Arrays.asList(Runnable.class,
+ java.lang.reflect.Proxy.class))},
+ };
+ return objects;
+ }
+
+ @DataProvider(name="Arrays")
+ static Object[][] arrays() {
+ return new Object[][]{
+ {new Object[16], 16},
+ {new boolean[16], 16},
+ {new byte[16], 16},
+ {new char[16], 16},
+ {new int[16], 16},
+ {new long[16], 16},
+ {new short[16], 16},
+ {new float[16], 16},
+ {new double[16], 16},
+ };
+ }
+
+
+ /**
+ * Test each object and verify the classes identified by the filter,
+ * the count of calls to the filter, the max array size, max refs, max depth,
+ * max bytes.
+ * This test ignores/is not dependent on the global filter settings.
+ *
+ * @param object a Serializable object
+ * @param count the expected count of calls to the filter
+ * @param maxArray the maximum array size
+ * @param maxRefs the maximum references
+ * @param maxDepth the maximum depth
+ * @param maxBytes the maximum stream size
+ * @param classes the expected (unique) classes
+ * @throws IOException
+ */
+ @Test(dataProvider="Objects")
+ public static void t1(Object object,
+ long count, long maxArray, long maxRefs, long maxDepth, long maxBytes,
+ Set<Class<?>> classes) throws IOException {
+ byte[] bytes = writeObjects(object);
+ Validator validator = new Validator();
+ validate(bytes, validator);
+ System.out.printf("v: %s%n", validator);
+ Assert.assertEquals(validator.count, count, "callback count wrong");
+ Assert.assertEquals(validator.classes, classes, "classes mismatch");
+ Assert.assertEquals(validator.maxArray, maxArray, "maxArray mismatch");
+ Assert.assertEquals(validator.maxRefs, maxRefs, "maxRefs wrong");
+ Assert.assertEquals(validator.maxDepth, maxDepth, "depth wrong");
+ Assert.assertEquals(validator.maxBytes, maxBytes, "maxBytes wrong");
+ }
+
+ /**
+ * Test each pattern with an appropriate object.
+ * A filter is created from the pattern and used to serialize and
+ * deserialize a generated object with both the positive and negative case.
+ * This test ignores/is not dependent on the global filter settings.
+ *
+ * @param pattern a pattern
+ */
+ @Test(dataProvider="Patterns")
+ static void testPatterns(String pattern) {
+ evalPattern(pattern, (p, o, neg) -> testPatterns(p, o, neg));
+ }
+
+ /**
+ * Test that the filter on a OIS can be set only on a fresh OIS,
+ * before deserializing any objects.
+ * This test is agnostic the global filter being set or not.
+ */
+ @Test
+ static void nonResettableFilter() {
+ Validator validator1 = new Validator();
+ Validator validator2 = new Validator();
+
+ try {
+ byte[] bytes = writeObjects("text1"); // an object
+
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ // Check the initial filter is the global filter; may be null
+ ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
+ ObjectInputFilter initial = ois.getObjectInputFilter();
+ Assert.assertEquals(global, initial, "initial filter should be the global filter");
+
+ // Check if it can be set to null
+ ois.setObjectInputFilter(null);
+ ObjectInputFilter filter = ois.getObjectInputFilter();
+ Assert.assertNull(filter, "set to null should be null");
+
+ ois.setObjectInputFilter(validator1);
+ Object o = ois.readObject();
+ try {
+ ois.setObjectInputFilter(validator2);
+ Assert.fail("Should not be able to set filter twice");
+ } catch (IllegalStateException ise) {
+ // success, the exception was expected
+ }
+ } catch (EOFException eof) {
+ Assert.fail("Should not reach end-of-file", eof);
+ } catch (ClassNotFoundException cnf) {
+ Assert.fail("Deserializing", cnf);
+ }
+ } catch (IOException ex) {
+ Assert.fail("Unexpected IOException", ex);
+ }
+ }
+
+ /**
+ * Test that if an Objects readReadResolve method returns an array
+ * that the callback to the filter includes the proper array length.
+ * @throws IOException if an error occurs
+ */
+ @Test(dataProvider="Arrays")
+ static void testReadResolveToArray(Object array, int length) throws IOException {
+ ReadResolveToArray object = new ReadResolveToArray(array, length);
+ byte[] bytes = writeObjects(object);
+ Object o = validate(bytes, object); // the object is its own filter
+ Assert.assertEquals(o.getClass(), array.getClass(), "Filter not called with the array");
+ }
+
+
+ /**
+ * Test repeated limits use the last value.
+ * Construct a filter with the limit and the limit repeated -1.
+ * Invoke the filter with the limit to make sure it is rejected.
+ * Invoke the filter with the limit -1 to make sure it is accepted.
+ * @param name the name of the limit to test
+ * @param value a test value
+ */
+ @Test(dataProvider="Limits")
+ static void testLimits(String name, int value) {
+ Class<?> arrayClass = new int[0].getClass();
+ String pattern = String.format("%s=%d;%s=%d", name, value, name, value - 1);
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+ Assert.assertEquals(
+ filter.checkInput(new FilterValues(arrayClass, value, value, value, value)),
+ ObjectInputFilter.Status.REJECTED,
+ "last limit value not used: " + filter);
+ Assert.assertEquals(
+ filter.checkInput(new FilterValues(arrayClass, value-1, value-1, value-1, value-1)),
+ ObjectInputFilter.Status.UNDECIDED,
+ "last limit value not used: " + filter);
+ }
+
+ /**
+ * Test that returning null from a filter causes deserialization to fail.
+ */
+ @Test(expectedExceptions=InvalidClassException.class)
+ static void testNullStatus() throws IOException {
+ byte[] bytes = writeObjects(0); // an Integer
+ try {
+ Object o = validate(bytes, new ObjectInputFilter() {
+ public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo f) {
+ return null;
+ }
+ });
+ } catch (InvalidClassException ice) {
+ System.out.printf("Success exception: %s%n", ice);
+ throw ice;
+ }
+ }
+
+ /**
+ * Verify that malformed patterns throw IAE.
+ * @param pattern pattern from the data source
+ */
+ @Test(dataProvider="InvalidPatterns", expectedExceptions=IllegalArgumentException.class)
+ static void testInvalidPatterns(String pattern) {
+ try {
+ ObjectInputFilter.Config.createFilter(pattern);
+ } catch (IllegalArgumentException iae) {
+ System.out.printf(" success exception: %s%n", iae);
+ throw iae;
+ }
+ }
+
+ /**
+ * Test that Config.create returns null if the argument does not contain any patterns or limits.
+ */
+ @Test()
+ static void testEmptyPattern() {
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("");
+ Assert.assertNull(filter, "empty pattern did not return null");
+
+ filter = ObjectInputFilter.Config.createFilter(";;;;");
+ Assert.assertNull(filter, "pattern with only delimiters did not return null");
+ }
+
+ /**
+ * Read objects from the serialized stream, validated with the filter.
+ *
+ * @param bytes a byte array to read objects from
+ * @param filter the ObjectInputFilter
+ * @return the object deserialized if any
+ * @throws IOException can be thrown
+ */
+ static Object validate(byte[] bytes,
+ ObjectInputFilter filter) throws IOException {
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ ois.setObjectInputFilter(filter);
+
+ Object o = ois.readObject();
+ return o;
+ } catch (EOFException eof) {
+ // normal completion
+ } catch (ClassNotFoundException cnf) {
+ Assert.fail("Deserializing", cnf);
+ }
+ return null;
+ }
+
+ /**
+ * Write objects and return a byte array with the bytes.
+ *
+ * @param objects zero or more objects to serialize
+ * @return the byte array of the serialized objects
+ * @throws IOException if an exception occurs
+ */
+ static byte[] writeObjects(Object... objects) throws IOException {
+ byte[] bytes;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+ for (Object o : objects) {
+ oos.writeObject(o);
+ }
+ bytes = baos.toByteArray();
+ }
+ return bytes;
+ }
+
+ /**
+ * A filter that accumulates information about the checkInput callbacks
+ * that can be checked after readObject completes.
+ */
+ static class Validator implements ObjectInputFilter {
+ long count; // Count of calls to checkInput
+ HashSet<Class<?>> classes = new HashSet<>();
+ long maxArray = -1;
+ long maxRefs;
+ long maxDepth;
+ long maxBytes;
+
+ Validator() {
+ }
+
+ @Override
+ public ObjectInputFilter.Status checkInput(FilterInfo filter) {
+ count++;
+ if (filter.serialClass() != null) {
+ if (filter.serialClass().getName().contains("$$Lambda$")) {
+ // TBD: proper identification of serialized Lambdas?
+ // Fold the serialized Lambda into the SerializedLambda type
+ classes.add(SerializedLambda.class);
+ } else if (Proxy.isProxyClass(filter.serialClass())) {
+ classes.add(Proxy.class);
+ } else {
+ classes.add(filter.serialClass());
+ }
+
+ }
+ this.maxArray = Math.max(this.maxArray, filter.arrayLength());
+ this.maxRefs = Math.max(this.maxRefs, filter.references());
+ this.maxDepth = Math.max(this.maxDepth, filter.depth());
+ this.maxBytes = Math.max(this.maxBytes, filter.streamBytes());
+ return ObjectInputFilter.Status.UNDECIDED;
+ }
+
+ public String toString(){
+ return "count: " + count
+ + ", classes: " + classes.toString()
+ + ", maxArray: " + maxArray
+ + ", maxRefs: " + maxRefs
+ + ", maxDepth: " + maxDepth
+ + ", maxBytes: " + maxBytes;
+ }
+ }
+
+
+ /**
+ * Create a filter from a pattern and API factory, then serialize and
+ * deserialize an object and check allowed or reject.
+ *
+ * @param pattern the pattern
+ * @param object the test object
+ * @param allowed the expected result from ObjectInputStream (exception or not)
+ */
+ static void testPatterns(String pattern, Object object, boolean allowed) {
+ try {
+ byte[] bytes = SerialFilterTest.writeObjects(object);
+ ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+ validate(bytes, filter);
+ Assert.assertTrue(allowed, "filter should have thrown an exception");
+ } catch (IllegalArgumentException iae) {
+ Assert.fail("bad format pattern", iae);
+ } catch (InvalidClassException ice) {
+ Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice);
+ } catch (IOException ioe) {
+ Assert.fail("Unexpected IOException", ioe);
+ }
+ }
+
+ /**
+ * For a filter pattern, generate and apply a test object to the action.
+ * @param pattern a pattern
+ * @param action an action to perform on positive and negative cases
+ */
+ static void evalPattern(String pattern, TriConsumer<String, Object, Boolean> action) {
+ Object o = genTestObject(pattern, true);
+ Assert.assertNotNull(o, "success generation failed");
+ action.accept(pattern, o, true);
+
+ // Test the negative pattern
+ o = genTestObject(pattern, false);
+ Assert.assertNotNull(o, "fail generation failed");
+ String negPattern = pattern.contains("=") ? pattern : "!" + pattern;
+ action.accept(negPattern, o, false);
+ }
+
+ /**
+ * Generate a test object based on the pattern.
+ * Handles each of the forms of the pattern, wildcards,
+ * class name, various limit forms.
+ * @param pattern a pattern
+ * @param allowed a boolean indicating to generate the allowed or disallowed case
+ * @return an object or {@code null} to indicate no suitable object could be generated
+ */
+ static Object genTestObject(String pattern, boolean allowed) {
+ if (pattern.contains("=")) {
+ return genTestLimit(pattern, allowed);
+ } else if (pattern.endsWith("*")) {
+ return genTestObjectWildcard(pattern, allowed);
+ } else {
+ // class
+ // isolate module name, if any
+ int poffset = 0;
+ int soffset = pattern.indexOf('/', poffset);
+ String module = null;
+ if (soffset >= 0) {
+ poffset = soffset + 1;
+ module = pattern.substring(0, soffset);
+ }
+ try {
+ Class<?> clazz = Class.forName(pattern.substring(poffset));
+ Constructor<?> cons = clazz.getConstructor();
+ return cons.newInstance();
+ } catch (ClassNotFoundException ex) {
+ Assert.fail("no such class available: " + pattern);
+ } catch (InvocationTargetException
+ | NoSuchMethodException
+ | InstantiationException
+ | IllegalAccessException ex1) {
+ Assert.fail("newInstance: " + ex1);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Generate an object to be used with the various wildcard pattern forms.
+ * Explicitly supports only specific package wildcards with specific objects.
+ * @param pattern a wildcard pattern ending in "*"
+ * @param allowed a boolean indicating to generate the allowed or disallowed case
+ * @return an object within or outside the wildcard
+ */
+ static Object genTestObjectWildcard(String pattern, boolean allowed) {
+ if (pattern.endsWith(".**")) {
+ // package hierarchy wildcard
+ if (pattern.startsWith("javax.lang.")) {
+ return SourceVersion.RELEASE_5;
+ }
+ if (pattern.startsWith("java.")) {
+ return 4;
+ }
+ if (pattern.startsWith("javax.")) {
+ return SourceVersion.RELEASE_6;
+ }
+ return otherObject;
+ } else if (pattern.endsWith(".*")) {
+ // package wildcard
+ if (pattern.startsWith("javax.lang.model")) {
+ return SourceVersion.RELEASE_6;
+ }
+ } else {
+ // class wildcard
+ if (pattern.equals("*")) {
+ return otherObject; // any object will do
+ }
+ if (pattern.startsWith("java.util.Hash")) {
+ return new Hashtable<String, String>();
+ }
+ }
+ Assert.fail("Object could not be generated for pattern: "
+ + pattern
+ + ", allowed: " + allowed);
+ return null;
+ }
+
+ /**
+ * Generate a limit test object for the pattern.
+ * For positive cases, the object exactly hits the limit.
+ * For negative cases, the object is 1 greater than the limit
+ * @param pattern the pattern, containing "=" and a maxXXX keyword
+ * @param allowed a boolean indicating to generate the allowed or disallowed case
+ * @return a sitable object
+ */
+ static Object genTestLimit(String pattern, boolean allowed) {
+ int ndx = pattern.indexOf('=');
+ Assert.assertNotEquals(ndx, -1, "missing value in limit");
+ long value = Long.parseUnsignedLong(pattern.substring(ndx+1));
+ if (pattern.startsWith("maxdepth=")) {
+ // Return an object with the requested depth (or 1 greater)
+ long depth = allowed ? value : value + 1;
+ Object[] array = new Object[1];
+ for (int i = 1; i < depth; i++) {
+ Object[] n = new Object[1];
+ n[0] = array;
+ array = n;
+ }
+ return array;
+ } else if (pattern.startsWith("maxbytes=")) {
+ // Return a byte array that when written to OOS creates
+ // a stream of exactly the size requested.
+ return genMaxBytesObject(allowed, value);
+ } else if (pattern.startsWith("maxrefs=")) {
+ Object[] array = new Object[allowed ? (int)value - 1 : (int)value];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = otherObject;
+ }
+ return array;
+ } else if (pattern.startsWith("maxarray=")) {
+ return allowed ? new int[(int)value] : new int[(int)value+1];
+ }
+ Assert.fail("Object could not be generated for pattern: "
+ + pattern
+ + ", allowed: " + allowed);
+ return null;
+ }
+
+ /**
+ * Generate an an object that will be serialized to some number of bytes.
+ * Or 1 greater if allowed is false.
+ * It returns a two element Object array holding a byte array sized
+ * to achieve the desired total size.
+ * @param allowed true if the stream should be allowed at that size,
+ * false if the stream should be larger
+ * @param maxBytes the number of bytes desired in the stream;
+ * should not be less than 72 (due to protocol overhead).
+ * @return a object that will be serialized to the length requested
+ */
+ private static Object genMaxBytesObject(boolean allowed, long maxBytes) {
+ Object[] holder = new Object[2];
+ long desiredSize = allowed ? maxBytes : maxBytes + 1;
+ long actualSize = desiredSize;
+ long byteSize = desiredSize - 72; // estimate needed array size
+ do {
+ byteSize += (desiredSize - actualSize);
+ byte[] a = new byte[(int)byteSize];
+ holder[0] = a;
+ holder[1] = a;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream os = new ObjectOutputStream(baos)) {
+ os.writeObject(holder);
+ os.flush();
+ actualSize = baos.size();
+ } catch (IOException ie) {
+ Assert.fail("exception generating stream", ie);
+ }
+ } while (actualSize != desiredSize);
+ return holder;
+ }
+
+ /**
+ * Returns a HashSet of a requested depth.
+ * @param depth the depth
+ * @return a HashSet of HashSets...
+ */
+ static HashSet<Object> deepHashSet(int depth) {
+ HashSet<Object> hashSet = new HashSet<>();
+ HashSet<Object> s1 = hashSet;
+ HashSet<Object> s2 = new HashSet<>();
+ for (int i = 0; i < depth; i++ ) {
+ HashSet<Object> t1 = new HashSet<>();
+ HashSet<Object> t2 = new HashSet<>();
+ // make t1 not equal to t2
+ t1.add("by Jimminy");
+ s1.add(t1);
+ s1.add(t2);
+ s2.add(t1);
+ s2.add(t2);
+ s1 = t1;
+ s2 = t2;
+ }
+ return hashSet;
+ }
+
+ /**
+ * Simple method to use with Serialized Lambda.
+ */
+ private static void noop() {}
+
+
+ /**
+ * Class that returns an array from readResolve and also implements
+ * the ObjectInputFilter to check that it has the expected length.
+ */
+ static class ReadResolveToArray implements Serializable, ObjectInputFilter {
+ private static final long serialVersionUID = 123456789L;
+
+ private final Object array;
+ private final int length;
+
+ ReadResolveToArray(Object array, int length) {
+ this.array = array;
+ this.length = length;
+ }
+
+ Object readResolve() {
+ return array;
+ }
+
+ @Override
+ public ObjectInputFilter.Status checkInput(FilterInfo filter) {
+ if (ReadResolveToArray.class.isAssignableFrom(filter.serialClass())) {
+ return ObjectInputFilter.Status.ALLOWED;
+ }
+ if (filter.serialClass() != array.getClass() ||
+ (filter.arrayLength() >= 0 && filter.arrayLength() != length)) {
+ return ObjectInputFilter.Status.REJECTED;
+ }
+ return ObjectInputFilter.Status.UNDECIDED;
+ }
+
+ }
+
+ /**
+ * Hold a snapshot of values to be passed to an ObjectInputFilter.
+ */
+ static class FilterValues implements ObjectInputFilter.FilterInfo {
+ private final Class<?> clazz;
+ private final long arrayLength;
+ private final long depth;
+ private final long references;
+ private final long streamBytes;
+
+ public FilterValues(Class<?> clazz, long arrayLength, long depth, long references, long streamBytes) {
+ this.clazz = clazz;
+ this.arrayLength = arrayLength;
+ this.depth = depth;
+ this.references = references;
+ this.streamBytes = streamBytes;
+ }
+
+ @Override
+ public Class<?> serialClass() {
+ return clazz;
+ }
+
+ public long arrayLength() {
+ return arrayLength;
+ }
+
+ public long depth() {
+ return depth;
+ }
+
+ public long references() {
+ return references;
+ }
+
+ public long streamBytes() {
+ return streamBytes;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/java.security-extra1 Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,4 @@
+# Serialization Input Process-wide Filter
+# See conf/security/java.security for pattern synatx
+#
+jdk.serialFilter=java.**;javax.**;maxarray=34;maxdepth=7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/security.policy Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,12 @@
+// Individual Permissions to for GlobalFilterTest
+grant {
+ // Specific permission under test
+ permission java.security.SerializablePermission "serialFilter";
+ // Permissions needed to run the test
+ permission java.util.PropertyPermission "*", "read";
+ permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
+ permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ permission java.security.SecurityPermission "*";
+ permission java.lang.RuntimePermission "accessDeclaredMembers";
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/security.policy.without.globalFilter Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,9 @@
+// Individual Permissions for FilterWithSecurityManagerTest
+grant {
+ // Permissions needed to run the test
+ permission java.util.PropertyPermission "*", "read";
+ permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
+ permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ permission java.lang.RuntimePermission "accessDeclaredMembers";
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/DatagramSocket/ReuseAddressTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,466 @@
+/* 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.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MulticastSocket;
+import java.net.SocketException;
+
+/*
+ * @test
+ * @bug 8153674
+ * @summary Expected SocketException not thrown when calling bind() with
+ * setReuseAddress(false)
+ * @run main/othervm ReuseAddressTest
+ */
+
+public class ReuseAddressTest {
+
+ String getInfo(DatagramSocket soc) {
+ if (soc == null) {
+ return null;
+ }
+
+ return "localPort: " + soc.getLocalPort()
+ + "; localAddress: " + soc.getLocalAddress()
+ + "; remotePort: " + soc.getPort()
+ + "; remoteAddress: " + soc.getInetAddress()
+ + "; isClosed: " + soc.isClosed()
+ + "; isBound: " + soc.isBound();
+ }
+
+ static InetSocketAddress createSocketAddress(int testMcastPort) throws Exception {
+ InetAddress localAddress = InetAddress.getLocalHost();
+ InetSocketAddress localSocketAddress = new InetSocketAddress(localAddress, testMcastPort);
+ return localSocketAddress;
+ }
+
+ /* standalone interface */
+ public static void main(String argv[]) throws Exception {
+ ReuseAddressTest test = new ReuseAddressTest();
+ test.DatagramSocket0029();
+ test.DatagramSocket0030();
+ test.DatagramSocket0031();
+ test.DatagramSocket0032();
+ test.DatagramSocket0034();
+ test.DatagramSocket0035();
+ test.DatagramSocket2028();
+ test.DatagramSocket2029();
+ test.DatagramSocket2030();
+
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setReuseAddress(boolean on) throws SocketException,
+ * <br><b>on</b>: false.
+ * <br><b>Expected results</b>: getReuseAddress() will return false
+ */
+ public void DatagramSocket0029() throws Exception {
+ String testCaseID = "DatagramSocket0029";
+ System.out.println(" >> " + testCaseID + ": " + "public void setReuseAddress(boolean on) throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket(null);
+ ds.setReuseAddress(false);
+ if (ds.getReuseAddress() == true) {
+ throw new RuntimeException("SO_REUSEADDR is not set to false");
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setReuseAddress(boolean on) throws SocketException,
+ * <br><b>on</b>: true.
+ * <br><b>Expected results</b>: Allows completely duplicate bindings (same
+ * address and port) on multicast sockets
+ */
+ public void DatagramSocket0030() throws Exception {
+ String testCaseID = "DatagramSocket0030";
+ System.out.println(" >> " + testCaseID + ": " + "public void setReuseAddress(boolean on) throws SocketException");
+
+ MulticastSocket ms1 = null;
+ MulticastSocket ms2 = null;
+ try {
+ InetSocketAddress addr = createSocketAddress(5050);
+
+ ms1 = new MulticastSocket(null);
+ ms1.setReuseAddress(true);
+ if (!ms1.getReuseAddress()) {
+ System.out.println("Cannot check: "
+ + " safety for SO_REUSEADDR option is not guaranteed");
+ }
+
+ try {
+ ms1.bind(addr);
+ } catch (SocketException e) {
+ throw new RuntimeException("cannot bind first socket to " + addr
+ + " unexpected " + e);
+ }
+
+ ms2 = new MulticastSocket(null);
+ ms2.setReuseAddress(true);
+ if (!ms2.getReuseAddress()) {
+ System.out.println("Cannot check: "
+ + " safety for SO_REUSEADDR option is not guaranteed");
+ }
+
+ try {
+ ms2.bind(addr);
+ } catch (SocketException e) {
+ throw new RuntimeException("cannot bind second socket to " + addr
+ + " unexpected " + e);
+ }
+
+ if (ms1.getLocalPort() != addr.getPort() || !ms1.isBound()
+ || ms2.getLocalPort() != addr.getPort() || !ms2.isBound()) {
+ System.out.println("bind() fails with: " + addr);
+ System.out.println(" ms1 [" + getInfo(ms1) + "]");
+ System.out.println(" ms2 [" + getInfo(ms2) + "]");
+ System.out.println(" getReuseAddress(): " + ms2.getReuseAddress());
+ throw new RuntimeException("bind() fails with: " + addr);
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ms1 != null) {
+ ms1.close();
+ }
+ if (ms2 != null) {
+ ms2.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setReuseAddress(boolean on) throws SocketException,
+ * <br><b>on</b>: false.
+ * <br><b>Expected results</b>: The second bind will throw SocketException,
+ * when SO_REUSEADDR disable
+ */
+ public void DatagramSocket0031() throws Exception {
+ String testCaseID = "DatagramSocket0031";
+ System.out.println(" >> " + testCaseID + ": " + "public void setReuseAddress(boolean on) throws SocketException");
+
+ MulticastSocket ms1 = null;
+ MulticastSocket ms2 = null;
+ try {
+ InetSocketAddress addr = createSocketAddress(6060);
+
+ ms1 = new MulticastSocket(null);
+ try {
+ ms1.bind(addr);
+ } catch (SocketException e) {
+ throw new RuntimeException("cannot bind first socket to " + addr
+ + " unexpected " + e);
+ }
+
+ ms2 = new MulticastSocket(null);
+ ms2.setReuseAddress(false); // method under test
+
+ try {
+ ms2.bind(addr);
+ System.out.println("No exceptions: ");
+ System.out.println(" addr: " + addr);
+ System.out.println(" ms1 [" + getInfo(ms1) + "]");
+ System.out.println(" ms2 [" + getInfo(ms2) + "]");
+ System.out.println(" getReuseAddress(): " + ms2.getReuseAddress());
+ throw new RuntimeException("no exceptions from bind() with " + addr);
+ } catch (SocketException e) {
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ms1 != null) {
+ ms1.close();
+ }
+ if (ms2 != null) {
+ ms2.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setReuseAddress(boolean on) throws SocketException,
+ * <br><b>on</b>: true.
+ * <br><b>Expected results</b>: Allows a single process to bind the same
+ * port to multiple sockets as long as each bind specifies a different local
+ * IP address
+ */
+ public void DatagramSocket0032() throws Exception {
+ String testCaseID = "DatagramSocket0032";
+ System.out.println(" >> " + testCaseID + ": " + "public void setReuseAddress(boolean on) throws SocketException");
+
+ DatagramSocket ds1 = null;
+ DatagramSocket ds2 = null;
+ try {
+
+ InetSocketAddress isa = createSocketAddress(7070);
+ InetAddress addr = isa.getAddress();
+ InetAddress wildcard = InetAddress.getByName("0.0.0.0");
+ if (addr.equals(wildcard) || addr.isLoopbackAddress()) {
+ System.out.println("Cannot check: addresses are equal");
+ }
+
+ InetSocketAddress isa1 = new InetSocketAddress(addr, isa.getPort());
+ InetSocketAddress isa2 = new InetSocketAddress(wildcard, isa.getPort());
+
+ ds1 = new DatagramSocket(null);
+ ds1.setReuseAddress(true); // method under test
+ if (!ds1.getReuseAddress()) {
+ System.out.println("Cannot check: "
+ + " safety for SO_REUSEADDR option is not guaranteed");
+ }
+ ds1.bind(isa1);
+
+ ds2 = new DatagramSocket(null);
+ ds2.setReuseAddress(true); // method under test
+ if (!ds2.getReuseAddress()) {
+ System.out.println("Cannot check: "
+ + " safety for SO_REUSEADDR option is not guaranteed");
+ }
+
+ try {
+ ds2.bind(isa2);
+ } catch (SocketException e) {
+ throw new RuntimeException("cannot bind second socket to " + isa2
+ + " unexpected " + e);
+ }
+
+ if (ds1.getLocalPort() != isa.getPort() || !ds1.isBound()
+ || ds2.getLocalPort() != isa.getPort() || !ds2.isBound()) {
+ System.out.println("bind() fails with: " + addr);
+ System.out.println(" ds1 [" + getInfo(ds1) + "]");
+ System.out.println(" ds2 [" + getInfo(ds2) + "]");
+ System.out.println(" getReuseAddress(): " + ds2.getReuseAddress());
+ throw new RuntimeException("bind() fails with: " + addr);
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ds1 != null) {
+ ds1.close();
+ }
+ if (ds2 != null) {
+ ds2.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Assertion testing for public int getTrafficClass() throws
+ * SocketException, will return a number in range from 0 to 255 or throw
+ * SocketException.
+ */
+ public void DatagramSocket2028() throws Exception {
+ String testCaseID = "DatagramSocket2028";
+ System.out.println(" >> " + testCaseID + ": " + "public int getTrafficClass() throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket();
+ int tc = ds.getTrafficClass();
+ if (tc < 0 || tc > 255) {
+ throw new RuntimeException("getTrafficClass() returns: " + tc);
+ }
+ } catch (SecurityException e) {
+ System.out.println("Security restriction: " + e);
+ } catch (SocketException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("Unexpected exception : " + e);
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Assertion testing for public void setTrafficClass(int tc) throws
+ * SocketException, IAE will be thrown with tc less than 0 or greater than
+ * 255.
+ */
+ public void DatagramSocket2029() throws Exception {
+ String testCaseID = "DatagramSocket2029";
+ System.out.println(" >> " + testCaseID + ": " + "public void setTrafficClass(int tc) throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket();
+ } catch (SecurityException e) {
+ System.out.println("Security restriction: " + e);
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("cannot create socket: " + e);
+ }
+
+ int[] values = {
+ Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1000, -2, -1,
+ 256, 257, 1000, 50000, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
+ };
+
+ for (int i = 0; i < values.length; i++) {
+ try {
+ ds.setTrafficClass(values[i]);
+ System.out.println("No exception with: " + values[i]);
+ System.out.println("getTrafficClass() returns: " + ds.getTrafficClass());
+ ds.close();
+ throw new RuntimeException("setTrafficClass() fails with : " + values[i]);
+ } catch (SocketException e) {
+ ds.close();
+ e.printStackTrace(System.out);
+ throw new RuntimeException("setTrafficClass() throws : " + e);
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Assertion testing for public void setTrafficClass(int tc) throws
+ * SocketException, only SocketException may be thrown with tc in range from
+ * 0 to 255.
+ */
+ public void DatagramSocket2030() throws Exception {
+ String testCaseID = "DatagramSocket2030";
+ System.out.println(" >> " + testCaseID + ": " + "public void setTrafficClass(int tc) throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket();
+ } catch (SecurityException e) {
+ System.out.println("Security restriction: " + e);
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("cannot create socket: " + e);
+ }
+
+ for (int i = 0; i <= 255; i++) {
+ try {
+ ds.setTrafficClass(i);
+ } catch (SocketException e) {
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setBroadcast(boolean on) throws SocketException,
+ * <br><b>on</b>: false.
+ * <br><b>Expected results</b>: getBroadcast() will return false
+ */
+ public void DatagramSocket0034() throws Exception {
+ String testCaseID = "DatagramSocket0034";
+ System.out.println(" >> " + testCaseID + ": " + "public void setBroadcast(boolean on) throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket();
+ ds.setBroadcast(false);
+ if (ds.getBroadcast() == true) {
+ throw new RuntimeException("SO_BROADCAST is not set to false");
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Equivalence class partitioning with input values orientation for public
+ * void setBroadcast(boolean on) throws SocketException,
+ * <br><b>on</b>: true.
+ * <br><b>Expected results</b>: getBroadcast() will return true
+ */
+ public void DatagramSocket0035() throws Exception {
+ String testCaseID = "DatagramSocket0035";
+ System.out.println(" >> " + testCaseID + ": " + "public void setBroadcast(boolean on) throws SocketException");
+
+ DatagramSocket ds = null;
+ try {
+ ds = new DatagramSocket();
+ ds.setBroadcast(true);
+ if (ds.getBroadcast() == false) {
+ throw new RuntimeException("SO_BROADCAST is not set to true");
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.out);
+ throw new RuntimeException("unexpected: " + e);
+ } catch (SecurityException e) {
+ System.out.println("Security restriction");
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+}
--- a/jdk/test/java/security/AccessController/DoPrivAccompliceTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/java/security/AccessController/DoPrivAccompliceTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -31,7 +31,7 @@
import java.util.Arrays;
import java.util.List;
-/**
+/*
* @test
* @bug 8048362
* @compile ../../../lib/testlibrary/JavaToolUtils.java
@@ -41,6 +41,7 @@
* DoPrivAccmplice.jar for reading user.home property from a PrivilagedAction.
* Run DoPrivTest.jar and try to access user.home property using
* DoPrivAccmplice.jar.
+ * @modules jdk.compiler
* @run main/othervm DoPrivAccompliceTest
*/
--- a/jdk/test/java/security/Security/ClassLoader/DeprivilegedModuleLoaderTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/java/security/Security/ClassLoader/DeprivilegedModuleLoaderTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -21,6 +21,17 @@
* questions.
*/
+/*
+ * @test
+ * @bug 8159964
+ * @summary Classes from deprivileged modules should get loaded through
+ * Platform Classloader.
+ * @modules java.xml.crypto
+ * jdk.security.auth
+ * jdk.security.jgss
+ * @run main DeprivilegedModuleLoaderTest
+ */
+
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -30,13 +41,6 @@
import com.sun.security.auth.callback.TextCallbackHandler;
import com.sun.security.jgss.AuthorizationDataEntry;
-/*
- * @test
- * @bug 8159964
- * @summary Classes from deprivileged modules should get loaded through
- * Platform Classloader.
- * @run main DeprivilegedModuleLoaderTest
- */
public class DeprivilegedModuleLoaderTest {
public static void main(String[] args) {
--- a/jdk/test/java/security/Signature/SignatureLength.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/java/security/Signature/SignatureLength.java Wed Oct 05 06:28:23 2016 -0700
@@ -21,15 +21,20 @@
* questions.
*/
-import java.security.*;
-
/*
* @test
* @bug 8161571
* @summary Reject signatures presented for verification that contain extra
* bytes.
+ * @modules jdk.crypto.ec
* @run main SignatureLength
*/
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.SignatureException;
+
public class SignatureLength {
public static void main(String[] args) throws Exception {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/text/Format/DecimalFormat/Bug8165466.java Wed Oct 05 06:28:23 2016 -0700
@@ -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
+ * questions.
+ */
+/*
+ * @test
+ * @bug 8165466
+ * @summary Checks the subsequent function calls of the DecimalFormat.format()
+ * method in which the minimumFractionDigit is set to 0 and one of
+ * the format() call include formatting of the number with zero
+ * fraction value e.g. 0.00, 9.00
+ */
+
+import java.text.DecimalFormat;
+import java.util.Locale;
+
+public class Bug8165466 {
+
+ public static void main(String[] args) {
+ DecimalFormat nf = (DecimalFormat) DecimalFormat
+ .getPercentInstance(Locale.US);
+ nf.setMaximumFractionDigits(3);
+ nf.setMinimumFractionDigits(0);
+ nf.setMultiplier(1);
+
+ double d = 0.005678;
+ String result = nf.format(d);
+ if (!result.equals("0.006%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 0.006%, Found: " + result
+ + "]");
+ }
+
+ d = 0.00;
+ result = nf.format(d);
+ if (!result.equals("0%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 0%, Found: " + result
+ + "]");
+ }
+
+ d = 0.005678;
+ result = nf.format(d);
+ if (!result.equals("0.006%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 0.006%, Found: " + result
+ + "]");
+ }
+
+ //checking with the non zero value
+ d = 0.005678;
+ result = nf.format(d);
+ if (!result.equals("0.006%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 0.006%, Found: " + result
+ + "]");
+ }
+
+ d = 9.00;
+ result = nf.format(d);
+ if (!result.equals("9%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 9%, Found: " + result
+ + "]");
+ }
+
+ d = 0.005678;
+ result = nf.format(d);
+ if (!result.equals("0.006%")) {
+ throw new RuntimeException("[Failed while formatting the double"
+ + " value: " + d + " Expected: 0.006%, Found: " + result
+ + "]");
+ }
+ }
+
+}
+
--- a/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -26,7 +26,6 @@
* @bug 6279846
* @summary Verifies that transform between the same ICC color spaces does not
* change pixels
- * @run main ColorConvertTest
*/
import java.awt.image.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/InputFilesTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,212 @@
+/*
+ * 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 8165944
+ * @summary test several jar tool input file scenarios with variations on -C
+ * options with/without a --release option. Some input files are
+ * duplicates that sometimes cause exceptions and other times do not,
+ * demonstrating identical behavior to JDK 8 jar tool.
+ * @library /lib/testlibrary
+ * @modules jdk.jartool/sun.tools.jar
+ * @build jdk.testlibrary.FileUtils
+ * @run testng InputFilesTest
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import java.util.zip.ZipException;
+
+import jdk.testlibrary.FileUtils;
+
+public class InputFilesTest {
+ private final String nl = System.lineSeparator();
+ private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ private final PrintStream out = new PrintStream(baos);
+ private Runnable onCompletion;
+
+ @BeforeMethod
+ public void reset() {
+ onCompletion = null;
+ }
+
+ @AfterMethod
+ public void run() {
+ if (onCompletion != null) {
+ onCompletion.run();
+ }
+ }
+
+ @Test
+ public void test1() throws IOException {
+ mkdir("test1 test2");
+ touch("test1/testfile1 test2/testfile2");
+ jar("cf test.jar -C test1 . -C test2 .");
+ jar("tf test.jar");
+ println();
+ String output = "META-INF/" + nl +
+ "META-INF/MANIFEST.MF" + nl +
+ "testfile1" + nl +
+ "testfile2" + nl;
+ rm("test.jar test1 test2");
+ Assert.assertEquals(baos.toByteArray(), output.getBytes());
+ }
+
+ @Test
+ public void test2() throws IOException {
+ mkdir("test1 test2 test3 test4");
+ touch("test1/testfile1 test2/testfile2 test3/testfile3 test4/testfile4");
+ jar("cf test.jar -C test1 . -C test2 . --release 9 -C test3 . -C test4 .");
+ jar("tf test.jar");
+ println();
+ String output = "META-INF/" + nl +
+ "META-INF/MANIFEST.MF" + nl +
+ "testfile1" + nl +
+ "testfile2" + nl +
+ "META-INF/versions/9/testfile3" + nl +
+ "META-INF/versions/9/testfile4" + nl;
+ rm("test.jar test1 test2 test3 test4");
+ Assert.assertEquals(baos.toByteArray(), output.getBytes());
+ }
+
+ @Test
+ public void test3() throws IOException {
+ touch("test");
+ jar("cf test.jar test test");
+ jar("tf test.jar");
+ println();
+ String output = "META-INF/" + nl +
+ "META-INF/MANIFEST.MF" + nl +
+ "test" + nl;
+ rm("test.jar test");
+ Assert.assertEquals(baos.toByteArray(), output.getBytes());
+ }
+
+ @Test
+ public void test4() throws IOException {
+ mkdir("a");
+ touch("a/test");
+ jar("cf test.jar -C a test -C a test");
+ jar("tf test.jar");
+ println();
+ String output = "META-INF/" + nl +
+ "META-INF/MANIFEST.MF" + nl +
+ "test" + nl;
+ rm("test.jar a");
+ Assert.assertEquals(baos.toByteArray(), output.getBytes());
+ }
+
+ @Test(expectedExceptions = {ZipException.class})
+ public void test5() throws IOException {
+ mkdir("a");
+ touch("test a/test");
+ onCompletion = () -> rm("test a");
+ jar("cf test.jar -C a test test");
+ }
+
+ @Test(expectedExceptions = {ZipException.class})
+ public void test6() throws IOException {
+ mkdir("test1 test2");
+ touch("test1/a test2/a");
+ onCompletion = () -> rm("test1 test2");
+ jar("cf test.jar --release 9 -C test1 a -C test2 a");
+ }
+
+ private Stream<Path> mkpath(String... args) {
+ return Arrays.stream(args).map(d -> Paths.get(".", d.split("/")));
+ }
+
+ private void mkdir(String cmdline) {
+ System.out.println("mkdir -p " + cmdline);
+ mkpath(cmdline.split(" +")).forEach(p -> {
+ try {
+ Files.createDirectories(p);
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+ }
+
+ private void touch(String cmdline) {
+ System.out.println("touch " + cmdline);
+ mkpath(cmdline.split(" +")).forEach(p -> {
+ try {
+ Files.createFile(p);
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+ }
+
+ private void rm(String cmdline) {
+ System.out.println("rm -rf " + cmdline);
+ mkpath(cmdline.split(" +")).forEach(p -> {
+ try {
+ if (Files.isDirectory(p)) {
+ FileUtils.deleteFileTreeWithRetry(p);
+ } else {
+ FileUtils.deleteFileIfExistsWithRetry(p);
+ }
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+ }
+
+ private void jar(String cmdline) throws IOException {
+ System.out.println("jar " + cmdline);
+ baos.reset();
+
+ // the run method catches IOExceptions, we need to expose them
+ ByteArrayOutputStream baes = new ByteArrayOutputStream();
+ PrintStream err = new PrintStream(baes);
+ PrintStream saveErr = System.err;
+ System.setErr(err);
+ boolean ok = new sun.tools.jar.Main(out, err, "jar").run(cmdline.split(" +"));
+ System.setErr(saveErr);
+ if (!ok) {
+ String s = baes.toString();
+ if (s.startsWith("java.util.zip.ZipException: duplicate entry: ")) {
+ throw new ZipException(s);
+ }
+ throw new IOException(s);
+ }
+ }
+
+ private void println() throws IOException {
+ System.out.println(new String(baos.toByteArray()));
+ }
+}
--- a/jdk/test/tools/jar/multiRelease/Basic.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/tools/jar/multiRelease/Basic.java Wed Oct 05 06:28:23 2016 -0700
@@ -195,6 +195,8 @@
new String[] {"v10", "version", "Version.class"}
);
+ compare(jarfile, names);
+
delete(jarfile);
deleteDir(Paths.get(usr, "classes"));
}
--- a/jdk/test/tools/jlink/JLinkNegativeTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/tools/jlink/JLinkNegativeTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -191,7 +191,7 @@
.output(imageFile)
.addMods("not_zip")
.modulePath(helper.defaultModulePath())
- .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
+ .call().assertFailure("Error: java.io.IOException: Invalid jmod file");
} finally {
deleteDirectory(jmod);
}
@@ -236,13 +236,10 @@
JImageGenerator.addFiles(module, new InMemoryFile("unknown/A.class", new byte[0]));
try {
Result result = helper.generateDefaultImage(moduleName);
- if (result.getExitCode() != 4) {
+ System.err.println(result.getMessage());
+ if (result.getExitCode() == 0) {
throw new AssertionError("Crash expected");
}
- if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: unknown")) {
- System.err.println(result.getMessage());
- throw new AssertionError("InternalError expected");
- }
} finally {
deleteDirectory(module);
}
@@ -250,7 +247,7 @@
@Test(enabled = true)
public void testSectionsAreFiles() throws IOException {
- String moduleName = "module";
+ String moduleName = "hacked4";
Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
JImageGenerator.addFiles(jmod,
new InMemoryFile("/native", new byte[0]),
@@ -258,13 +255,10 @@
new InMemoryFile("/bin", new byte[0]));
try {
Result result = helper.generateDefaultImage(moduleName);
- if (result.getExitCode() != 4) {
+ System.err.println(result.getMessage());
+ if (result.getExitCode() == 0) {
throw new AssertionError("Crash expected");
}
- if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: ")) {
- System.err.println(result.getMessage());
- throw new AssertionError("InternalError expected");
- }
} finally {
deleteDirectory(jmod);
}
--- a/jdk/test/tools/jlink/JLinkTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/tools/jlink/JLinkTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -122,15 +122,6 @@
}
{
- String moduleName = "filter";
- Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
- String className = "_A.class";
- JImageGenerator.addFiles(jmod, new InMemoryFile(className, new byte[0]));
- Path image = helper.generateDefaultImage(moduleName).assertSuccess();
- helper.checkImage(image, moduleName, new String[] {"/" + moduleName + "/" + className}, null);
- }
-
- {
String moduleName = "m"; // 8163382
Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
JImageGenerator.getJLinkTask()
--- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -92,7 +92,7 @@
// Asterisk works exactly the same as above
{
- "*",
+ "--include-locales=*",
"jdk.localedata",
List.of(
"/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
--- a/langtools/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -380,3 +380,4 @@
af5eb8f3ffd21288305a54ea177ffad75021a741 jdk-9+135
c8f02f0ecbd7cd6700f47416e4b7e9d5ec20ad77 jdk-9+136
dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137
+90dd93e668a521642382561c47abe96ee2e065b7 jdk-9+138
--- a/langtools/make/gendata/Gendata-jdk.compiler.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/make/gendata/Gendata-jdk.compiler.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -52,7 +52,7 @@
$(RM) -r $(@D)
$(MKDIR) -p $(@D)
$(ECHO) Creating ct.sym classes
- $(JAVA) $(INTERIM_LANGTOOLS_ARGS) \
+ $(JAVA_SMALL) $(INTERIM_LANGTOOLS_ARGS) \
$(COMPILECREATESYMBOLS_ADD_EXPORTS) \
-classpath $(BUILDTOOLS_OUTPUTDIR)/create_symbols \
build.tools.symbolgenerator.CreateSymbols \
--- a/langtools/make/gensrc/GensrcCommon.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/make/gensrc/GensrcCommon.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -32,12 +32,12 @@
################################################################################
# The compileprops tools compiles a properties file into a resource bundle.
-TOOL_COMPILEPROPS_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \
+TOOL_COMPILEPROPS_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \
compileproperties.CompileProperties -quiet
################################################################################
# The compileprops tools compiles a properties file into an enum-like class.
-TOOL_PARSEPROPS_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \
+TOOL_PARSEPROPS_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \
propertiesparser.PropertiesParser
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java Wed Oct 05 06:28:23 2016 -0700
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.function.Function;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
@@ -38,10 +39,14 @@
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
+import com.sun.tools.javac.code.Symbol.Completer;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.jvm.ModuleNameReader;
+import com.sun.tools.javac.jvm.ModuleNameReader.BadClassFile;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.Fragment;
@@ -50,7 +55,6 @@
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
-import com.sun.tools.javac.util.StringUtils;
import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -84,6 +88,10 @@
private final JCDiagnostic.Factory diags;
+ private ModuleNameReader moduleNameReader;
+
+ public ModuleInfoSourceFileCompleter sourceFileCompleter;
+
/** Get the ModuleFinder instance for this invocation. */
public static ModuleFinder instance(Context context) {
ModuleFinder instance = context.get(moduleFinderKey);
@@ -182,6 +190,8 @@
return list;
}
+ private boolean inFindSingleModule;
+
public ModuleSymbol findSingleModule() {
try {
JavaFileObject src_fo = getModuleInfoFromLocation(StandardLocation.SOURCE_PATH, Kind.SOURCE);
@@ -194,26 +204,41 @@
if (fo == null) {
msym = syms.unnamedModule;
} else {
- // Note: the following may trigger a re-entrant call to Modules.enter
-// msym = new ModuleSymbol();
-// ClassSymbol info = new ClassSymbol(Flags.MODULE, names.module_info, msym);
-// info.modle = msym;
-// info.classfile = fo;
-// info.members_field = WriteableScope.create(info);
-// msym.module_info = info;
- msym = ModuleSymbol.create(null, names.module_info);
- msym.module_info.classfile = fo;
- msym.completer = sym -> classFinder.fillIn(msym.module_info);
-// // TODO: should we do the following here, or as soon as we find the name in
-// // the source or class file?
-// // Consider the case when the class/source path module shadows one on the
-// // module source path
-// if (syms.modules.get(msym.name) != null) {
-// // error: module already defined
-// System.err.println("ERROR: module already defined: " + msym);
-// } else {
-// syms.modules.put(msym.name, msym);
-// }
+ switch (fo.getKind()) {
+ case SOURCE:
+ if (!inFindSingleModule) {
+ try {
+ inFindSingleModule = true;
+ // Note: the following will trigger a re-entrant call to Modules.enter
+ msym = sourceFileCompleter.complete(fo);
+ msym.module_info.classfile = fo;
+ } finally {
+ inFindSingleModule = false;
+ }
+ } else {
+ //the module-info.java does not contain a module declaration,
+ //avoid infinite recursion:
+ msym = syms.unnamedModule;
+ }
+ break;
+ case CLASS:
+ Name name;
+ try {
+ name = names.fromString(readModuleName(fo));
+ } catch (BadClassFile | IOException ex) {
+ //fillIn will report proper errors:
+ name = names.error;
+ }
+ msym = syms.enterModule(name);
+ msym.module_info.classfile = fo;
+ msym.completer = Completer.NULL_COMPLETER;
+ classFinder.fillIn(msym.module_info);
+ break;
+ default:
+ Assert.error();
+ msym = syms.unnamedModule;
+ break;
+ }
}
msym.classLocation = StandardLocation.CLASS_OUTPUT;
@@ -224,6 +249,12 @@
}
}
+ private String readModuleName(JavaFileObject jfo) throws IOException, ModuleNameReader.BadClassFile {
+ if (moduleNameReader == null)
+ moduleNameReader = new ModuleNameReader();
+ return moduleNameReader.readModuleName(jfo);
+ }
+
private JavaFileObject getModuleInfoFromLocation(Location location, Kind kind) throws IOException {
if (!fileManager.hasLocation(location))
return null;
@@ -332,4 +363,8 @@
}
}
+ public interface ModuleInfoSourceFileCompleter {
+ public ModuleSymbol complete(JavaFileObject file);
+ }
+
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Wed Oct 05 06:28:23 2016 -0700
@@ -916,7 +916,6 @@
/**
* Create a ModuleSymbol with an associated module-info ClassSymbol.
- * The name of the module may be null, if it is not known yet.
*/
public static ModuleSymbol create(Name name, Name module_info) {
ModuleSymbol msym = new ModuleSymbol(name, null);
@@ -930,6 +929,7 @@
public ModuleSymbol(Name name, Symbol owner) {
super(MDL, 0, name, null, owner);
+ Assert.checkNonNull(name);
this.type = new ModuleType(this);
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Wed Oct 05 06:28:23 2016 -0700
@@ -764,17 +764,6 @@
return msym;
}
- public void enterModule(ModuleSymbol msym, Name name) {
- Assert.checkNull(modules.get(name));
- Assert.checkNull(msym.name);
- msym.name = name;
- addRootPackageFor(msym);
- ClassSymbol info = msym.module_info;
- info.fullname = msym.name.append('.', names.module_info);
- info.flatname = info.fullname;
- modules.put(name, msym);
- }
-
public ModuleSymbol getModule(Name name) {
return modules.get(name);
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Wed Oct 05 06:28:23 2016 -0700
@@ -292,15 +292,12 @@
Name name = TreeInfo.fullName(decl.qualId);
ModuleSymbol sym;
if (c != null) {
- sym = (ModuleSymbol) c.owner;
- if (sym.name == null) {
- //ModuleFinder.findSingleModule creates a stub of a ModuleSymbol without a name,
- //fill the name here after the module-info.java has been parsed
- //also enter the ModuleSymbol among modules:
- syms.enterModule(sym, name);
- } else {
- // TODO: validate name
- }
+ sym = (ModuleSymbol) c.owner;
+ Assert.checkNonNull(sym.name);
+ Name treeName = TreeInfo.fullName(decl.qualId);
+ if (sym.name != treeName) {
+ log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name));
+ }
} else {
sym = syms.enterModule(name);
if (sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) {
@@ -1006,6 +1003,10 @@
return new Symbol.Completer() {
@Override
public void complete(Symbol sym) throws CompletionFailure {
+ if (inInitModules) {
+ sym.completer = this;
+ return ;
+ }
ModuleSymbol msym = (ModuleSymbol) sym;
Set<ModuleSymbol> allModules = allModules();
for (ModuleSymbol m : allModules) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Wed Oct 05 06:28:23 2016 -0700
@@ -415,10 +415,10 @@
if (!isSameMemberWhenErased(dest, impl, impl_erasure))
return true;
- // If the erasure of the return type is different, a
- // bridge is needed.
- return !types.isSameType(impl_erasure.getReturnType(),
- method_erasure.getReturnType());
+ /* Bottom line: A bridge is needed if the erasure of the implementation
+ is different from that of the method that it overrides.
+ */
+ return !types.isSameType(impl_erasure, method_erasure);
} else {
// method and impl are the same...
if ((method.flags() & ABSTRACT) != 0) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Wed Oct 05 06:28:23 2016 -0700
@@ -80,6 +80,7 @@
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.jvm.ModuleNameReader;
import com.sun.tools.javac.util.Pair;
import com.sun.tools.javac.util.StringUtils;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ModuleNameReader.java Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/*
- * 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
- * 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 com.sun.tools.javac.file;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import com.sun.tools.javac.jvm.ClassFile;
-
-import static com.sun.tools.javac.jvm.ClassFile.*;
-
-
-/**
- * Stripped down ClassReader, just sufficient to read module names from module-info.class files
- * while analyzing the module path.
- *
- * <p>
- * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
- * your own risk. This code and its internal interfaces are subject to change or deletion without
- * notice.</b>
- */
-public class ModuleNameReader {
- static class BadClassFile extends Exception {
- private static final long serialVersionUID = 0;
- BadClassFile(String msg) {
- super(msg);
- }
- }
-
- private static final int INITIAL_BUFFER_SIZE = 0x0fff0;
-
- /** The buffer containing the currently read class file.
- */
- private byte[] buf = new byte[INITIAL_BUFFER_SIZE];
-
- /** The current input pointer.
- */
- private int bp;
-
- /** The objects of the constant pool.
- */
- private Object[] poolObj;
-
- /** For every constant pool entry, an index into buf where the
- * defining section of the entry is found.
- */
- private int[] poolIdx;
-
- ModuleNameReader() {
- }
-
- String readModuleName(Path p) throws IOException, BadClassFile {
- try (InputStream in = Files.newInputStream(p)) {
- bp = 0;
- buf = readInputStream(buf, in);
-
- int magic = nextInt();
- if (magic != JAVA_MAGIC)
- throw new BadClassFile("illegal.start.of.class.file");
-
- int minorVersion = nextChar();
- int majorVersion = nextChar();
-
- indexPool();
-
- int accessflags = nextChar();
- return readModuleInfoName(nextChar());
- }
- }
-
- /** Extract a character at position bp from buf.
- */
- char getChar(int bp) {
- return
- (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
- }
-
- /** Read a character.
- */
- char nextChar() {
- return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
- }
-
- /** Read an integer.
- */
- int nextInt() {
- return
- ((buf[bp++] & 0xFF) << 24) +
- ((buf[bp++] & 0xFF) << 16) +
- ((buf[bp++] & 0xFF) << 8) +
- (buf[bp++] & 0xFF);
- }
-
- /** Index all constant pool entries, writing their start addresses into
- * poolIdx.
- */
- void indexPool() throws BadClassFile {
- poolIdx = new int[nextChar()];
- poolObj = new Object[poolIdx.length];
- int i = 1;
- while (i < poolIdx.length) {
- poolIdx[i++] = bp;
- byte tag = buf[bp++];
- switch (tag) {
- case CONSTANT_Utf8: case CONSTANT_Unicode: {
- int len = nextChar();
- bp = bp + len;
- break;
- }
- case CONSTANT_Class:
- case CONSTANT_String:
- case CONSTANT_MethodType:
- bp = bp + 2;
- break;
- case CONSTANT_MethodHandle:
- bp = bp + 3;
- break;
- case CONSTANT_Fieldref:
- case CONSTANT_Methodref:
- case CONSTANT_InterfaceMethodref:
- case CONSTANT_NameandType:
- case CONSTANT_Integer:
- case CONSTANT_Float:
- case CONSTANT_InvokeDynamic:
- bp = bp + 4;
- break;
- case CONSTANT_Long:
- case CONSTANT_Double:
- bp = bp + 8;
- i++;
- break;
- default:
- throw new BadClassFile("malformed constant pool");
- }
- }
- }
-
- /** Read the class name of a module-info.class file.
- * The name is stored in a CONSTANT_Class entry, where the
- * class name is of the form module-name/module-info.
- */
- String readModuleInfoName(int i) throws BadClassFile {
- int classIndex = poolIdx[i];
- if (buf[classIndex] == CONSTANT_Class) {
- int utf8Index = poolIdx[getChar(classIndex + 1)];
- if (buf[utf8Index] == CONSTANT_Utf8) {
- int len = getChar(utf8Index + 1);
- int start = utf8Index + 3;
- String suffix = "/module-info";
- if (endsWith(buf, start, len, suffix))
- return new String(ClassFile.internalize(buf, start, len - suffix.length()));
- }
- }
- throw new BadClassFile("bad module-info name");
- }
-
- private boolean endsWith(byte[] buf, int start, int len, String suffix) {
- if (len <= suffix.length())
- return false;
- for (int i = 0; i < suffix.length(); i++) {
- if (buf[start + len - suffix.length() + i] != suffix.charAt(i))
- return false;
- }
- return true;
- }
-
- private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
- try {
- buf = ensureCapacity(buf, s.available());
- int r = s.read(buf);
- int bp = 0;
- while (r != -1) {
- bp += r;
- buf = ensureCapacity(buf, bp);
- r = s.read(buf, bp, buf.length - bp);
- }
- return buf;
- } finally {
- try {
- s.close();
- } catch (IOException e) {
- /* Ignore any errors, as this stream may have already
- * thrown a related exception which is the one that
- * should be reported.
- */
- }
- }
- }
-
- /*
- * ensureCapacity will increase the buffer as needed, taking note that
- * the new buffer will always be greater than the needed and never
- * exactly equal to the needed size or bp. If equal then the read (above)
- * will infinitely loop as buf.length - bp == 0.
- */
- private static byte[] ensureCapacity(byte[] buf, int needed) {
- if (buf.length <= needed) {
- byte[] old = buf;
- buf = new byte[Integer.highestOneBit(needed) << 1];
- System.arraycopy(old, 0, buf, 0, old.length);
- }
- return buf;
- }
-}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Oct 05 06:28:23 2016 -0700
@@ -2396,12 +2396,15 @@
} else {
c.flags_field = flags;
Name modInfoName = readModuleInfoName(nextChar());
- if (c.owner.name == null) {
- syms.enterModule((ModuleSymbol) c.owner, Convert.packagePart(modInfoName));
- } else {
- // TODO: validate name
+ currentModule = (ModuleSymbol) c.owner;
+ if (currentModule.name.append('.', names.module_info) != modInfoName) {
+ //strip trailing .module-info, if exists:
+ int modInfoStart = modInfoName.length() - names.module_info.length();
+ modInfoName = modInfoName.subName(modInfoStart, modInfoName.length()) == names.module_info &&
+ modInfoName.charAt(modInfoStart - 1) == '.' ?
+ modInfoName.subName(0, modInfoStart - 1) : modInfoName;
+ throw badClassFile("module.name.mismatch", modInfoName, currentModule.name);
}
- currentModule = (ModuleSymbol) c.owner;
}
// class attributes must be read before class
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,235 @@
+/*
+ * 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
+ * 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 com.sun.tools.javac.jvm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.jvm.ClassFile;
+
+import static com.sun.tools.javac.jvm.ClassFile.*;
+
+
+/**
+ * Stripped down ClassReader, just sufficient to read module names from module-info.class files
+ * while analyzing the module path.
+ *
+ * <p>
+ * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
+ * your own risk. This code and its internal interfaces are subject to change or deletion without
+ * notice.</b>
+ */
+public class ModuleNameReader {
+ public static class BadClassFile extends Exception {
+ private static final long serialVersionUID = 0;
+ BadClassFile(String msg) {
+ super(msg);
+ }
+ }
+
+ private static final int INITIAL_BUFFER_SIZE = 0x0fff0;
+
+ /** The buffer containing the currently read class file.
+ */
+ private byte[] buf = new byte[INITIAL_BUFFER_SIZE];
+
+ /** The current input pointer.
+ */
+ private int bp;
+
+ /** For every constant pool entry, an index into buf where the
+ * defining section of the entry is found.
+ */
+ private int[] poolIdx;
+
+ public ModuleNameReader() {
+ }
+
+ public String readModuleName(Path p) throws IOException, BadClassFile {
+ try (InputStream in = Files.newInputStream(p)) {
+ return readModuleName(in);
+ }
+ }
+
+ public String readModuleName(JavaFileObject jfo) throws IOException, BadClassFile {
+ try (InputStream in = jfo.openInputStream()) {
+ return readModuleName(in);
+ }
+ }
+
+ public String readModuleName(InputStream in) throws IOException, BadClassFile {
+ bp = 0;
+ buf = readInputStream(buf, in);
+
+ int magic = nextInt();
+ if (magic != JAVA_MAGIC)
+ throw new BadClassFile("illegal.start.of.class.file");
+
+ int minorVersion = nextChar();
+ int majorVersion = nextChar();
+
+ indexPool();
+
+ int accessflags = nextChar();
+ return readModuleInfoName(nextChar());
+ }
+
+ /** Extract a character at position bp from buf.
+ */
+ char getChar(int bp) {
+ return
+ (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
+ }
+
+ /** Read a character.
+ */
+ char nextChar() {
+ return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
+ }
+
+ /** Read an integer.
+ */
+ int nextInt() {
+ return
+ ((buf[bp++] & 0xFF) << 24) +
+ ((buf[bp++] & 0xFF) << 16) +
+ ((buf[bp++] & 0xFF) << 8) +
+ (buf[bp++] & 0xFF);
+ }
+
+ /** Index all constant pool entries, writing their start addresses into
+ * poolIdx.
+ */
+ void indexPool() throws BadClassFile {
+ poolIdx = new int[nextChar()];
+ int i = 1;
+ while (i < poolIdx.length) {
+ poolIdx[i++] = bp;
+ byte tag = buf[bp++];
+ switch (tag) {
+ case CONSTANT_Utf8: case CONSTANT_Unicode: {
+ int len = nextChar();
+ bp = bp + len;
+ break;
+ }
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ case CONSTANT_MethodType:
+ bp = bp + 2;
+ break;
+ case CONSTANT_MethodHandle:
+ bp = bp + 3;
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ case CONSTANT_NameandType:
+ case CONSTANT_Integer:
+ case CONSTANT_Float:
+ case CONSTANT_InvokeDynamic:
+ bp = bp + 4;
+ break;
+ case CONSTANT_Long:
+ case CONSTANT_Double:
+ bp = bp + 8;
+ i++;
+ break;
+ default:
+ throw new BadClassFile("malformed constant pool");
+ }
+ }
+ }
+
+ /** Read the class name of a module-info.class file.
+ * The name is stored in a CONSTANT_Class entry, where the
+ * class name is of the form module-name/module-info.
+ */
+ String readModuleInfoName(int i) throws BadClassFile {
+ int classIndex = poolIdx[i];
+ if (buf[classIndex] == CONSTANT_Class) {
+ int utf8Index = poolIdx[getChar(classIndex + 1)];
+ if (buf[utf8Index] == CONSTANT_Utf8) {
+ int len = getChar(utf8Index + 1);
+ int start = utf8Index + 3;
+ String suffix = "/module-info";
+ if (endsWith(buf, start, len, suffix))
+ return new String(ClassFile.internalize(buf, start, len - suffix.length()));
+ }
+ }
+ throw new BadClassFile("bad module-info name");
+ }
+
+ private boolean endsWith(byte[] buf, int start, int len, String suffix) {
+ if (len <= suffix.length())
+ return false;
+ for (int i = 0; i < suffix.length(); i++) {
+ if (buf[start + len - suffix.length() + i] != suffix.charAt(i))
+ return false;
+ }
+ return true;
+ }
+
+ private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
+ try {
+ buf = ensureCapacity(buf, s.available());
+ int r = s.read(buf);
+ int bp = 0;
+ while (r != -1) {
+ bp += r;
+ buf = ensureCapacity(buf, bp);
+ r = s.read(buf, bp, buf.length - bp);
+ }
+ return buf;
+ } finally {
+ try {
+ s.close();
+ } catch (IOException e) {
+ /* Ignore any errors, as this stream may have already
+ * thrown a related exception which is the one that
+ * should be reported.
+ */
+ }
+ }
+ }
+
+ /*
+ * ensureCapacity will increase the buffer as needed, taking note that
+ * the new buffer will always be greater than the needed and never
+ * exactly equal to the needed size or bp. If equal then the read (above)
+ * will infinitely loop as buf.length - bp == 0.
+ */
+ private static byte[] ensureCapacity(byte[] buf, int needed) {
+ if (buf.length <= needed) {
+ byte[] old = buf;
+ buf = new byte[Integer.highestOneBit(needed) << 1];
+ System.arraycopy(old, 0, buf, 0, old.length);
+ }
+ return buf;
+ }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Oct 05 06:28:23 2016 -0700
@@ -37,6 +37,7 @@
import java.util.Queue;
import java.util.ResourceBundle;
import java.util.Set;
+import java.util.function.Function;
import javax.annotation.processing.Processor;
import javax.lang.model.SourceVersion;
@@ -67,7 +68,9 @@
import com.sun.tools.javac.tree.JCTree.JCLambda;
import com.sun.tools.javac.tree.JCTree.JCMemberReference;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.JCDiagnostic.Factory;
@@ -341,6 +344,13 @@
}
};
+ protected final ModuleFinder.ModuleInfoSourceFileCompleter moduleInfoSourceFileCompleter =
+ fo -> (ModuleSymbol) readSourceFile(parseImplicitFile(fo), null, tl -> {
+ return tl.defs.nonEmpty() && tl.defs.head.hasTag(Tag.MODULEDEF) ?
+ ((JCModuleDecl) tl.defs.head).sym.module_info :
+ syms.defineClass(names.module_info, syms.errModule);
+ }).owner;
+
/**
* Command line options.
*/
@@ -411,6 +421,7 @@
diags = Factory.instance(context);
finder.sourceCompleter = sourceCompleter;
+ moduleFinder.sourceFileCompleter = moduleInfoSourceFileCompleter;
options = Options.instance(context);
@@ -779,6 +790,19 @@
readSourceFile(null, c);
}
+ private JCTree.JCCompilationUnit parseImplicitFile(JavaFileObject filename) {
+ JavaFileObject prev = log.useSource(filename);
+ try {
+ JCTree.JCCompilationUnit t = parse(filename, filename.getCharContent(false));
+ return t;
+ } catch (IOException e) {
+ log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
+ return make.TopLevel(List.<JCTree>nil());
+ } finally {
+ log.useSource(prev);
+ }
+ }
+
/** Compile a ClassSymbol from source, optionally using the given compilation unit as
* the source tree.
* @param tree the compilation unit in which the given ClassSymbol resides,
@@ -789,20 +813,20 @@
if (completionFailureName == c.fullname) {
throw new CompletionFailure(c, "user-selected completion failure by class name");
}
- JavaFileObject filename = c.classfile;
- JavaFileObject prev = log.useSource(filename);
if (tree == null) {
- try {
- tree = parse(filename, filename.getCharContent(false));
- } catch (IOException e) {
- log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
- tree = make.TopLevel(List.<JCTree>nil());
- } finally {
- log.useSource(prev);
- }
+ tree = parseImplicitFile(c.classfile);
}
+ readSourceFile(tree, c, cut -> c);
+ }
+
+ private ClassSymbol readSourceFile(JCCompilationUnit tree,
+ ClassSymbol expectedSymbol,
+ Function<JCCompilationUnit, ClassSymbol> symbolGetter)
+ throws CompletionFailure {
+ Assert.checkNonNull(tree);
+
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.started(e);
@@ -814,18 +838,20 @@
// Note that if module resolution failed, we may not even
// have enough modules available to access java.lang, and
// so risk getting FatalError("no.java.lang") from MemberEnter.
- if (!modules.enter(List.of(tree), c)) {
- throw new CompletionFailure(c, diags.fragment("cant.resolve.modules"));
+ if (!modules.enter(List.of(tree), expectedSymbol)) {
+ throw new CompletionFailure(symbolGetter.apply(tree),
+ diags.fragment("cant.resolve.modules"));
}
- enter.complete(List.of(tree), c);
+ enter.complete(List.of(tree), expectedSymbol);
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.finished(e);
}
- if (enter.getEnv(c) == null) {
+ ClassSymbol sym = symbolGetter.apply(tree);
+ if (sym == null || enter.getEnv(sym) == null) {
boolean isPkgInfo =
tree.sourcefile.isNameCompatible("package-info",
JavaFileObject.Kind.SOURCE);
@@ -836,24 +862,26 @@
if (enter.getEnv(tree.modle) == null) {
JCDiagnostic diag =
diagFactory.fragment("file.does.not.contain.module");
- throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+ throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
}
} else if (isPkgInfo) {
if (enter.getEnv(tree.packge) == null) {
JCDiagnostic diag =
diagFactory.fragment("file.does.not.contain.package",
- c.location());
- throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+ sym.location());
+ throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
}
} else {
JCDiagnostic diag =
diagFactory.fragment("file.doesnt.contain.class",
- c.getQualifiedName());
- throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+ sym.getQualifiedName());
+ throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
}
}
implicitSourceFilesRead = true;
+
+ return sym;
}
/** Track when the JavaCompiler has been used to compile something. */
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Wed Oct 05 06:28:23 2016 -0700
@@ -425,8 +425,7 @@
J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, ArgKind.ADJACENT) {
@Override
public boolean process(OptionHelper helper, String option) {
- throw new AssertionError
- ("the -J flag should be caught by the launcher.");
+ throw new AssertionError("the -J flag should be caught by the launcher.");
}
},
@@ -691,7 +690,7 @@
* This option takes an argument.
* If the name of option ends with ':' or '=', the argument must be provided directly
* after that separator.
- * Otherwise, if may appear after an '=' or in the following argument position.
+ * Otherwise, it may appear after an '=' or in the following argument position.
*/
REQUIRED,
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Wed Oct 05 06:28:23 2016 -0700
@@ -1336,8 +1336,7 @@
errorStatus = errorStatus || (compiler.errorCount() > 0);
- if (!errorStatus)
- round.finalCompiler();
+ round.finalCompiler();
if (newSourceFiles.size() > 0)
roots = roots.appendList(compiler.parseFiles(newSourceFiles));
@@ -1350,10 +1349,8 @@
if (!taskListener.isEmpty())
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
- if (errorStatus) {
- if (compiler.errorCount() == 0)
- compiler.log.nerrors++;
- return true;
+ if (errorStatus && compiler.errorCount() == 0) {
+ compiler.log.nerrors++;
}
compiler.enterTreesIfNeeded(roots);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Oct 05 06:28:23 2016 -0700
@@ -2770,6 +2770,10 @@
compiler.err.module.name.mismatch=\
module name {0} does not match expected name {1}
+# 0: name, 1: name
+compiler.misc.module.name.mismatch=\
+ module name {0} does not match expected name {1}
+
compiler.err.module.decl.sb.in.module-info.java=\
module declarations should be in a file named module-info.java
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java Wed Oct 05 06:28:23 2016 -0700
@@ -165,9 +165,11 @@
public int isSupportedOption(String option) {
if (option == null)
throw new NullPointerException();
- for (ToolOption o: ToolOption.values()) {
- if (o.opt.equals(option))
- return o.hasArg ? 1 : 0;
+ for (ToolOption o : ToolOption.values()) {
+ for (String name : o.names) {
+ if (name.equals(option))
+ return o.hasArg ? 1 : 0;
+ }
}
return -1;
}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java Wed Oct 05 06:28:23 2016 -0700
@@ -595,8 +595,9 @@
@Override
public Set<Doclet.Option> getSupportedOptions() {
+ Resources resources = getResources();
Doclet.Option[] options = {
- new Option(this, "-bottom", 1) {
+ new Option(resources, "-bottom", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -604,7 +605,7 @@
return true;
}
},
- new Option(this, "-charset", 1) {
+ new Option(resources, "-charset", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -612,7 +613,7 @@
return true;
}
},
- new Option(this, "-doctitle", 1) {
+ new Option(resources, "-doctitle", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -620,7 +621,7 @@
return true;
}
},
- new Option(this, "-footer", 1) {
+ new Option(resources, "-footer", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -628,7 +629,7 @@
return true;
}
},
- new Option(this, "-header", 1) {
+ new Option(resources, "-header", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -636,7 +637,7 @@
return true;
}
},
- new Option(this, "-helpfile", 1) {
+ new Option(resources, "-helpfile", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -644,7 +645,7 @@
return true;
}
},
- new Option(this, "-html4") {
+ new Option(resources, "-html4") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -652,7 +653,7 @@
return true;
}
},
- new Option(this, "-html5") {
+ new Option(resources, "-html5") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -660,7 +661,7 @@
return true;
}
},
- new Option(this, "-nohelp") {
+ new Option(resources, "-nohelp") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -668,7 +669,7 @@
return true;
}
},
- new Option(this, "-nodeprecatedlist") {
+ new Option(resources, "-nodeprecatedlist") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -676,7 +677,7 @@
return true;
}
},
- new Option(this, "-noindex") {
+ new Option(resources, "-noindex") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -684,7 +685,7 @@
return true;
}
},
- new Option(this, "-nonavbar") {
+ new Option(resources, "-nonavbar") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -692,7 +693,7 @@
return true;
}
},
- new Hidden(this, "-nooverview") {
+ new Hidden(resources, "-nooverview") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -700,7 +701,7 @@
return true;
}
},
- new Option(this, "-notree") {
+ new Option(resources, "-notree") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -708,7 +709,7 @@
return true;
}
},
- new Option(this, "-overview", 1) {
+ new Option(resources, "-overview", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -716,7 +717,7 @@
return true;
}
},
- new Option(this, "--frames") {
+ new Option(resources, "--frames") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -724,7 +725,7 @@
return true;
}
},
- new Option(this, "--no-frames") {
+ new Option(resources, "--no-frames") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -732,7 +733,7 @@
return true;
}
},
- new Hidden(this, "-packagesheader", 1) {
+ new Hidden(resources, "-packagesheader", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -740,7 +741,7 @@
return true;
}
},
- new Option(this, "-splitindex") {
+ new Option(resources, "-splitindex") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -748,7 +749,7 @@
return true;
}
},
- new Option(this, "-stylesheetfile", 1) {
+ new Option(resources, "-stylesheetfile", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -756,7 +757,7 @@
return true;
}
},
- new Option(this, "-top", 1) {
+ new Option(resources, "-top", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -764,7 +765,7 @@
return true;
}
},
- new Option(this, "-use") {
+ new Option(resources, "-use") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -772,7 +773,7 @@
return true;
}
},
- new Option(this, "-windowtitle", 1) {
+ new Option(resources, "-windowtitle", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -780,7 +781,7 @@
return true;
}
},
- new XOption(this, "-Xdoclint") {
+ new XOption(resources, "-Xdoclint") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -788,7 +789,7 @@
return true;
}
},
- new XOption(this, "-Xdocrootparent", 1) {
+ new XOption(resources, "-Xdocrootparent", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -796,7 +797,7 @@
return true;
}
},
- new XOption(this, "doclet.xusage.xdoclint-extended.", "-Xdoclint:", 0) {
+ new XOption(resources, "doclet.usage.xdoclint-extended", "-Xdoclint:", 0) {
@Override
public boolean matches(String option) {
return option.toLowerCase().startsWith(getName().toLowerCase());
@@ -809,7 +810,7 @@
return true;
}
},
- new XOption(this, "doclet.xusage.xdoclint-package.", "-Xdoclint/package:", 0) {
+ new XOption(resources, "doclet.usage.xdoclint-package", "-Xdoclint/package:", 0) {
@Override
public boolean matches(String option) {
return option.toLowerCase().startsWith(getName().toLowerCase());
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Wed Oct 05 06:28:23 2016 -0700
@@ -191,144 +191,196 @@
doclet.Same_package_name_used=Package name format used twice: {0}
# option specifiers
-doclet.usage.d.parameters=<directory>
-doclet.usage.d.description=Destination directory for output files
+doclet.usage.d.parameters=\
+ <directory>
+doclet.usage.d.description=\
+ Destination directory for output files
-doclet.usage.use.description=Create class and package usage pages
-
-doclet.usage.version.description=Include @version paragraphs
+doclet.usage.use.description=\
+ Create class and package usage pages
-doclet.usage.author.description=Include @author paragraphs
+doclet.usage.version.description=\
+ Include @version paragraphs
-doclet.usage.docfilessubdirs.description=Recursively copy doc-file subdirectories
+doclet.usage.author.description=\
+ Include @author paragraphs
-doclet.usage.splitindex.description=Split index into one file per letter
+doclet.usage.docfilessubdirs.description=\
+ Recursively copy doc-file subdirectories
-doclet.usage.overview.parameters=<file>
-doclet.usage.overview.description=Read overview documentation from HTML file
+doclet.usage.splitindex.description=\
+ Split index into one file per letter
+doclet.usage.overview.parameters=\
+ <file>
+doclet.usage.overview.description=\
+ Read overview documentation from HTML file
-doclet.usage.windowtitle.parameters=<text>
-doclet.usage.windowtitle.description=Browser window title for the documentation
-
-doclet.usage.doctitle.parameters=<html-code>
-doclet.usage.doctitle.description=Include title for the overview page
+doclet.usage.windowtitle.parameters=\
+ <text>
+doclet.usage.windowtitle.description=\
+ Browser window title for the documentation
-doclet.usage.header.parameters=<html-code>
-doclet.usage.header.description=Include header text for each page
-
-doclet.usage.html4.description=Generate HTML 4.01 output
+doclet.usage.doctitle.parameters=\
+ <html-code>
+doclet.usage.doctitle.description=\
+ Include title for the overview page
-doclet.usage.html5.description=Generate HTML 5 output
+doclet.usage.header.parameters=\
+ <html-code>
+doclet.usage.header.description=\
+ Include header text for each page
-doclet.usage.footer.parameters=<html-code>
-doclet.usage.footer.description=Include footer text for each page
+doclet.usage.html4.description=\
+ Generate HTML 4.01 output
+
+doclet.usage.html5.description=\
+ Generate HTML 5 output
-doclet.usage.top.parameters=<html-code>
-doclet.usage.top.description=Include top text for each page
+doclet.usage.footer.parameters=\
+ <html-code>
+doclet.usage.footer.description=\
+ Include footer text for each page
-doclet.usage.bottom.parameters=<html-code>
-doclet.usage.bottom.description=Include bottom text for each page
-
-doclet.usage.link.parameters=<url>
-doclet.usage.link.description=Create links to javadoc output at <url>
+doclet.usage.top.parameters=\
+ <html-code>
+doclet.usage.top.description=\
+ Include top text for each page
-doclet.usage.linkoffline.parameters=<url1> <url2>
-doclet.usage.linkoffline.description=Link to docs at <url1> using package list\n\
-\ at <url2>
+doclet.usage.bottom.parameters=\
+ <html-code>
+doclet.usage.bottom.description=\
+ Include bottom text for each page
-doclet.usage.excludedocfilessubdir.parameters=<name>:..
-doclet.usage.excludedocfilessubdir.description=\n\
-\ Exclude any doc-files subdirectories with\n\
-\ given name
+doclet.usage.link.parameters=\
+ <url>
+doclet.usage.link.description=\
+ Create links to javadoc output at <url>
-doclet.usage.group.parameters=<name> <p1>:<p2>..
-doclet.usage.group.description=Group specified packages together\n\
-\ in overview page
+doclet.usage.linkoffline.parameters=\
+ <url1> <url2>
+doclet.usage.linkoffline.description=\
+ Link to docs at <url1> using package list at <url2>
-doclet.usage.nocomment.description=Suppress description and tags, generate\n\
-\ only declarations
-
-doclet.usage.nodeprecated.description=Do not include @deprecated information
+doclet.usage.excludedocfilessubdir.parameters=\
+ <name>:..
+doclet.usage.excludedocfilessubdir.description=\
+ Exclude any doc-files subdirectories with given name
-doclet.usage.noqualifier.parameters=<name1>:<name2>:..
-doclet.usage.noqualifier.description=Exclude the list of qualifiers from the output
+doclet.usage.group.parameters=\
+ <name> <p1>:<p2>..
+doclet.usage.group.description=\
+ Group specified packages together in overview page
-doclet.usage.nosince.description=Do not include @since information
+doclet.usage.nocomment.description=\
+ Suppress description and tags, generate only declarations
-doclet.usage.notimestamp.description=Do not include hidden time stamp
+doclet.usage.nodeprecated.description=\
+ Do not include @deprecated information
-doclet.usage.nodeprecatedlist.description=Do not generate deprecated list
+doclet.usage.noqualifier.parameters=\
+ <name1>:<name2>:..
+doclet.usage.noqualifier.description=\
+ Exclude the list of qualifiers from the output
-doclet.usage.notree.description=Do not generate class hierarchy
+doclet.usage.nosince.description=\
+ Do not include @since information
-doclet.usage.noindex.description=Do not generate index
+doclet.usage.notimestamp.description=\
+ Do not include hidden time stamp
-doclet.usage.nohelp.description=Do not generate help link
+doclet.usage.nodeprecatedlist.description=\
+ Do not generate deprecated list
-doclet.usage.nonavbar.description=Do not generate navigation bar
+doclet.usage.notree.description=\
+ Do not generate class hierarchy
-doclet.usage.nooverview.description=Do not generate overview pages
+doclet.usage.noindex.description=\
+ Do not generate index
-doclet.usage.serialwarn.description=Generate warning about @serial tag
+doclet.usage.nohelp.description=\
+ Do not generate help link
+
+doclet.usage.nonavbar.description=\
+ Do not generate navigation bar
-doclet.usage.tag.parameters=<name>:<locations>:<header>
-doclet.usage.tag.description=\n\
-\ Specify single argument custom tags
+doclet.usage.nooverview.description=\
+ Do not generate overview pages
-doclet.usage.taglet.description=The fully qualified name of Taglet to register
+doclet.usage.serialwarn.description=\
+ Generate warning about @serial tag
-doclet.usage.tagletpath.description=The path to Taglets
+doclet.usage.tag.parameters=\
+ <name>:<locations>:<header>
+doclet.usage.tag.description=\
+ Specify single argument custom tags
-doclet.usage.charset.parameters=<charset>
-doclet.usage.charset.description=Charset for cross-platform viewing of\n\
-\ generated documentation
+doclet.usage.taglet.description=\
+ The fully qualified name of Taglet to register
-doclet.usage.helpfile.parameters=<file>
-doclet.usage.helpfile.description=Include file that help link links to
+doclet.usage.tagletpath.description=\
+ The path to Taglets
-doclet.usage.linksource.description=Generate source in HTML
+doclet.usage.charset.parameters=\
+ <charset>
+doclet.usage.charset.description=\
+ Charset for cross-platform viewing of generated documentation
-doclet.usage.sourcetab.parameters=<tab length>
-doclet.usage.sourcetab.description=Specify the number of spaces each tab\n\
-\ takes up in the source
+doclet.usage.helpfile.parameters=\
+ <file>
+doclet.usage.helpfile.description=\
+ Include file that help link links to
-doclet.usage.keywords.description=Include HTML meta tags with package,\n\
-\ class and member info
+doclet.usage.linksource.description=\
+ Generate source in HTML
-doclet.usage.stylesheetfile.parameters=<path>
-doclet.usage.stylesheetfile.description=File to change style of the generated\n\
-\ documentation
+doclet.usage.sourcetab.parameters=\
+ <tab length>
+doclet.usage.sourcetab.description=\
+ Specify the number of spaces each tab takes up in the source
-doclet.usage.docencoding.parameters=<name>
-doclet.usage.docencoding.description=Specify the character encoding for the output
-
-doclet.usage.frames.description=Enable the use of frames in the generated output (default)
+doclet.usage.keywords.description=\
+ Include HTML meta tags with package, class and member info
-doclet.usage.no-frames.description=Disable the use of frames in the generated output
+doclet.usage.stylesheetfile.parameters=\
+ <path>
+doclet.usage.stylesheetfile.description=\
+ File to change style of the generated documentation
-doclet.xusage.xdocrootparent.parameters=<url>
-doclet.xusage.xdocrootparent.description=Replaces all @docRoot followed by /..\n\
-\ in doc comments with <url>
+doclet.usage.docencoding.parameters=\
+ <name>
+doclet.usage.docencoding.description=\
+ Specify the character encoding for the output
-doclet.xusage.xdoclint.description=Enable recommended checks for problems in\n\
-\ javadoc comments
+doclet.usage.frames.description=\
+ Enable the use of frames in the generated output (default)
+
+doclet.usage.no-frames.description=\
+ Disable the use of frames in the generated output
-doclet.xusage.xdoclint-extended.parameters=(all|none|[-]<group>)
-# L10N: do not localize these words: all none accessibility html missing reference syntax
-doclet.xusage.xdoclint-extended.description=Enable or disable specific checks\n\
-\ for problems in javadoc comments, where \n\
-\ <group> is one of accessibility, html,\n\
-\ missing, reference, or syntax.\n
+doclet.usage.xdocrootparent.parameters=\
+ <url>
+doclet.usage.xdocrootparent.description=\
+ Replaces all @docRoot followed by /.. in doc comments with\n\
+ <url>
+
+doclet.usage.xdoclint.description=\
+ Enable recommended checks for problems in javadoc comments
-doclet.xusage.xdoclint-package.parameters=([-]<packages>)
-doclet.xusage.xdoclint-package.description=\n\
-\ Enable or disable checks in specific\n\
-\ packages. <packages> is a comma separated\n\
-\ list of package specifiers. Package\n\
-\ specifier is either a qualified name of a\n\
-\ package or a package name prefix followed\n\
-\ by .*, which expands to all sub-packages\n\
-\ of the given package. Prefix the package\n\
-\ specifier with - to disable checks for\n\
-\ the specified packages.\n
+doclet.usage.xdoclint-extended.parameters=\
+ (all|none|[-]<group>)
+# L10N: do not localize these words: all none accessibility html missing reference syntax
+doclet.usage.xdoclint-extended.description=\
+ Enable or disable specific checks for problems in javadoc\n\
+ comments, where <group> is one of accessibility, html,\n\
+ missing, reference, or syntax.
+
+doclet.usage.xdoclint-package.parameters=\
+ ([-]<packages>)
+doclet.usage.xdoclint-package.description=\
+ Enable or disable checks in specific packages. <packages> is a\n\
+ comma separated list of package specifiers. A package\n\
+ specifier is either a qualified name of a package or a package\n\
+ name prefix followed by .*, which expands to all sub-packages\n\
+ of the given package. Prefix the package specifier with - to\n\
+ disable checks for the specified packages.
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java Wed Oct 05 06:28:23 2016 -0700
@@ -404,8 +404,9 @@
}
public Set<Doclet.Option> getSupportedOptions() {
+ Resources resources = getResources();
Doclet.Option[] options = {
- new Option(this, "-author") {
+ new Option(resources, "-author") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -413,7 +414,7 @@
return true;
}
},
- new Option(this, "-d", 1) {
+ new Option(resources, "-d", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -421,7 +422,7 @@
return true;
}
},
- new Option(this, "-docencoding", 1) {
+ new Option(resources, "-docencoding", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -429,7 +430,7 @@
return true;
}
},
- new Option(this, "-docfilessubdirs") {
+ new Option(resources, "-docfilessubdirs") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -437,7 +438,7 @@
return true;
}
},
- new Hidden(this, "-encoding", 1) {
+ new Hidden(resources, "-encoding", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -445,7 +446,7 @@
return true;
}
},
- new Option(this, "-excludedocfilessubdir", 1) {
+ new Option(resources, "-excludedocfilessubdir", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -453,7 +454,7 @@
return true;
}
},
- new Option(this, "-group", 2) {
+ new Option(resources, "-group", 2) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -461,7 +462,7 @@
return true;
}
},
- new Hidden(this, "-javafx") {
+ new Hidden(resources, "-javafx") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -469,7 +470,7 @@
return true;
}
},
- new Option(this, "-keywords") {
+ new Option(resources, "-keywords") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -477,7 +478,7 @@
return true;
}
},
- new Option(this, "-link", 1) {
+ new Option(resources, "-link", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -486,7 +487,7 @@
return true;
}
},
- new Option(this, "-linksource") {
+ new Option(resources, "-linksource") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -494,7 +495,7 @@
return true;
}
},
- new Option(this, "-linkoffline", 2) {
+ new Option(resources, "-linkoffline", 2) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -503,7 +504,7 @@
return true;
}
},
- new Option(this, "-nocomment") {
+ new Option(resources, "-nocomment") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -511,7 +512,7 @@
return true;
}
},
- new Option(this, "-nodeprecated") {
+ new Option(resources, "-nodeprecated") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -519,7 +520,7 @@
return true;
}
},
- new Option(this, "-nosince") {
+ new Option(resources, "-nosince") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -527,7 +528,7 @@
return true;
}
},
- new Option(this, "-notimestamp") {
+ new Option(resources, "-notimestamp") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -535,7 +536,7 @@
return true;
}
},
- new Option(this, "-noqualifier", 1) {
+ new Option(resources, "-noqualifier", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -543,7 +544,7 @@
return true;
}
},
- new Hidden(this, "-quiet") {
+ new Hidden(resources, "-quiet") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -551,7 +552,7 @@
return true;
}
},
- new Option(this, "-serialwarn") {
+ new Option(resources, "-serialwarn") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -559,7 +560,7 @@
return true;
}
},
- new Option(this, "-sourcetab", 1) {
+ new Option(resources, "-sourcetab", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -578,7 +579,7 @@
return true;
}
},
- new Option(this, "-tag", 1) {
+ new Option(resources, "-tag", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -589,7 +590,7 @@
return true;
}
},
- new Option(this, "-taglet", 1) {
+ new Option(resources, "-taglet", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -600,7 +601,7 @@
return true;
}
},
- new Option(this, "-tagletpath", 1) {
+ new Option(resources, "-tagletpath", 1) {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -608,7 +609,7 @@
return true;
}
},
- new Option(this, "-version") {
+ new Option(resources, "-version") {
@Override
public boolean process(String opt, ListIterator<String> args) {
optionsProcessed.add(this);
@@ -1057,37 +1058,30 @@
private final String description;
private final int argCount;
- protected final Configuration c;
+ protected Option(Resources resources, String name, int argCount) {
+ this(resources, "doclet.usage." + name.toLowerCase().replaceAll("^-*", ""), name, argCount);
+ }
- protected Option(Configuration config, String keyName, String name, int argCount) {
- c = config;
+ protected Option(Resources resources, String keyBase, String name, int argCount) {
this.name = name;
- String desc = getOptionsMessage(keyName + "description");
+ String desc = getOptionsMessage(resources, keyBase + ".description");
if (desc.isEmpty()) {
this.description = "<MISSING KEY>";
this.parameters = "<MISSING KEY>";
} else {
this.description = desc;
- this.parameters = getOptionsMessage(keyName + "parameters");
+ this.parameters = getOptionsMessage(resources, keyBase + ".parameters");
}
this.argCount = argCount;
}
- protected Option(String prefix, Configuration config, String name, int argCount) {
- this(config, prefix + name.toLowerCase().replaceAll("^-*", "") + ".", name, argCount);
- }
-
- protected Option(Configuration config, String name, int argCount) {
- this("doclet.usage.", config, name, argCount);
+ protected Option(Resources resources, String name) {
+ this(resources, name, 0);
}
- protected Option(Configuration config, String name) {
- this(config, name, 0);
- }
-
- private String getOptionsMessage(String key) {
+ private String getOptionsMessage(Resources resources, String key) {
try {
- return c.getResources().getText(key);
+ return resources.getText(key);
} catch (MissingResourceException ignore) {
return "";
}
@@ -1113,19 +1107,9 @@
return parameters;
}
- /**
- * Maintains the formatting for javadoc -help. Note the space
- * alignment.
- */
@Override
public String toString() {
- String opt = name + (name.endsWith(":") ? "" : " ") + parameters;
- StringBuffer sb = new StringBuffer(" ").append(opt).append(" ");
- for (int i = opt.length(); i < 32; i++) {
- sb.append(" ");
- }
- sb.append(description);
- return sb.toString();
+ return name;
}
@Override
@@ -1135,7 +1119,14 @@
@Override
public boolean matches(String option) {
- return name.toLowerCase().equals(option.toLowerCase());
+ boolean matchCase = name.startsWith("--");
+ if (option.startsWith("--") && option.contains("=")) {
+ return name.equals(option.substring(option.indexOf("=") + 1));
+ } else if (matchCase) {
+ return name.equals(option);
+ } else {
+ return name.toLowerCase().equals(option.toLowerCase());
+ }
}
@Override
@@ -1146,16 +1137,16 @@
public abstract class XOption extends Option {
- public XOption(Configuration config, String keyname, String name, int argCount) {
- super(config, keyname, name, argCount);
+ public XOption(Resources resources, String prefix, String name, int argCount) {
+ super(resources, prefix, name, argCount);
}
- public XOption(Configuration config, String name, int argCount) {
- super("doclet.xusage.", config, name, argCount);
+ public XOption(Resources resources, String name, int argCount) {
+ super(resources, name, argCount);
}
- public XOption(Configuration config, String name) {
- this(config, name, 0);
+ public XOption(Resources resources, String name) {
+ this(resources, name, 0);
}
@Override
@@ -1166,12 +1157,12 @@
public abstract class Hidden extends Option {
- public Hidden(Configuration config, String name, int argCount) {
- super("doclet.xusage.", config, name, argCount);
+ public Hidden(Resources resources, String name, int argCount) {
+ super(resources, name, argCount);
}
- public Hidden(Configuration config, String name) {
- this(config, name, 0);
+ public Hidden(Resources resources, String name) {
+ this(resources, name, 0);
}
@Override
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java Wed Oct 05 06:28:23 2016 -0700
@@ -255,7 +255,7 @@
private void incrementErrorCount(String prefix, String msg) {
if (nerrors < MaxErrors) {
PrintWriter errWriter = getWriter(WriterKind.ERROR);
- errWriter.println(prefix + ": " + getText("javadoc.error") + " - " + msg);
+ printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg);
errWriter.flush();
prompt();
nerrors++;
@@ -293,7 +293,7 @@
private void incrementWarningCount(String prefix, String msg) {
if (nwarnings < MaxWarnings) {
PrintWriter warnWriter = getWriter(WriterKind.WARNING);
- warnWriter.println(prefix + ": " + getText("javadoc.warning") + " - " + msg);
+ printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg);
warnWriter.flush();
nwarnings++;
}
@@ -318,9 +318,9 @@
PrintWriter noticeWriter = getWriter(WriterKind.NOTICE);
if (path == null) {
- noticeWriter.println(msg);
+ printRawLines(noticeWriter, msg);
} else {
- noticeWriter.println(prefix + ": " + msg);
+ printRawLines(noticeWriter, prefix + ": " + msg);
}
noticeWriter.flush();
}
@@ -334,9 +334,9 @@
PrintWriter noticeWriter = getWriter(WriterKind.NOTICE);
if (e == null) {
- noticeWriter.println(msg);
+ printRawLines(noticeWriter, msg);
} else {
- noticeWriter.println(pos + ": " + msg);
+ printRawLines(noticeWriter, pos + ": " + msg);
}
noticeWriter.flush();
}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Wed Oct 05 06:28:23 2016 -0700
@@ -31,14 +31,18 @@
import java.io.PrintWriter;
import java.nio.file.Path;
import java.text.BreakIterator;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
@@ -61,6 +65,7 @@
import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.Doclet.Option;
import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.internal.doclets.toolkit.Resources;
import static javax.tools.DocumentationTool.Location.*;
@@ -168,7 +173,10 @@
}
void usage(boolean exit) {
- usage("main.usage", "-help", "main.usage.foot", exit);
+ usage("main.usage", "-help", "main.usage.foot");
+
+ if (exit)
+ throw new Messager.ExitJavadoc();
}
@Override
@@ -177,30 +185,128 @@
}
void Xusage(boolean exit) {
- usage("main.Xusage", "-X", "main.Xusage.foot", exit);
- }
-
- private void usage(String main, String option, String foot, boolean exit) {
- messager.notice(main);
- // let doclet print usage information (does nothing on error)
- if (docletClass != null) {
- String name = doclet.getName();
- Set<Option> supportedOptions = doclet.getSupportedOptions();
- messager.notice("main.doclet.usage.header", name);
- Option.Kind myKind = option.equals("-X")
- ? Option.Kind.EXTENDED
- : Option.Kind.STANDARD;
- supportedOptions.stream()
- .filter(opt -> opt.getKind() == myKind)
- .forEach(opt -> messager.printNotice(opt.toString()));
- }
- if (foot != null)
- messager.notice(foot);
+ usage("main.Xusage", "-X", "main.Xusage.foot");
if (exit)
throw new Messager.ExitJavadoc();
}
+ private void usage(String header, String option, String footer) {
+ messager.notice(header);
+ showToolOptions(option.equals("-X") ? OptionKind.EXTENDED : OptionKind.STANDARD);
+
+ // let doclet print usage information
+ if (docletClass != null) {
+ String name = doclet.getName();
+ messager.notice("main.doclet.usage.header", name);
+ showDocletOptions(option.equals("-X") ? Option.Kind.EXTENDED : Option.Kind.STANDARD);
+ }
+
+ if (footer != null)
+ messager.notice(footer);
+ }
+
+ void showToolOptions(OptionKind kind) {
+ Comparator<ToolOption> comp = new Comparator<ToolOption>() {
+ final Collator collator = Collator.getInstance(Locale.US);
+ { collator.setStrength(Collator.PRIMARY); }
+
+ @Override
+ public int compare(ToolOption o1, ToolOption o2) {
+ return collator.compare(o1.primaryName, o2.primaryName);
+ }
+ };
+
+ Stream.of(ToolOption.values())
+ .filter(opt -> opt.kind == kind)
+ .sorted(comp)
+ .forEach(opt -> showToolOption(opt));
+ }
+
+ void showToolOption(ToolOption option) {
+ List<String> names = option.getNames();
+ String parameters;
+ if (option.hasArg || option.primaryName.endsWith(":")) {
+ String sep = (option == ToolOption.J) || option.primaryName.endsWith(":") ? "" : " ";
+ parameters = sep + option.getParameters(messager);
+ } else {
+ parameters = "";
+ }
+ String description = option.getDescription(messager);
+ showUsage(names, parameters, description);
+ }
+
+ void showDocletOptions(Option.Kind kind) {
+ Comparator<Doclet.Option> comp = new Comparator<Doclet.Option>() {
+ final Collator collator = Collator.getInstance(Locale.US);
+ { collator.setStrength(Collator.PRIMARY); }
+
+ @Override
+ public int compare(Doclet.Option o1, Doclet.Option o2) {
+ return collator.compare(o1.getName(), o2.getName());
+ }
+ };
+
+ doclet.getSupportedOptions().stream()
+ .filter(opt -> opt.getKind() == kind)
+ .sorted(comp)
+ .forEach(opt -> showDocletOption(opt));
+ }
+
+ void showDocletOption(Doclet.Option option) {
+ List<String> names = Arrays.asList(option.getName());
+ String parameters;
+ if (option.getArgumentCount() > 0 || option.getName().endsWith(":")) {
+ String sep = option.getName().endsWith(":") ? "" : " ";
+ parameters = sep + option.getParameters();
+ } else {
+ parameters = "";
+ }
+ String description = option.getDescription();
+ showUsage(names, parameters, description);
+ }
+
+ // The following constants are intended to format the output to
+ // be similar to that of the java launcher: i.e. "java -help".
+
+ /** The indent for the option synopsis. */
+ private static final String SMALL_INDENT = " ";
+ /** The automatic indent for the description. */
+ private static final String LARGE_INDENT = " ";
+ /** The space allowed for the synopsis, if the description is to be shown on the same line. */
+ private static final int DEFAULT_SYNOPSIS_WIDTH = 13;
+ /** The nominal maximum line length, when seeing if text will fit on a line. */
+ private static final int DEFAULT_MAX_LINE_LENGTH = 80;
+ /** The format for a single-line help entry. */
+ private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s";
+
+ void showUsage(List<String> names, String parameters, String description) {
+ String synopses = names.stream()
+ .map(s -> s + parameters)
+ .collect(Collectors.joining(", "));
+ // If option synopses and description fit on a single line of reasonable length,
+ // display using COMPACT_FORMAT
+ if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH
+ && !description.contains("\n")
+ && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + description.length() <= DEFAULT_MAX_LINE_LENGTH)) {
+ messager.printNotice(String.format(COMPACT_FORMAT, synopses, description));
+ return;
+ }
+
+ // If option synopses fit on a single line of reasonable length, show that;
+ // otherwise, show 1 per line
+ if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) {
+ messager.printNotice(SMALL_INDENT + synopses);
+ } else {
+ for (String name: names) {
+ messager.printNotice(SMALL_INDENT + name + parameters);
+ }
+ }
+
+ // Finally, show the description
+ messager.printNotice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT));
+ }
+
/**
* Main program - external wrapper. In order to maintain backward
@@ -433,14 +539,37 @@
docletOptions = doclet.getSupportedOptions();
}
String arg = args.get(idx);
+ String argBase, argVal;
+ if (arg.startsWith("--") && arg.contains("=")) {
+ int sep = arg.indexOf("=");
+ argBase = arg.substring(0, sep);
+ argVal = arg.substring(sep + 1);
+ } else {
+ argBase = arg;
+ argVal = null;
+ }
for (Doclet.Option opt : docletOptions) {
- if (opt.matches(arg)) {
- if (args.size() - idx < opt.getArgumentCount()) {
- usageError("main.requires_argument", arg);
+ if (opt.matches(argBase)) {
+ if (argVal != null) {
+ switch (opt.getArgumentCount()) {
+ case 0:
+ usageError("main.unnecessary_arg_provided", argBase);
+ break;
+ case 1:
+ opt.process(arg, Arrays.asList(argVal).listIterator());
+ break;
+ default:
+ usageError("main.only_one_argument_with_equals", argBase);
+ break;
+ }
+ } else {
+ if (args.size() - idx -1 < opt.getArgumentCount()) {
+ usageError("main.requires_argument", arg);
+ }
+ opt.process(arg, args.listIterator(idx + 1));
+ idx += opt.getArgumentCount();
}
- opt.process(arg, args.listIterator(idx + 1));
- idx += opt.getArgumentCount();
return idx;
}
}
@@ -463,11 +592,11 @@
// Step 1: loop through the args, set locale early on, if found.
for (int i = 0 ; i < argv.size() ; i++) {
String arg = argv.get(i);
- if (arg.equals(ToolOption.LOCALE.opt)) {
+ if (arg.equals(ToolOption.LOCALE.primaryName)) {
checkOneArg(argv, i++);
String lname = argv.get(i);
locale = getLocale(lname);
- } else if (arg.equals(ToolOption.DOCLET.opt)) {
+ } else if (arg.equals(ToolOption.DOCLET.primaryName)) {
checkOneArg(argv, i++);
if (userDocletName != null) {
usageError("main.more_than_one_doclet_specified_0_and_1",
@@ -478,7 +607,7 @@
docletName, argv.get(i));
}
userDocletName = argv.get(i);
- } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
+ } else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) {
checkOneArg(argv, i++);
if (userDocletPath == null) {
userDocletPath = argv.get(i);
@@ -599,8 +728,12 @@
handleDocletOptions(i, args, true);
if (o.hasArg) {
- checkOneArg(args, i++);
- o.process(this, args.get(i));
+ if (arg.startsWith("--") && arg.contains("=")) {
+ o.process(this, arg.substring(arg.indexOf('=') + 1));
+ } else {
+ checkOneArg(args, i++);
+ o.process(this, args.get(i));
+ }
} else if (o.hasSuffix) {
o.process(this, arg);
} else {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java Wed Oct 05 06:28:23 2016 -0700
@@ -35,9 +35,12 @@
import javax.lang.model.element.ElementKind;
import com.sun.tools.javac.main.Option;
+import com.sun.tools.javac.main.Option.OptionKind;
import com.sun.tools.javac.main.OptionHelper;
import com.sun.tools.javac.util.Options;
+import static com.sun.tools.javac.main.Option.OptionKind.*;
+
/**
* javadoc tool options.
*
@@ -50,197 +53,169 @@
// ----- options for underlying compiler -----
- BOOTCLASSPATH("-bootclasspath", true) {
+ BOOTCLASSPATH("-bootclasspath", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.BOOT_CLASS_PATH, arg);
}
},
- CLASSPATH("-classpath", true) {
+ CLASS_PATH("--class-path -classpath -cp", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.CLASS_PATH, arg);
}
},
- CP("-cp", true) {
- @Override
- public void process(Helper helper, String arg) {
- helper.setFileManagerOpt(Option.CLASS_PATH, arg);
- }
- },
-
- CLASS_PATH("--class-path", true) {
- @Override
- public void process(Helper helper, String arg) {
- helper.setFileManagerOpt(Option.CLASS_PATH, arg);
- }
- },
-
- EXTDIRS("-extdirs", true) {
+ EXTDIRS("-extdirs", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.EXTDIRS, arg);
}
},
- SOURCEPATH("-sourcepath", true) {
+ SOURCE_PATH("--source-path -sourcepath", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.SOURCE_PATH, arg);
}
},
- SOURCE_PATH("--source-path", true) {
- @Override
- public void process(Helper helper, String arg) {
- helper.setFileManagerOpt(Option.SOURCE_PATH, arg);
- }
- },
-
- SYSCLASSPATH("-sysclasspath", true) {
+ SYSCLASSPATH("-sysclasspath", HIDDEN, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.BOOT_CLASS_PATH, arg);
}
},
- MODULE_SOURCE_PATH("--module-source-path", true) {
+ MODULE_SOURCE_PATH("--module-source-path", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.MODULE_SOURCE_PATH, arg);
}
},
- UPGRADE_MODULE_PATH("--upgrade-module-path", true) {
+ UPGRADE_MODULE_PATH("--upgrade-module-path", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.UPGRADE_MODULE_PATH, arg);
}
},
- SYSTEM("--system", true) {
+ SYSTEM("--system", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.SYSTEM, arg);
}
},
- MODULE_PATH("--module-path", true) {
- @Override
- public void process(Helper helper, String arg) {
- helper.setFileManagerOpt(Option.MODULE_PATH, arg);
- }
- },
-
- P("-p", true) {
+ MODULE_PATH("--module-path -p", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.MODULE_PATH, arg);
}
},
- ADD_MODULES("--add-modules", true) {
+ ADD_MODULES("--add-modules", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- Option.ADD_MODULES.process(helper.getOptionHelper(), opt, arg);
+ Option.ADD_MODULES.process(helper.getOptionHelper(), primaryName, arg);
}
},
- LIMIT_MODULES("--limit-modules", true) {
+ LIMIT_MODULES("--limit-modules", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- Option.LIMIT_MODULES.process(helper.getOptionHelper(), opt, arg);
+ Option.LIMIT_MODULES.process(helper.getOptionHelper(), primaryName, arg);
}
},
- MODULE("--module", true) {
+ MODULE("--module", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.addToList(this, ",", arg);
}
},
- ENCODING("-encoding", true) {
+ ENCODING("-encoding", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFileManagerOpt(Option.ENCODING, arg);
}
},
- RELEASE("--release", true) {
+ RELEASE("--release", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- Option.RELEASE.process(helper.getOptionHelper(), opt, arg);
+ Option.RELEASE.process(helper.getOptionHelper(), primaryName, arg);
}
},
- SOURCE("-source", true) {
+ SOURCE("-source", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- Option.SOURCE.process(helper.getOptionHelper(), opt, arg);
+ Option.SOURCE.process(helper.getOptionHelper(), primaryName, arg);
}
},
- XMAXERRS("-Xmaxerrs", true) {
+ XMAXERRS("-Xmaxerrs", EXTENDED, true) {
@Override
public void process(Helper helper, String arg) {
- Option.XMAXERRS.process(helper.getOptionHelper(), opt, arg);
+ Option.XMAXERRS.process(helper.getOptionHelper(), primaryName, arg);
}
},
- XMAXWARNS("-Xmaxwarns", true) {
+ XMAXWARNS("-Xmaxwarns", EXTENDED, true) {
@Override
public void process(Helper helper, String arg) {
- Option.XMAXWARNS.process(helper.getOptionHelper(), opt, arg);
+ Option.XMAXWARNS.process(helper.getOptionHelper(), primaryName, arg);
}
},
- ADD_READS("--add-reads", true) {
+ ADD_READS("--add-reads", EXTENDED, true) {
@Override
public void process(Helper helper, String arg) {
- Option.ADD_READS.process(helper.getOptionHelper(), opt, arg);
+ Option.ADD_READS.process(helper.getOptionHelper(), primaryName, arg);
}
},
- ADD_EXPORTS("--add-exports", true) {
+ ADD_EXPORTS("--add-exports", EXTENDED, true) {
@Override
public void process(Helper helper, String arg) {
- Option.ADD_EXPORTS.process(helper.getOptionHelper(), opt, arg);
+ Option.ADD_EXPORTS.process(helper.getOptionHelper(), primaryName, arg);
}
},
- XMODULE("-Xmodule:", false) {
+ XMODULE("-Xmodule:", EXTENDED, false) {
@Override
public void process(Helper helper, String arg) {
Option.XMODULE.process(helper.getOptionHelper(), arg);
}
},
- PATCH_MODULE("--patch-module", true) {
+ PATCH_MODULE("--patch-module", EXTENDED, true) {
@Override
public void process(Helper helper, String arg) {
- Option.PATCH_MODULE.process(helper.getOptionHelper(), opt, arg);
+ Option.PATCH_MODULE.process(helper.getOptionHelper(), primaryName, arg);
}
},
// ----- doclet options -----
- DOCLET("-doclet", true), // handled in setDocletInvoker
+ DOCLET("-doclet", STANDARD, true), // handled in setDocletInvoker
- DOCLETPATH("-docletpath", true), // handled in setDocletInvoker
+ DOCLETPATH("-docletpath", STANDARD, true), // handled in setDocletInvoker
// ----- selection options -----
- SUBPACKAGES("-subpackages", true) {
+ SUBPACKAGES("-subpackages", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.addToList(this, ":", arg);
}
},
- EXCLUDE("-exclude", true) {
+ EXCLUDE("-exclude", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.addToList(this, ":", arg);
@@ -249,72 +224,72 @@
// ----- filtering options -----
- PACKAGE("-package") {
+ PACKAGE("-package", STANDARD) {
@Override
public void process(Helper helper) {
helper.setSimpleFilter("package");
}
},
- PRIVATE("-private") {
+ PRIVATE("-private", STANDARD) {
@Override
public void process(Helper helper) {
helper.setSimpleFilter("private");
}
},
- PROTECTED("-protected") {
+ PROTECTED("-protected", STANDARD) {
@Override
public void process(Helper helper) {
helper.setSimpleFilter("protected");
}
},
- PUBLIC("-public") {
+ PUBLIC("-public", STANDARD) {
@Override
public void process(Helper helper) {
helper.setSimpleFilter("public");
}
},
- SHOW_MEMBERS("--show-members:") {
+ SHOW_MEMBERS("--show-members", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFilter(this, arg);
}
},
- SHOW_TYPES("--show-types:") {
+ SHOW_TYPES("--show-types", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.setFilter(this, arg);
}
},
- SHOW_PACKAGES("--show-packages:") {
+ SHOW_PACKAGES("--show-packages", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- helper.setShowPackageAccess(SHOW_PACKAGES, helper.getOptionArgumentValue(arg));
+ helper.setShowPackageAccess(SHOW_PACKAGES, arg);
}
},
- SHOW_MODULE_CONTENTS("--show-module-contents:") {
+ SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- helper.setShowModuleContents(SHOW_MODULE_CONTENTS, helper.getOptionArgumentValue(arg));
+ helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
}
},
- EXPAND_REQUIRES("--expand-requires:") {
+ EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
- helper.setExpandRequires(EXPAND_REQUIRES, helper.getOptionArgumentValue(arg));
+ helper.setExpandRequires(EXPAND_REQUIRES, arg);
}
},
// ----- output control options -----
- PROMPT("-prompt") {
+ PROMPT("-prompt", HIDDEN) {
@Override
public void process(Helper helper) {
helper.compOpts.put("-prompt", "-prompt");
@@ -322,21 +297,21 @@
}
},
- QUIET("-quiet") {
+ QUIET("-quiet", STANDARD) {
@Override
public void process(Helper helper) {
helper.jdtoolOpts.put(QUIET, true);
}
},
- VERBOSE("-verbose") {
+ VERBOSE("-verbose", STANDARD) {
@Override
public void process(Helper helper) {
helper.compOpts.put("-verbose", "");
}
},
- XWERROR("-Xwerror") {
+ XWERROR("-Xwerror", HIDDEN) {
@Override
public void process(Helper helper) {
helper.rejectWarnings = true;
@@ -346,21 +321,21 @@
// ----- other options -----
- BREAKITERATOR("-breakiterator") {
+ BREAKITERATOR("-breakiterator", STANDARD) {
@Override
public void process(Helper helper) {
helper.breakiterator = true;
}
},
- LOCALE("-locale", true) {
+ LOCALE("-locale", STANDARD, true) {
@Override
public void process(Helper helper, String arg) {
helper.docLocale = arg;
}
},
- XCLASSES("-Xclasses") {
+ XCLASSES("-Xclasses", HIDDEN) {
@Override
public void process(Helper helper) {
helper.jdtoolOpts.put(XCLASSES, true);
@@ -369,32 +344,54 @@
// ----- help options -----
- HELP("-help") {
+ HELP("--help -help", STANDARD) {
@Override
public void process(Helper helper) {
helper.usage();
}
},
- X("-X") {
+ X("-X", STANDARD) {
@Override
public void process(Helper helper) {
helper.Xusage();
}
+ },
+
+ // This option exists only for the purpose of documenting itself.
+ // It's actually implemented by the launcher.
+ J("-J", STANDARD, true) {
+ @Override
+ public void process(Helper helper) {
+ throw new AssertionError("the -J flag should be caught by the launcher.");
+ }
+ },
+
+ // This option exists only for the purpose of documenting itself.
+ // It's actually implemented ahead of the normal option decoding loop.
+ Xold("-Xold", EXTENDED) {
+ @Override
+ public void process(Helper helper) {
+ throw new AssertionError("the -Xold flag should be handled earlier.");
+ }
};
- public final String opt;
+ public final String primaryName;
+ public final List<String> names;
+ public final OptionKind kind;
public final boolean hasArg;
public final boolean hasSuffix; // ex: foo:bar or -foo=bar
- ToolOption(String opt) {
- this(opt, false);
+ ToolOption(String opt, OptionKind kind) {
+ this(opt, kind, false);
}
- ToolOption(String opt, boolean hasArg) {
- this.opt = opt;
+ ToolOption(String names, OptionKind kind, boolean hasArg) {
+ this.names = Arrays.asList(names.split("\\s+"));
+ this.primaryName = this.names.get(0);
+ this.kind = kind;
this.hasArg = hasArg;
- char lastChar = opt.charAt(opt.length() - 1);
+ char lastChar = names.charAt(names.length() - 1);
this.hasSuffix = lastChar == ':' || lastChar == '=';
}
@@ -402,16 +399,42 @@
void process(Helper helper) { }
+ List<String> getNames() {
+ return names;
+ }
+
+ String getParameters(Messager messager) {
+ return (hasArg || primaryName.endsWith(":"))
+ ? messager.getText(getKey(primaryName, ".arg"))
+ : null;
+ }
+
+ String getDescription(Messager messager) {
+ return messager.getText(getKey(primaryName, ".desc"));
+ }
+
+ private String getKey(String optionName, String suffix) {
+ return "main.opt."
+ + optionName
+ .replaceAll("^-*", "") // remove leading '-'
+ .replaceAll("[^A-Za-z0-9]+$", "") // remove trailing non-alphanumeric
+ .replaceAll("[^A-Za-z0-9]", ".") // replace internal non-alphanumeric
+ + suffix;
+ }
+
+
static ToolOption get(String name) {
String oname = name;
if (name.contains(":")) {
oname = name.substring(0, name.indexOf(':') + 1);
} else if (name.contains("=")) {
- oname = name.substring(0, name.indexOf('=') + 1);
+ oname = name.substring(0, name.indexOf('='));
}
for (ToolOption o : values()) {
- if (oname.equals(o.opt)) {
- return o;
+ for (String n : o.names) {
+ if (oname.equals(n)) {
+ return o;
+ }
}
}
return null;
@@ -457,11 +480,6 @@
jdtoolOpts.put(opt, list);
}
- String getOptionArgumentValue(String in) {
- String[] values = in.trim().split(":");
- return values[1];
- }
-
void setExpandRequires(ToolOption opt, String arg) {
switch (arg) {
case "public":
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties Wed Oct 05 06:28:23 2016 -0700
@@ -28,112 +28,234 @@
main.warnings={0} warnings
main.warning={0} warning
-main.usage=Usage: javadoc [options] [packagenames] [sourcefiles] [@files]\n\
-\ -overview <file> Read overview documentation from HTML file\n\
-\ -public Show only public classes and members\n\
-\ -protected Show protected/public classes and \n\
-\ members (default)\n\
-\ -package Show package/protected/public classes\n\
-\ and members\n\
-\ -private Show all classes and members\n\
-\ --show-members:value Specifies which members (fields, methods\n\
-\ etc.) will be documented, where value can\n\
-\ be one of "public", "protected", "package"\n\
-\ or "private".\n\
-\ Default is protected, will show public and\n\
-\ protected members, "public" will show only\n\
-\ public members, "package" will show public,\n\
-\ protected and package members and \n\
-\ "private" will show all members\n\
-\ --show-types:value Specifies which types (classes, interfaces\n\
-\ etc.) will be documented, where value can be\n\
-\ one of "public", "protected", "package" or\n\
-\ "private".\n\
-\ Default is "protected", show public and\n\
-\ protected types, "package" will show public,\n\
-\ protected and package types and "private"\n\
-\ will show all types\n\
-\ --show-packages:value Specifies which module's packages will be\n\
-\ documented. Possible values are "exported"\n\
-\ or "all" packages\n\
-\ --show-module-contents:value Specifies the documentation granularity of\n\
-\ module declarations.\n\
-\ Possible values are "api" or "all".\n\
-\ --expand-requires:value Instructs the tool to expand the "requires"\n\
-\ module dependencies "public" expands all the\n\
-\ "requires public" edges of the module graph.\n\
-\ "all" expands all the "requires" edges of\n\
-\ the module graph by default only the\n\
-\ specified modules will be considered.\n\
-\ -help Display command line options and exit\n\
-\ --module m1, m2.. Document the specified module(s)\n\
-\ -doclet <class> Generate output via alternate doclet\n\
-\ -docletpath <path> Specify where to find doclet class files\n\
-\ --module-source-path <path> Specify where to find input source files\n\
-\ for multiple modules\n\
-\ --upgrade-module-path <path> Override location of upgradeable modules\n\
-\ --module-path <path>, -p <path> Specify where to find application modules\n\
-\ --add-modules <module>(,<module>)*\n\
-\ Root modules to resolve in addition to the\n\
-\ initial modules,\n\
-\ or all modules on the module path if\n\
-\ <module> is ALL-MODULE-PATH.\n\
-\ --limit-modules <module>(,<module>)*\n\
-\ Limit the universe of observable modules\n\
-\ --source-path <path> Specify where to find source files\n\
-\ -sourcepath <path> Specify where to find source files\n\
-\ --class-path <path> Specify where to find user class files\n\
-\ -classpath <path> Specify where to find user class files\n\
-\ -cp <path> Specify where to find user class files\n\
-\ -exclude <pkglist> Specify a list of packages to exclude\n\
-\ -subpackages <subpkglist> Specify subpackages to recursively load\n\
-\ -breakiterator Compute first sentence with BreakIterator\n\
-\ -bootclasspath <path> Override location of platform class files\n\
-\ used for non-modular releases\n\
-\ --system <jdk> Override location of system modules used\n\
-\ for modular releases.\n\
-\ --release <release> Provide source compatibility with\n\
-\ specified release\n\
-\ -source <release> Provide source compatibility with\n\
-\ specified release\n\
-\ -extdirs <dirlist> Override location of installed extensions\n\
-\ -verbose Output messages about what Javadoc is doing\n\
-\ -locale <name> Locale to be used, e.g. en_US or en_US_WIN\n\
-\ -encoding <name> Source file encoding name\n\
-\ -quiet Do not display status messages\n\
-\ -J<flag> Pass <flag> directly to the runtime system\n\
-\ -X Print a synopsis of nonstandard\n\
-\ options and exit\n
+main.usage=Usage:\n\
+\ javadoc [options] [packagenames] [sourcefiles] [@files]\n\
+where options include:
+
+main.opt.public.desc=\
+ Show only public classes and members
+
+main.opt.protected.desc=\
+ Show protected/public classes and members (default)
+
+main.opt.package.desc=\
+ Show package/protected/public classes and members
+
+main.opt.private.desc=\
+ Show all classes and members
+
+main.opt.show.members.arg=\
+ <value>
+main.opt.show.members.desc=\
+ Specifies which members (fields, methods, etc.) will be\n\
+ documented, where value can be one of "public", "protected",\n\
+ "package" or "private". The default is "protected", which will\n\
+ show public and protected members, "public" will show only\n\
+ public members, "package" will show public, protected and\n\
+ package members and "private" will show all members.
+
+main.opt.show.types.arg=\
+ <value>
+main.opt.show.types.desc=\
+ Specifies which types (classes, interfaces, etc.) will be\n\
+ documented, where value can be one of "public", "protected",\n\
+ "package" or "private". The default is "protected", which will\n\
+ show public and protected types, "public" will show only\n\
+ public types, "package" will show public, protected and\n\
+ package types and "private" will show all types.
+
+main.opt.show.packages.arg=\
+ <value>
+main.opt.show.packages.desc=\
+ Specifies which module's packages will be documented. Possible\n\
+ values are "exported" or "all" packages.
+
+main.opt.show.module.contents.arg=\
+ <value>
+main.opt.show.module.contents.desc=\
+ Specifies the documentation granularity of module\n\
+ declarations. Possible values are "api" or "all".
+
+main.opt.expand.requires.arg=\
+ <value>
+main.opt.expand.requires.desc=\
+ Instructs the tool to expand the set of modules to be\n\
+ documented. By default, only the modules given explicitly on\n\
+ the command line will be documented. A value of "public" will\n\
+ additionally include all "requires public" dependencies of\n\
+ those modules. A value of "all" will include all dependencies\n\
+ of those modules.
+
+main.opt.help.desc=\
+ Display command line options and exit
+
+main.opt.module.arg=\
+ <module>(,<module>)*
+main.opt.module.desc=\
+ Document the specified module(s)
+
+main.opt.doclet.arg=\
+ <class>
+main.opt.doclet.desc=\
+ Generate output via alternate doclet
+
+main.opt.docletpath.arg=\
+ <path>
+main.opt.docletpath.desc=\
+ Specify where to find doclet class files
+
+main.opt.module.source.path.arg=\
+ <path>
+main.opt.module.source.path.desc=\
+ Specify where to find input source files for multiple modules
+
+main.opt.upgrade.module.path.arg=\
+ <path>
+main.opt.upgrade.module.path.desc=\
+ Override location of upgradeable modules
+
+main.opt.module.path.arg=\
+ <path>
+main.opt.module.path.desc=\
+ Specify where to find application modules
+
+main.opt.add.modules.arg=\
+ <module>(,<module>)*
+main.opt.add.modules.desc=\
+ Root modules to resolve in addition to the initial modules,\n\
+ or all modules on the module path if <module> is\n\
+ ALL-MODULE-PATH.
+
+main.opt.limit.modules.arg=\
+ <module>(,<module>)*
+main.opt.limit.modules.desc=\
+ Limit the universe of observable modules
+
+main.opt.source.path.arg=\
+ <path>
+main.opt.source.path.desc=\
+ Specify where to find source files
+
+main.opt.class.path.arg=\
+ <path>
+main.opt.class.path.desc=\
+ Specify where to find user class files
+
+main.opt.exclude.arg=\
+ <pkglist>
+main.opt.exclude.desc=\
+ Specify a list of packages to exclude
+
+main.opt.subpackages.arg=\
+ <subpkglist>
+main.opt.subpackages.desc=\
+ Specify subpackages to recursively load
+
+main.opt.breakiterator.desc=\
+ Compute first sentence with BreakIterator
+
+main.opt.bootclasspath.arg=\
+ <path>
+main.opt.bootclasspath.desc=\
+ Override location of platform class files used for non-modular\n\
+ releases
+
+main.opt.system.arg=\
+ <jdk>
+main.opt.system.desc=\
+ Override location of system modules used for modular releases
+
+main.opt.release.arg=\
+ <release>
+main.opt.release.desc=\
+ Provide source compatibility with specified release
+
+main.opt.source.arg=\
+ <release>
+main.opt.source.desc=\
+ Provide source compatibility with specified release
+
+main.opt.extdirs.arg=\
+ <dirlist>
+main.opt.extdirs.desc=\
+ Override location of installed extensions
+
+main.opt.verbose.desc=\
+ Output messages about what Javadoc is doing
+
+main.opt.locale.arg=\
+ <name>
+main.opt.locale.desc=\
+ Locale to be used, e.g. en_US or en_US_WIN
+
+main.opt.encoding.arg=\
+ <name>
+main.opt.encoding.desc=\
+ Source file encoding name
+
+main.opt.quiet.desc=\
+ Do not display status messages
+
+main.opt.J.arg=\
+ <flag>
+main.opt.J.desc=\
+ Pass <flag> directly to the runtime system
+
+main.opt.X.desc=\
+ Print a synopsis of nonstandard options and exit
main.usage.foot=\n\
GNU-style options may use '=' instead of whitespace to separate the name of an\n\
option from its value.\n
-main.Xusage=\
-\ -Xmaxerrs <number> Set the maximum number of errors to print\n\
-\ -Xmaxwarns <number> Set the maximum number of warnings to print\n\
-\ --add-exports <module>/<package>=<other-module>(,<other-module>)*\n\
-\ Specify a package to be considered as exported\n\
-\ from its defining module to additional modules,\n\
-\ or to all unnamed modules if <other-module> is\n\
-\ ALL-UNNAMED.\n\
-\ --add-reads <module>=<other-module>(,<other-module>)*\n\
-\ Specify additional modules to be considered as\n\
-\ required by a given module. <other-module> may be\n\
-\ ALL-UNNAMED to require the unnamed module.\n\
-\ -Xmodule:<module-name> Specify a module to which the classes being\n\
-\ compiled belong.\n\
-\ --patch-module <module>=<file>(:<file>)*\n\
-\ Override or augment a module with classes\n\
-\ and resources in JAR files or directories\n\
-\ -Xold Invoke the legacy javadoc tool\n
+main.Xusage=
+
+main.opt.Xmaxerrs.arg=\
+ <number>
+main.opt.Xmaxerrs.desc=\
+ Set the maximum number of errors to print
+
+main.opt.Xmaxwarns.arg=\
+ <number>
+main.opt.Xmaxwarns.desc=\
+ Set the maximum number of warnings to print
+
+main.opt.add.exports.arg=\
+ <module>/<package>=<other-module>(,<other-module>)*
+main.opt.add.exports.desc=\
+ Specify a package to be considered as exported from its\n\
+ defining module to additional modules, or to all unnamed\n\
+ modules if <other-module> is ALL-UNNAMED
-main.Xusage.foot=\
+main.opt.add.reads.arg=\
+ <module>=<other-module>(,<other-module>)*
+main.opt.add.reads.desc=\
+ Specify additional modules to be considered as required by a\n\
+ given module. <other-module> may be ALL-UNNAMED to require\n\
+ the unnamed module.
+
+main.opt.Xmodule.arg=\
+ <module-name>
+main.opt.Xmodule.desc=\
+ Specify a module to which the classes being compiled belong
+
+main.opt.patch.module.arg=\
+ <module>=<file>(:<file>)*
+main.opt.patch.module.desc=\
+ Override or augment a module with classes and resources in\n\
+ JAR files or directories
+
+main.opt.Xold.desc=\
+ Invoke the legacy javadoc tool
+
+main.Xusage.foot=\n\
These options are non-standard and subject to change without notice.
-main.doclet.usage.header=Provided by the {0} doclet:
+main.doclet.usage.header=\nProvided by the {0} doclet:
main.requires_argument=option {0} requires an argument.
+main.unnecessary_arg_provided=option {0} does not require an argument
+main.only_one_argument_with_equals=cannot use ''='' syntax for options that require multiple arguments
main.invalid_flag=invalid flag: {0}
main.No_modules_packages_or_classes_specified=No modules, packages or classes specified.
main.module_not_found=module {0} not found.\n
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Oct 05 06:28:23 2016 -0700
@@ -150,7 +150,7 @@
task.options.help = true;
}
},
- new Option(true, "-dotoutput") {
+ new Option(true, "-dotoutput", "--dot-output") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
@@ -191,7 +191,7 @@
}
}
},
- new Option(false, "-apionly") {
+ new Option(false, "-apionly", "--api-only") {
void process(JdepsTask task, String opt, String arg) {
task.options.apiOnly = true;
}
@@ -203,7 +203,7 @@
task.options.addmods.addAll(mods);
}
},
- new Option(true, "--gen-module-info") {
+ new Option(true, "--generate-module-info") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
@@ -212,7 +212,7 @@
task.options.genModuleInfo = Paths.get(arg);
}
},
- new Option(false, "-jdkinternals") {
+ new Option(false, "-jdkinternals", "--jdk-internals") {
void process(JdepsTask task, String opt, String arg) {
task.options.findJDKInternals = true;
task.options.verbose = CLASS;
@@ -263,19 +263,36 @@
task.options.addmods.add(arg);
}
},
+ new Option(true, "--multi-release") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (arg.equalsIgnoreCase("base")) {
+ task.options.multiRelease = JarFile.baseVersion();
+ } else {
+ try {
+ int v = Integer.parseInt(arg);
+ if (v < 9) {
+ throw new BadArgs("err.invalid.arg.for.option", arg);
+ }
+ } catch (NumberFormatException x) {
+ throw new BadArgs("err.invalid.arg.for.option", arg);
+ }
+ task.options.multiRelease = Runtime.Version.parse(arg);
+ }
+ }
+ },
// ---- Target filtering options ----
- new Option(true, "-p", "-package") {
+ new Option(true, "-p", "-package", "--package") {
void process(JdepsTask task, String opt, String arg) {
task.options.packageNames.add(arg);
}
},
- new Option(true, "-e", "-regex") {
+ new Option(true, "-e", "-regex", "--regex") {
void process(JdepsTask task, String opt, String arg) {
task.options.regex = Pattern.compile(arg);
}
},
- new Option(true, "-requires") {
+ new Option(true, "--require") {
void process(JdepsTask task, String opt, String arg) {
task.options.requires.add(arg);
}
@@ -336,7 +353,7 @@
}
},
- new Option(false, "-I", "-inverse") {
+ new Option(false, "-I", "--inverse") {
void process(JdepsTask task, String opt, String arg) {
task.options.inverse = true;
// equivalent to the inverse of compile-time view analysis
@@ -361,7 +378,7 @@
}
},
- new Option(false, "-version") {
+ new Option(false, "-version", "--version") {
void process(JdepsTask task, String opt, String arg) {
task.options.version = true;
}
@@ -390,23 +407,6 @@
}
}
},
- new Option(true, "--multi-release") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (arg.equalsIgnoreCase("base")) {
- task.options.multiRelease = JarFile.baseVersion();
- } else {
- try {
- int v = Integer.parseInt(arg);
- if (v < 9) {
- throw new BadArgs("err.invalid.arg.for.option", arg);
- }
- } catch (NumberFormatException x) {
- throw new BadArgs("err.invalid.arg.for.option", arg);
- }
- task.options.multiRelease = Runtime.Version.parse(arg);
- }
- }
- },
};
private static final String PROGNAME = "jdeps";
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Oct 05 06:28:23 2016 -0700
@@ -13,162 +13,168 @@
main.opt.h=\
\ -h -? -help\n\
-\ --help Print this usage message
+\ --help Print this usage message
main.opt.version=\
-\ -version Version information
+\ -version --version Version information
main.opt.v=\
-\ -v -verbose Print all class level dependencies\n\
-\ Equivalent to -verbose:class -filter:none.\n\
-\ -verbose:package Print package-level dependencies excluding\n\
-\ dependencies within the same package by default\n\
-\ -verbose:class Print class-level dependencies excluding\n\
-\ dependencies within the same package by default
+\ -v -verbose Print all class level dependences\n\
+\ Equivalent to -verbose:class -filter:none.\n\
+\ -verbose:package Print package-level dependences excluding\n\
+\ dependences within the same package by default\n\
+\ -verbose:class Print class-level dependences excluding\n\
+\ dependences within the same package by default
main.opt.s=\
-\ -s -summary Print dependency summary only.
+\ -s -summary Print dependency summary only.
main.opt.f=\
-\ -f <regex> -filter <regex> Filter dependences matching the given\n\
-\ pattern. If given multiple times, the last\n\
-\ one will be used.\n\
-\ -filter:package Filter dependences within the same package.\n\
-\ This is the default.\n\
-\ -filter:archive Filter dependences within the same archive.\n\
-\ -filter:module Filter dependences within the same module.\n\
-\ -filter:none No -filter:package and -filter:archive\n\
-\ filtering. Filtering specified via the\n\
-\ -filter option still applies.\n\
+\ -f <regex> -filter <regex> Filter dependences matching the given\n\
+\ pattern. If given multiple times, the last\n\
+\ one will be used.\n\
+\ -filter:package Filter dependences within the same package.\n\
+\ This is the default.\n\
+\ -filter:archive Filter dependences within the same archive.\n\
+\ -filter:module Filter dependences within the same module.\n\
+\ -filter:none No -filter:package and -filter:archive\n\
+\ filtering. Filtering specified via the\n\
+\ -filter option still applies.\n\
main.opt.p=\n\
-\Options to filter dependencies:\n\
-\ -p <pkgname> -package <pkgname> Finds dependences matching the given package\n\
-\ name (may be given multiple times).
+\Options to filter dependences:\n\
+\ -p <pkg>\n\
+\ -package <pkg>\n\
+\ --package <pkg> Finds dependences matching the given package\n\
+\ name (may be given multiple times).
main.opt.e=\
-\ -e <regex> -regex <regex> Finds dependences matching the given pattern.
+\ -e <regex>\n\
+\ -regex <regex>\n\
+\ --regex <regex> Finds dependences matching the given pattern.
-main.opt.requires=\
-\ -requires <module-name> Finds dependences matching the given module\n\
-\ name (may be given multiple times).\n\
-\ -package, -regex, -requires are mutual exclusive.
+main.opt.require=\
+\ --require <module-name> Finds dependences matching the given module\n\
+\ name (may be given multiple times). --package,\n\
+\ --regex, --require are mutual exclusive.
main.opt.include=\n\
\Options to filter classes to be analyzed:\n\
-\ -include <regex> Restrict analysis to classes matching pattern\n\
-\ This option filters the list of classes to\n\
-\ be analyzed. It can be used together with\n\
-\ -p and -e which apply pattern to the dependences
+\ -include <regex> Restrict analysis to classes matching pattern\n\
+\ This option filters the list of classes to\n\
+\ be analyzed. It can be used together with\n\
+\ -p and -e which apply pattern to the dependences
main.opt.P=\
-\ -P -profile Show profile containing a package
+\ -P -profile Show profile containing a package
main.opt.cp=\
\ -cp <path>\n\
\ -classpath <path>\n\
-\ --class-path <path> Specify where to find class files
+\ --class-path <path> Specify where to find class files
main.opt.module-path=\
-\ --module-path <module path>... Specify module path
+\ --module-path <module path> Specify module path
main.opt.upgrade-module-path=\
-\ --upgrade-module-path <module path>... Specify upgrade module path
+\ --upgrade-module-path <module path> Specify upgrade module path
main.opt.system=\
-\ --system <java-home> Specify an alternate system module path
+\ --system <java-home> Specify an alternate system module path
main.opt.add-modules=\
\ --add-modules <module-name>[,<module-name>...]\n\
-\ Adds modules to the root set for analysis
+\ Adds modules to the root set for analysis
main.opt.m=\
\ -m <module-name>\n\
-\ --module <module-name> Specify the root module for analysis
+\ --module <module-name> Specify the root module for analysis
main.opt.R=\
-\ -R -recursive Recursively traverse all run-time dependencies.\n\
-\ The -R option implies -filter:none. If -p,\n\
-\ -e, -foption is specified, only the matching\n\
-\ dependences are analyzed.
+\ -R -recursive Recursively traverse all run-time dependences.\n\
+\ The -R option implies -filter:none. If -p,\n\
+\ -e, -foption is specified, only the matching\n\
+\ dependences are analyzed.
main.opt.I=\
-\ -I -inverse Analyzes the dependences per other given options\n\
-\ and then find all artifacts that directly\n\
-\ and indirectly depend on the matching nodes.\n\
-\ This is equivalent to the inverse of\n\
-\ compile-time view analysis and print\n\
-\ dependency summary. This option must use\n\
-\ with -requires, -package or -regex option.
+\ -I --inverse Analyzes the dependences per other given options\n\
+\ and then find all artifacts that directly\n\
+\ and indirectly depend on the matching nodes.\n\
+\ This is equivalent to the inverse of\n\
+\ compile-time view analysis and print\n\
+\ dependency summary. This option must use\n\
+\ with --require, --package or --regex option.
main.opt.compile-time=\
-\ --compile-time Compile-time view of transitive dependencies\n\
-\ i.e. compile-time view of -R option.\n\
-\ Analyzes the dependences per other given options\n\
-\ If a dependence is found from a directory,\n\
-\ a JAR file or a module, all classes in that \n\
-\ containing archive are analyzed.
+\ --compile-time Compile-time view of transitive dependences\n\
+\ i.e. compile-time view of -R option.\n\
+\ Analyzes the dependences per other given options\n\
+\ If a dependence is found from a directory,\n\
+\ a JAR file or a module, all classes in that \n\
+\ containing archive are analyzed.
main.opt.apionly=\
-\ -apionly Restrict analysis to APIs i.e. dependences\n\
-\ from the signature of public and protected\n\
-\ members of public classes including field\n\
-\ type, method parameter types, returned type,\n\
-\ checked exception types etc.
+\ -apionly\n\
+\ --api-only Restrict analysis to APIs i.e. dependences\n\
+\ from the signature of public and protected\n\
+\ members of public classes including field\n\
+\ type, method parameter types, returned type,\n\
+\ checked exception types etc.
-main.opt.gen-module-info=\
-\ --gen-module-info <dir> Generate module-info.java under the specified\n\
-\ directory. The specified JAR files will be\n\
-\ analyzed. This option cannot be used with\n\
-\ -dotoutput or -cp.
+main.opt.generate-module-info=\
+\ --generate-module-info <dir> Generate module-info.java under the specified\n\
+\ directory. The specified JAR files will be\n\
+\ analyzed. This option cannot be used with\n\
+\ --dot-output or --class-path.
main.opt.check=\
\ --check <module-name>[,<module-name>...\n\
-\ Analyze the dependence of the specified modules\n\
-\ It prints the module descriptor, the resulting\n\
-\ module dependences after analysis and the\n\
-\ graph after transition reduction. It also\n\
-\ identifies any unused qualified exports.
+\ Analyze the dependence of the specified modules\n\
+\ It prints the module descriptor, the resulting\n\
+\ module dependences after analysis and the\n\
+\ graph after transition reduction. It also\n\
+\ identifies any unused qualified exports.
main.opt.dotoutput=\
-\ -dotoutput <dir> Destination directory for DOT file output
+\ -dotoutput <dir>\n\
+\ --dot-output <dir> Destination directory for DOT file output
main.opt.jdkinternals=\
-\ -jdkinternals Finds class-level dependences on JDK internal\n\
-\ APIs. By default, it analyzes all classes\n\
-\ on -classpath and input files unless -include\n\
-\ option is specified. This option cannot be\n\
-\ used with -p, -e and -s options.\n\
-\ WARNING: JDK internal APIs are inaccessible.
+\ -jdkinternals\n\
+\ --jdk-internals Finds class-level dependences on JDK internal\n\
+\ APIs. By default, it analyzes all classes\n\
+\ on --class-path and input files unless -include\n\
+\ option is specified. This option cannot be\n\
+\ used with -p, -e and -s options.\n\
+\ WARNING: JDK internal APIs are inaccessible.
main.opt.depth=\
-\ -depth=<depth> Specify the depth of the transitive\n\
-\ dependency analysis
+\ -depth=<depth> Specify the depth of the transitive\n\
+\ dependency analysis
main.opt.q=\
-\ -q -quiet Do not show missing dependencies from \n\
-\ -genmoduleinfo output.
+\ -q -quiet Do not show missing dependences from \n\
+\ --generate-module-info output.
main.opt.multi-release=\
-\ --multi-release <version> Specifies the version when processing\n\
-\ multi-release jar files. <version> should\n\
-\ be integer >= 9 or base.
+\ --multi-release <version> Specifies the version when processing\n\
+\ multi-release jar files. <version> should\n\
+\ be integer >= 9 or base.
err.unknown.option=unknown option: {0}
err.missing.arg=no value given for {0}
err.invalid.arg.for.option=invalid argument for option: {0}
err.option.after.class=option must be specified before classes: {0}
-err.genmoduleinfo.not.jarfile={0} not valid for --gen-module-info option (must be non-modular JAR file)
+err.genmoduleinfo.not.jarfile={0} not valid for --generate-module-info option (must be non-modular JAR file)
err.profiles.msg=No profile information
err.exception.message={0}
err.invalid.path=invalid path: {0}
err.invalid.module.option=Cannot set {0} with {1} option.
-err.invalid.filters=Only one of -package (-p), -regex (-e), -requires option can be set
+err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be set
err.module.not.found=module not found: {0}
err.root.module.not.set=root module set empty
-err.invalid.inverse.option={0} cannot be used with -inverse option
-err.inverse.filter.not.set={0} cannot be used with -inverse option
+err.invalid.inverse.option={0} cannot be used with --inverse option
err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set
err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set
err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
@@ -178,7 +184,7 @@
warn.replace.useJDKInternals=\
JDK internal APIs are unsupported and private to JDK implementation that are\n\
subject to be removed or changed incompatibly and could break your application.\n\
-Please modify your code to eliminate dependency on any JDK internal APIs.\n\
+Please modify your code to eliminate dependence on any JDK internal APIs.\n\
For the most recent update on JDK internal API replacements, please check:\n\
{0}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Oct 05 06:28:23 2016 -0700
@@ -199,6 +199,7 @@
private boolean feedbackInitialized = false;
private String commandLineFeedbackMode = null;
private List<String> remoteVMOptions = new ArrayList<>();
+ private List<String> compilerOptions = new ArrayList<>();
SourceCodeAnalysis analysis;
JShell state = null;
@@ -558,9 +559,14 @@
parser.accepts("s");
parser.accepts("v");
OptionSpec<String> r = parser.accepts("R").withRequiredArg();
+ OptionSpec<String> c = parser.accepts("C").withRequiredArg();
parser.acceptsAll(asList("h", "help"));
parser.accepts("version");
parser.accepts("full-version");
+
+ parser.accepts("X");
+ OptionSpec<String> addExports = parser.accepts("add-exports").withRequiredArg();
+
NonOptionArgumentSpec<String> loadFileSpec = parser.nonOptions();
OptionSet options;
@@ -585,6 +591,10 @@
printUsage();
return null;
}
+ if (options.has("X")) {
+ printUsageX();
+ return null;
+ }
if (options.has("version")) {
cmdout.printf("jshell %s\n", version());
return null;
@@ -630,7 +640,19 @@
commandLineFeedbackMode = "verbose";
}
if (options.has(r)) {
- remoteVMOptions = options.valuesOf(r);
+ remoteVMOptions.addAll(options.valuesOf(r));
+ }
+ if (options.has(c)) {
+ compilerOptions.addAll(options.valuesOf(c));
+ }
+
+ if (options.has(addExports)) {
+ List<String> exports = options.valuesOf(addExports).stream()
+ .map(mp -> mp + "=ALL-UNNAMED")
+ .flatMap(mp -> Stream.of("--add-exports", mp))
+ .collect(toList());
+ remoteVMOptions.addAll(exports);
+ compilerOptions.addAll(exports);
}
return options.valuesOf(loadFileSpec);
@@ -640,6 +662,10 @@
cmdout.print(getResourceString("help.usage"));
}
+ private void printUsageX() {
+ cmdout.print(getResourceString("help.usage.x"));
+ }
+
/**
* Message handler to use during initial start-up.
*/
@@ -683,7 +709,8 @@
.idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive())
? currentNameSpace.tid(sn)
: errorNamespace.tid(sn))
- .remoteVMOptions(remoteVMOptions.toArray(new String[remoteVMOptions.size()]))
+ .remoteVMOptions(remoteVMOptions.stream().toArray(String[]::new))
+ .compilerOptions(compilerOptions.stream().toArray(String[]::new))
.build();
shutdownSubscription = state.onShutdown((JShell deadState) -> {
if (deadState == state) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties Wed Oct 05 06:28:23 2016 -0700
@@ -164,8 +164,15 @@
\ Use one -J for each runtime flag or flag argument\n\
\ -R<flag> Pass <flag> to the remote runtime system.\n\
\ Use one -R for each remote flag or flag argument\n\
+\ -C<flag> Pass <flag> to the compiler.\n\
+\ Use one -C for each compiler flag or flag argument\n\
\ --help Print this synopsis of standard options\n\
-\ --version Version information\n
+\ --version Version information\n\
+\ -X Print help on non-standard options\n
+help.usage.x = \
+\ --add-exports <module>/<package> Export specified module-private package to snippets\n\
+\ \n\
+\These options are non-standard and subject to change without notice.\n
help.list.summary = list the source you have typed
help.list.args = [<name or id>|-all|-start]
--- a/langtools/test/jdk/javadoc/doclet/lib/JavadocTester.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/doclet/lib/JavadocTester.java Wed Oct 05 06:28:23 2016 -0700
@@ -41,6 +41,7 @@
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
@@ -410,6 +411,23 @@
}
/**
+ * Get the content of the one of the output streams written by
+ * javadoc.
+ */
+ public String getOutput(Output output) {
+ return outputMap.get(output);
+ }
+
+ /**
+ * Get the content of the one of the output streams written by
+ * javadoc.
+ */
+ public List<String> getOutputLines(Output output) {
+ String text = outputMap.get(output);
+ return (text == null) ? Collections.emptyList() : Arrays.asList(text.split(NL));
+ }
+
+ /**
* Check for files in (or not in) the generated output.
* @param expectedFound true if all of the files are expected
* to be found, or false if all of the files are expected to be
--- a/langtools/test/jdk/javadoc/doclet/testHelpOption/TestHelpOption.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/doclet/testHelpOption/TestHelpOption.java Wed Oct 05 06:28:23 2016 -0700
@@ -32,6 +32,9 @@
* @run main TestHelpOption
*/
+import java.util.*;
+import java.util.stream.*;
+
public class TestHelpOption extends JavadocTester {
public static void main(String... args) throws Exception {
@@ -40,6 +43,26 @@
}
@Test
+ void testLineLengths() {
+ javadoc("-d", "out1",
+ "-sourcepath", testSrc,
+ "-X",
+ testSrc("TestXOption.java"));
+ checkExit(Exit.OK);
+ List<String> longLines = getOutputLines(Output.OUT).stream()
+ .filter(s -> s.length() > 80)
+ .collect(Collectors.toList());
+ checking("line lengths");
+ if (longLines.isEmpty()) {
+ passed("all lines OK");
+ } else {
+ out.println("long lines:");
+ longLines.stream().forEach(s -> out.println(">>>" + s + "<<<"));
+ failed(longLines.size() + " long lines");
+ }
+ }
+
+ @Test
void testWithOption() {
javadoc("-d", "out1",
"-sourcepath", testSrc,
@@ -107,7 +130,7 @@
"-use ",
"-version ",
"-author ",
- "-docfilessubdirs ",
+ "-docfilessubdirs\n",
"-splitindex ",
"-windowtitle ",
"-doctitle ",
@@ -119,11 +142,11 @@
"-excludedocfilessubdir ",
"-group ",
"-nocomment ",
- "-nodeprecated ",
+ "-nodeprecated\n",
"-noqualifier ",
"-nosince ",
"-notimestamp ",
- "-nodeprecatedlist ",
+ "-nodeprecatedlist\n",
"-notree ",
"-noindex ",
"-nohelp ",
--- a/langtools/test/jdk/javadoc/doclet/testXOption/TestXOption.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/doclet/testXOption/TestXOption.java Wed Oct 05 06:28:23 2016 -0700
@@ -31,6 +31,9 @@
* @run main TestXOption
*/
+import java.util.*;
+import java.util.stream.*;
+
public class TestXOption extends JavadocTester {
public static void main(String... args) throws Exception {
@@ -39,6 +42,26 @@
}
@Test
+ void testLineLengths() {
+ javadoc("-d", "out1",
+ "-sourcepath", testSrc,
+ "-X",
+ testSrc("TestXOption.java"));
+ checkExit(Exit.OK);
+ List<String> longLines = getOutputLines(Output.OUT).stream()
+ .filter(s -> s.length() > 80)
+ .collect(Collectors.toList());
+ checking("line lengths");
+ if (longLines.isEmpty()) {
+ passed("all lines OK");
+ } else {
+ out.println("long lines:");
+ longLines.stream().forEach(s -> out.println(">>>" + s + "<<<"));
+ failed(longLines.size() + " long lines");
+ }
+ }
+
+ @Test
void testWithOption() {
javadoc("-d", "out1",
"-sourcepath", testSrc,
@@ -58,14 +81,9 @@
}
private void checkOutput(boolean expectFound) {
- // TODO: It's an ugly hidden side-effect of the current doclet API
- // that the -X output from the tool and the -X output from the doclet
- // come out on different streams!
- // When we clean up the doclet API, this should be rationalized.
checkOutput(Output.OUT, expectFound,
"-Xmaxerrs ",
- "-Xmaxwarns ");
- checkOutput(Output.OUT, expectFound,
+ "-Xmaxwarns ",
"-Xdocrootparent ",
"-Xdoclint ",
"-Xdoclint:");
--- a/langtools/test/jdk/javadoc/tool/CheckResourceKeys.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/tool/CheckResourceKeys.java Wed Oct 05 06:28:23 2016 -0700
@@ -145,6 +145,9 @@
// ignore these synthesized keys, tested by usageTests
if (rk.startsWith("doclet.usage.") || rk.startsWith("doclet.xusage"))
continue;
+ // ignore these synthesized keys, tested by usageTests
+ if (rk.matches("main\\.opt\\..*\\.(arg|desc)"))
+ continue;
if (codeKeys.contains(rk))
continue;
@@ -161,6 +164,9 @@
// ignore these synthesized keys, tested by usageTests
if (ck.startsWith("doclet.usage.") || ck.startsWith("doclet.xusage."))
continue;
+ // ignore this partial key, tested by usageTests
+ if (ck.equals("main.opt."))
+ continue;
if (resourceKeys.contains(ck))
continue;
error("No resource for \"" + ck + "\"");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/tool/OptionSyntaxTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,293 @@
+/*
+ * 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
+ * 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 8166144
+ * @summary support new-style options
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * @modules jdk.compiler/com.sun.tools.javac.main
+ * @modules jdk.javadoc/jdk.javadoc.internal.api
+ * @modules jdk.javadoc/jdk.javadoc.internal.tool
+ * @library /tools/lib
+ * @build toolbox.JavacTask toolbox.JavadocTask toolbox.ModuleBuilder toolbox.TestRunner toolbox.ToolBox
+ * @run main OptionSyntaxTest
+ */
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+
+import jdk.javadoc.doclet.Doclet;
+import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.doclet.Reporter;
+
+import toolbox.JavadocTask;
+import toolbox.ModuleBuilder;
+import toolbox.Task;
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+
+public class OptionSyntaxTest extends TestRunner {
+ public static class TestDoclet implements Doclet {
+ @Override
+ public boolean run(DocletEnvironment root) {
+ System.out.println("TestDoclet.run");
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return "Test";
+ }
+
+ @Override
+ public Set<Option> getSupportedOptions() {
+ return options;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ @Override
+ public void init(Locale locale, Reporter reporter) {
+ }
+
+ private final Set<Doclet.Option> options = new HashSet<>(Arrays.asList(
+ new DOption("-old", 0),
+ new DOption("-oldWithArg", 1),
+ new DOption("-oldWithArgs", 2),
+ new DOption("--new", 0),
+ new DOption("--newWithArg", 1),
+ new DOption("--newWithArgs", 2)
+ ));
+
+ }
+
+ static class DOption implements Doclet.Option {
+ private final String name;
+ private final int argCount;
+
+ DOption(String name, int argCount) {
+ this.name = name;
+ this.argCount = argCount;
+ }
+
+ @Override
+ public int getArgumentCount() {
+ return argCount;
+ }
+
+ @Override
+ public String getDescription() {
+ return "description[" + name + "]";
+ }
+
+ @Override
+ public Kind getKind() {
+ return Doclet.Option.Kind.STANDARD;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getParameters() {
+ return argCount > 0 ? "parameters[" + name + "," + argCount + "]" : null;
+ }
+
+ @Override
+ public boolean matches(String option) {
+ return option.equals(name);
+ }
+
+ @Override
+ public boolean process(String option, ListIterator<String> arguments) {
+ List<String> args = new ArrayList<>();
+ for (int i = 0; i < argCount && arguments.hasNext(); i++) {
+ args.add(arguments.next());
+ }
+ System.out.println("process " + option + " " + args);
+ return args.stream().filter(s -> s.startsWith("arg")).count() == argCount;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ OptionSyntaxTest t = new OptionSyntaxTest();
+ t.runTests();
+ }
+
+ private final ToolBox tb = new ToolBox();
+ private final Path src = Paths.get("src");
+ private final Path modules = Paths.get("modules");
+
+ OptionSyntaxTest() throws IOException {
+ super(System.err);
+ initModules();
+ }
+
+ void initModules() throws IOException {
+ new ModuleBuilder(tb, "m1")
+ .exports("p1")
+ .classes("package p1; public class C1 { }")
+ .write(src);
+
+ new ModuleBuilder(tb, "m2")
+ .exports("p2")
+ .classes("package p2; public class C2 { }")
+ .build(modules);
+
+ }
+
+ @Test
+ public void testBasic() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testNewSourcePath() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "--source-path", "src/m1",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testNewSourcePathEquals() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "--source-path=src/m1",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testOldDocletArgs() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "-old",
+ "-oldWithArg", "arg",
+ "-oldWithArgs", "arg1", "arg2",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testNewDocletArgs() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "--new",
+ "--newWithArg", "arg",
+ "--newWithArgs", "arg1", "arg2",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testNewDocletArgsEquals() {
+ new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "--new", "--newWithArg=arg",
+ "p1")
+ .run()
+ .writeAll();
+ }
+
+ @Test
+ public void testNewDocletArgsMissingArgs() throws Exception {
+ String log = new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "--newWithArg")
+ .run(Task.Expect.FAIL)
+ .writeAll()
+ .getOutput(Task.OutputKind.DIRECT);
+ if (!log.contains("option --newWithArg requires an argument"))
+ throw new Exception("expected output not found");
+ }
+
+ @Test
+ public void testNewDocletArgsExtraArgs() throws Exception {
+ String log = new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "--new=arg",
+ "p1")
+ .run(Task.Expect.FAIL)
+ .writeAll()
+ .getOutput(Task.OutputKind.DIRECT);
+ if (!log.contains("option --new does not require an argument"))
+ throw new Exception("expected output not found");
+ }
+
+ @Test
+ public void testNewDocletArgsExtraArgs2() throws Exception {
+ String log = new JavadocTask(tb, Task.Mode.CMDLINE)
+ .options("-docletpath", System.getProperty("test.classes"),
+ "-doclet", TestDoclet.class.getName(),
+ "-sourcepath", "src/m1",
+ "--newWithArgs=arg1 arg2",
+ "p1")
+ .run(Task.Expect.FAIL)
+ .writeAll()
+ .getOutput(Task.OutputKind.DIRECT);
+ if (!log.contains("cannot use '=' syntax for options that require multiple arguments"))
+ throw new Exception("expected output not found");
+ }
+
+}
--- a/langtools/test/jdk/javadoc/tool/api/basic/IsSupportedOptionTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/tool/api/basic/IsSupportedOptionTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, 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
@@ -35,7 +35,7 @@
import javax.tools.ToolProvider;
/**
- * Tests for DocumentationTool.usSupportedOption method.
+ * Tests for DocumentationTool.isSupportedOption method.
*/
public class IsSupportedOptionTest extends APITest {
public static void main(String... args) throws Exception {
--- a/langtools/test/jdk/javadoc/tool/modules/FilterOptions.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/tool/modules/FilterOptions.java Wed Oct 05 06:28:23 2016 -0700
@@ -70,7 +70,7 @@
@Test
public void testModuleModeApi(Path base) throws Exception {
execTask("--module-source-path", src,
- "--module", "m1", "--show-module-contents:api");
+ "--module", "m1", "--show-module-contents", "api");
checkModuleMode("API");
}
@@ -78,7 +78,7 @@
@Test
public void testModuleModeAll(Path base) throws Exception {
execTask("--module-source-path", src,
- "--module", "m1", "--show-module-contents:all");
+ "--module", "m1", "--show-module-contents", "all");
checkModuleMode("ALL");
}
@@ -87,7 +87,7 @@
public void testShowPackagesExported(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-packages:exported"); // default
+ "--show-packages", "exported"); // default
checkModulesSpecified("m1");
checkModulesIncluded("m1");
@@ -99,7 +99,7 @@
public void testShowPackagesAll(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-packages:all");
+ "--show-packages", "all");
checkModulesSpecified("m1");
checkModulesIncluded("m1");
checkPackagesIncluded("pub", "pro");
@@ -112,7 +112,7 @@
public void testShowTypesPrivate(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-types:private");
+ "--show-types", "private");
checkModulesSpecified("m1");
checkModulesIncluded("m1");
@@ -129,7 +129,7 @@
public void testShowTypesPackage(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-types:package");
+ "--show-types", "package");
checkModulesSpecified("m1");
checkModulesIncluded("m1");
@@ -145,7 +145,7 @@
public void testShowTypesProtected(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-types:protected");
+ "--show-types", "protected");
checkModulesSpecified("m1");
checkModulesIncluded("m1");
@@ -162,7 +162,7 @@
public void testShowTypesPublic(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-types:public");
+ "--show-types", "public");
checkModulesSpecified("m1");
checkModulesIncluded("m1");
@@ -179,7 +179,7 @@
public void testShowMembersPrivate(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-members:private");
+ "--show-members", "private");
checkMembers(Visibility.PRIVATE);
}
@@ -188,7 +188,7 @@
public void testShowMembersPackage(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-members:package");
+ "--show-members", "package");
checkMembers(Visibility.PACKAGE);
}
@@ -197,7 +197,7 @@
public void testShowMembersProtected(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-members:protected");
+ "--show-members", "protected");
checkMembers(Visibility.PROTECTED);
}
@@ -206,7 +206,7 @@
public void testShowMembersPublic(Path base) throws Exception {
execTask("--module-source-path", src,
"--module", "m1",
- "--show-members:public");
+ "--show-members", "public");
checkMembers(Visibility.PUBLIC);
}
--- a/langtools/test/jdk/javadoc/tool/modules/Modules.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/javadoc/tool/modules/Modules.java Wed Oct 05 06:28:23 2016 -0700
@@ -440,7 +440,7 @@
execTask("--module-source-path", src.toString(),
"--module", "M",
- "--expand-requires:public");
+ "--expand-requires", "public");
checkModulesSpecified("M", "N", "O");
checkModulesIncluded("M", "N", "O");
@@ -465,7 +465,7 @@
execTask("--module-source-path", src.toString(),
"--module", "M",
- "--expand-requires:all");
+ "--expand-requires", "all");
checkModulesSpecified("M", "java.base", "N", "L", "O");
checkModulesIncluded("M", "java.base", "N", "L", "O");
@@ -493,7 +493,7 @@
execNegativeTask("--module-source-path", src.toString(),
"--module", "MIA",
- "--expand-requires:all");
+ "--expand-requires", "all");
assertErrorPresent("javadoc: error - module MIA not found.");
}
@@ -515,7 +515,7 @@
execNegativeTask("--module-source-path", src.toString(),
"--module", "M,N,L,MIA,O,P",
- "--expand-requires:all");
+ "--expand-requires", "all");
assertErrorPresent("javadoc: error - module MIA not found");
}
--- a/langtools/test/jdk/jshell/HistoryTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/jshell/HistoryTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 8166744
* @summary Test Completion
* @modules jdk.internal.le/jdk.internal.jline.extra
* jdk.jshell/jdk.internal.jshell.tool
@@ -75,6 +76,44 @@
});
}
+ public void test8166744() {
+ test(
+ a -> {if (!a) setCommandInput("class C {\n");},
+ a -> {if (!a) setCommandInput("void f() {\n");},
+ a -> {if (!a) setCommandInput("}\n");},
+ a -> {assertCommand(a, "}", "| created class C");},
+ a -> {
+ if (!a) {
+ try {
+ previousAndAssert(getHistory(), "}");
+ previousAndAssert(getHistory(), "}");
+ previousAndAssert(getHistory(), "void f() {");
+ previousAndAssert(getHistory(), "class C {");
+ getHistory().add("class C{");
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ assertCommand(a, "int dummy;", "dummy ==> 0");
+ });
+ test(
+ a -> {if (!a) setCommandInput("class C {\n");},
+ a -> {if (!a) setCommandInput("void f() {\n");},
+ a -> {if (!a) setCommandInput("}\n");},
+ a -> {assertCommand(a, "}", "| created class C");},
+ a -> {
+ if (!a) {
+ try {
+ previousSnippetAndAssert(getHistory(), "class C {");
+ getHistory().add("class C{");
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ assertCommand(a, "int dummy;", "dummy ==> 0");
+ });
+ }
+
private EditingHistory getHistory() throws Exception {
Field input = repl.getClass().getDeclaredField("input");
input.setAccessible(true);
--- a/langtools/test/jdk/jshell/ToolBasicTest.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347
+ * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714
* @summary Tests for Basic tests for REPL tool
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@@ -574,4 +574,20 @@
}
}
+ public void testAddExports() {
+ test(false, new String[]{"--no-startup"},
+ a -> assertCommandOutputStartsWith(a, "import jdk.internal.misc.VM;", "| Error:")
+ );
+ test(false, new String[]{"--no-startup",
+ "-R--add-exports", "-Rjava.base/jdk.internal.misc=ALL-UNNAMED",
+ "-C--add-exports", "-Cjava.base/jdk.internal.misc=ALL-UNNAMED"},
+ a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"),
+ a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n")
+ );
+ test(false, new String[]{"--no-startup", "--add-exports", "java.base/jdk.internal.misc"},
+ a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"),
+ a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n")
+ );
+ }
+
}
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt Wed Oct 05 06:28:23 2016 -0700
@@ -66,6 +66,7 @@
compiler.misc.kindname.type.variable.bound
compiler.misc.kindname.value
compiler.misc.incompatible.eq.lower.bounds # cannot happen?
+compiler.misc.module.name.mismatch
compiler.misc.no.unique.minimal.instance.exists
compiler.misc.no.unique.maximal.instance.exists # cannot happen?
compiler.misc.resume.abort # prompt for a response
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/ReorderedBoundsTest.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,65 @@
+/*
+ * 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 8166363
+ * @summary Method with reordered type parameter bounds compiles with Override annotation but does not actually override superclass method.
+ * @run main ReorderedBoundsTest
+ */
+
+import java.io.Serializable;
+
+public class ReorderedBoundsTest {
+ public static class Parent {
+ public <T extends Appendable & Serializable> String printClassName(T t) {
+ return "Parent";
+ }
+ }
+
+ public static class OrderedChild extends Parent {
+ @Override
+ public <T extends Appendable & Serializable> String printClassName(T t) {
+ return "OrderedChild";
+ }
+ }
+
+ public static class ReorderedChild extends Parent {
+ @Override
+ public <T extends Serializable & Appendable> String printClassName(T t) {
+ return "ReorderedChild";
+ }
+ }
+
+ public static void main(String[] args) {
+
+ String s;
+ Parent p = new OrderedChild();
+ if (!(s = p.printClassName(new StringBuilder())).equals("OrderedChild"))
+ throw new AssertionError("Bad output: " + s);
+
+ p = new ReorderedChild();
+ if (!(s = p.printClassName(new StringBuilder())).equals("ReorderedChild"))
+ throw new AssertionError("Bad output: " + s);
+ }
+}
\ No newline at end of file
--- a/langtools/test/tools/javac/modules/EdgeCases.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/javac/modules/EdgeCases.java Wed Oct 05 06:28:23 2016 -0700
@@ -58,6 +58,8 @@
import toolbox.JarTask;
import toolbox.JavacTask;
import toolbox.Task;
+import toolbox.Task.Expect;
+import toolbox.Task.OutputKind;
public class EdgeCases extends ModuleTestBase {
@@ -304,4 +306,147 @@
}
}
+ @Test
+ public void testImplicitJavaBase(Path base) throws Exception {
+ Path src = base.resolve("src");
+ Path src_java_base = src.resolve("java.base");
+ Files.createDirectories(src_java_base);
+ tb.writeJavaFiles(src_java_base, "module java.base { exports java.lang; }");
+ tb.writeJavaFiles(src_java_base,
+ "package java.lang; public class Object {}");
+ Path classes = base.resolve("classes");
+ tb.createDirectories(classes);
+
+ //module-info from source:
+ new JavacTask(tb)
+ .options("-sourcepath", src_java_base.toString())
+ .outdir(classes)
+ .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
+ .run()
+ .writeAll();
+
+ //module-info from class:
+ if (!Files.exists(classes.resolve("module-info.class"))) {
+ throw new AssertionError("module-info.class not created!");
+ }
+
+ new JavacTask(tb)
+ .outdir(classes)
+ .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
+ .run()
+ .writeAll();
+
+ //broken module-info.class:
+ Files.newOutputStream(classes.resolve("module-info.class")).close();
+
+ List<String> log = new JavacTask(tb)
+ .options("-XDrawDiagnostics")
+ .outdir(classes)
+ .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
+ .run(Expect.FAIL)
+ .writeAll()
+ .getOutputLines(OutputKind.DIRECT);
+
+ List<String> expected = Arrays.asList(
+ "- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))",
+ "1 error");
+
+ if (!expected.equals(log)) {
+ throw new AssertionError("Unexpected output: " + log);
+ }
+
+ //broken module-info.java:
+ Files.delete(classes.resolve("module-info.class"));
+
+ try (Writer out = Files.newBufferedWriter(src_java_base.resolve("module-info.java"))) {
+ out.write("class Broken {}");
+ }
+
+ log = new JavacTask(tb)
+ .options("-sourcepath", src_java_base.toString(),
+ "-XDrawDiagnostics")
+ .outdir(classes)
+ .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
+ .run(Expect.FAIL)
+ .writeAll()
+ .getOutputLines(OutputKind.DIRECT);
+
+ expected = Arrays.asList("X");
+
+ if (expected.equals(log)) {
+ throw new AssertionError("Unexpected output: " + log);
+ }
+ }
+
+ @Test
+ public void testModuleInfoNameMismatchSource(Path base) throws Exception {
+ Path src = base.resolve("src");
+ Path m1 = src.resolve("m1");
+ Files.createDirectories(m1);
+ tb.writeJavaFiles(m1, "module other { }",
+ "package test; public class Test {}");
+ Path classes = base.resolve("classes");
+ tb.createDirectories(classes);
+
+ List<String> log = new JavacTask(tb)
+ .options("--module-source-path", src.toString(),
+ "-XDrawDiagnostics")
+ .outdir(classes)
+ .files(findJavaFiles(m1.resolve("test").resolve("Test.java")))
+ .run(Expect.FAIL)
+ .writeAll()
+ .getOutputLines(OutputKind.DIRECT);
+
+ List<String> expected = Arrays.asList(
+ "module-info.java:1:1: compiler.err.module.name.mismatch: other, m1",
+ "- compiler.err.cant.access: m1.module-info, (compiler.misc.cant.resolve.modules)",
+ "2 errors");
+
+ if (!expected.equals(log)) {
+ throw new AssertionError("Unexpected output: " + log);
+ }
+ }
+
+ @Test
+ public void testModuleInfoNameMismatchClass(Path base) throws Exception {
+ Path src = base.resolve("src");
+ Files.createDirectories(src);
+ tb.writeJavaFiles(src, "module other { }",
+ "package test; public class Test {}");
+ Path classes = base.resolve("classes");
+ Path m1Classes = classes.resolve("m1");
+ tb.createDirectories(m1Classes);
+
+ new JavacTask(tb)
+ .outdir(m1Classes)
+ .files(findJavaFiles(src))
+ .run()
+ .writeAll()
+ .getOutputLines(OutputKind.DIRECT);
+
+ Path src2 = base.resolve("src2");
+ Files.createDirectories(src2);
+ tb.writeJavaFiles(src2, "module use { requires m1; }");
+
+ Path classes2 = base.resolve("classes2");
+ tb.createDirectories(classes2);
+
+ List<String> log = new JavacTask(tb)
+ .options("--module-path", classes.toString(),
+ "-XDrawDiagnostics")
+ .outdir(classes2)
+ .files(findJavaFiles(src2))
+ .run(Expect.FAIL)
+ .writeAll()
+ .getOutputLines(OutputKind.DIRECT);
+
+ List<String> expected = Arrays.asList(
+ "- compiler.err.cant.access: m1.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: other, m1))",
+ "1 error");
+
+ if (!expected.equals(log)) {
+ throw new AssertionError("Unexpected output: " + log);
+ }
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/StopAfterError/StopAfterError.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,61 @@
+/*
+ * 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 8073844
+ * @summary If an error is produced by an annotation processor, the code should not be Attred, \
+ * unless requested
+ * @modules jdk.compiler
+ * @compile StopAfterError.java
+ * @compile/fail/ref=StopAfterError.out -XDrawDiagnostics -processor StopAfterError StopAfterErrorAux.java
+ * @compile/fail/ref=StopAfterError.out -XDshould-stop.ifError=PROCESS -XDrawDiagnostics -processor StopAfterError StopAfterErrorAux.java
+ * @compile/fail/ref=StopAfterErrorContinue.out -XDshould-stop.ifError=ATTR -XDrawDiagnostics -processor StopAfterError StopAfterErrorAux.java
+ */
+
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic.Kind;
+
+@SupportedAnnotationTypes("*")
+public class StopAfterError extends AbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver()) {
+ processingEnv.getMessager().printMessage(Kind.ERROR, "Stop!");
+ }
+ return false;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/StopAfterError/StopAfterError.out Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,2 @@
+- compiler.err.proc.messager: Stop!
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/StopAfterError/StopAfterErrorAux.java Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,6 @@
+/* /nodynamiccopyright/ */
+class StopAfterErrorAux {
+ public void test() {
+ should not; get here;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/StopAfterError/StopAfterErrorContinue.out Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,4 @@
+- compiler.err.proc.messager: Stop!
+StopAfterErrorAux.java:4:9: compiler.err.cant.resolve.location: kindname.class, should, , , (compiler.misc.location: kindname.class, StopAfterErrorAux, null)
+StopAfterErrorAux.java:4:21: compiler.err.cant.resolve.location: kindname.class, get, , , (compiler.misc.location: kindname.class, StopAfterErrorAux, null)
+3 errors
--- a/langtools/test/tools/jdeps/APIDeps.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/jdeps/APIDeps.java Wed Oct 05 06:28:23 2016 -0700
@@ -135,7 +135,7 @@
"java.util.Set",
"c.C", "d.D", "c.I", "e.E", "m.Bar"},
new String[] {"compact1", testDirBasename, mDir.getName()},
- new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"});
+ new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "--api-only"});
return errors;
}
--- a/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java Wed Oct 05 06:28:23 2016 -0700
@@ -116,7 +116,7 @@
@Test
public void removedPackage() {
Path file = Paths.get("q", "RemovedPackage.class");
- String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+ String[] output = JdepsUtil.jdeps("--jdk-internals", CLASSES_DIR.resolve(file).toString());
int i = 0;
// expect no replacement
while (i < output.length && !output[i].contains("Suggested Replacement")) {
--- a/langtools/test/tools/jdeps/modules/GenModuleInfo.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/jdeps/modules/GenModuleInfo.java Wed Oct 05 06:28:23 2016 -0700
@@ -23,7 +23,7 @@
/*
* @test
- * @summary Tests jdeps --gen-module-info option
+ * @summary Tests jdeps --generate-module-info option
* @library ../lib
* @build CompilerUtils JdepsUtil
* @modules jdk.jdeps/com.sun.tools.jdeps
@@ -106,7 +106,7 @@
.map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.map(Path::toString);
- JdepsUtil.jdeps(Stream.concat(Stream.of("--gen-module-info", DEST_DIR.toString()),
+ JdepsUtil.jdeps(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
files).toArray(String[]::new));
// check file exists
--- a/langtools/test/tools/jdeps/modules/InverseDeps.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/jdeps/modules/InverseDeps.java Wed Oct 05 06:28:23 2016 -0700
@@ -91,7 +91,7 @@
@DataProvider(name = "testrequires")
public Object[][] expected1() {
return new Object[][] {
- // -requires and result
+ // --require and result
{ "java.sql", new String[][] {
new String[] { "java.sql", "m5" },
}
@@ -117,7 +117,7 @@
@Test(dataProvider = "testrequires")
public void testrequires(String name, String[][] expected) throws Exception {
- String cmd1 = String.format("jdeps -inverse --module-path %s -requires %s --add-modules %s%n",
+ String cmd1 = String.format("jdeps --inverse --module-path %s --require %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
@@ -128,7 +128,7 @@
runJdeps(jdeps, expected);
}
- String cmd2 = String.format("jdeps -inverse --module-path %s -requires %s" +
+ String cmd2 = String.format("jdeps --inverse --module-path %s --require %s" +
" --add-modules ALL-MODULE-PATH%n", LIBS_DIR, name);
// automatic module
@@ -164,7 +164,7 @@
@Test(dataProvider = "testpackage")
public void testpackage(String name, String[][] expected) throws Exception {
- String cmd = String.format("jdeps -inverse --module-path %s -package %s --add-modules %s%n",
+ String cmd = String.format("jdeps --inverse --module-path %s -package %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
jdeps.appModulePath(MODS_DIR.toString())
@@ -195,7 +195,7 @@
@Test(dataProvider = "testregex")
public void testregex(String name, String[][] expected) throws Exception {
- String cmd = String.format("jdeps -inverse --module-path %s -regex %s --add-modules %s%n",
+ String cmd = String.format("jdeps --inverse --module-path %s -regex %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
@@ -240,7 +240,7 @@
Path jarfile = LIBS_DIR.resolve("m7.jar");
- String cmd1 = String.format("jdeps -inverse -classpath %s -regex %s %s%n",
+ String cmd1 = String.format("jdeps --inverse -classpath %s -regex %s %s%n",
cpath, name, jarfile);
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
jdeps.verbose("-verbose:class")
@@ -253,7 +253,7 @@
Set<Path> paths = modules.stream()
.map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.collect(Collectors.toSet());
- String cmd2 = String.format("jdeps -inverse -regex %s %s%n", name, paths);
+ String cmd2 = String.format("jdeps --inverse -regex %s %s%n", name, paths);
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) {
jdeps.verbose("-verbose:class").regex(name);
paths.forEach(jdeps::addRoot);
--- a/langtools/test/tools/jdeps/modules/src/m3/module-info.java Fri Sep 30 02:52:42 2016 -0700
+++ b/langtools/test/tools/jdeps/modules/src/m3/module-info.java Wed Oct 05 06:28:23 2016 -0700
@@ -24,7 +24,7 @@
module m3 {
requires public java.sql;
requires public m2;
- requires java.logging; // TODO: --gen-module-info to do transitive reduction
+ requires java.logging; // TODO: --generate-module-info to do transitive reduction
requires public m1;
exports p3;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/ExplodedImageOptimize.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+
+# Runs a tool on the exploded image to improve performance
+
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+include $(JDK_TOPDIR)/make/ModuleTools.gmk
+
+################################################################################
+
+PACKAGES_ATTRIBUTE_TARGET := $(JDK_OUTPUTDIR)/_packages_attribute.done
+ALL_MODULEINFO_CLASSES := $(wildcard $(JDK_OUTPUTDIR)/modules/*/module_info.class)
+
+$(PACKAGES_ATTRIBUTE_TARGET): $(ALL_MODULEINFO_CLASSES) $(BUILD_JIGSAW_CLASSES)
+ $(call LogInfo, Optimizing the exploded image)
+ $(TOOL_ADD_PACKAGES_ATTRIBUTE) $(JDK_OUTPUTDIR)
+
+TARGETS := $(PACKAGES_ATTRIBUTE_TARGET)
+
+################################################################################
+
+all: $(TARGETS)
+
+.PHONY: all default
--- a/make/Javadoc.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/make/Javadoc.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -1575,7 +1575,7 @@
$(JACCESSAPI_INDEX_HTML): $(JACCESSAPI_OPTIONS_FILE) $(JACCESSAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE)
$(prep-javadoc)
$(call JavadocSummary,$(JACCESSAPI_OPTIONS_FILE),$(JACCESSAPI_PACKAGES_FILE))
- $(JAVADOC_CMD) -d $(@D) \
+ $(JAVADOC_CMD_SMALL) -d $(@D) \
@$(JACCESSAPI_OPTIONS_FILE) @$(JACCESSAPI_PACKAGES_FILE)
# Create file with javadoc options in it
--- a/make/Main.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/make/Main.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -82,10 +82,13 @@
buildtools-jdk:
+($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileTools.gmk)
+
+ buildtools-modules:
+ +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileModuleTools.gmk)
endif
ALL_TARGETS += buildtools-langtools interim-langtools \
- interim-rmic interim-cldrconverter buildtools-jdk
+ interim-rmic interim-cldrconverter buildtools-jdk buildtools-modules
################################################################################
# Special targets for certain modules
@@ -340,8 +343,12 @@
mac-bundles-jdk:
+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f MacBundles.gmk)
+exploded-image-optimize:
+ +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f ExplodedImageOptimize.gmk)
+
ALL_TARGETS += source-tips create-hgtip-files bootcycle-images zip-security \
- zip-source jrtfs-jar jimages profiles mac-bundles-jdk
+ zip-source jrtfs-jar jimages profiles mac-bundles-jdk \
+ exploded-image-optimize
################################################################################
# Docs targets
@@ -521,6 +528,8 @@
buildtools-jdk: interim-langtools interim-cldrconverter
+ buildtools-modules: exploded-image-base
+
$(CORBA_GENSRC_TARGETS): interim-langtools
$(HOTSPOT_GENSRC_TARGETS): interim-langtools
@@ -646,6 +655,7 @@
# Avoid calling create-buildjdk from within a create-buildjdk call
ifneq ($(CREATING_BUILDJDK), true)
$(JMOD_TARGETS): create-buildjdk
+ buildtools-modules: create-buildjdk
endif
endif
@@ -677,6 +687,8 @@
mac-bundles-jdk: jimages
+ exploded-image-optimize: exploded-image-base buildtools-modules
+
bootcycle-images: jimages
docs-javadoc: $(GENSRC_TARGETS) rmic
@@ -728,7 +740,7 @@
docs-bundles: docs-image
- generate-summary: jmods
+ generate-summary: jmods buildtools-modules
endif
@@ -774,7 +786,8 @@
samples: samples-jdk
# The "exploded image" is a locally runnable JDK in $(BUILD_OUTPUT)/jdk.
-exploded-image: $(ALL_MODULES)
+exploded-image-base: $(ALL_MODULES)
+exploded-image: exploded-image-base exploded-image-optimize
create-buildjdk: create-buildjdk-copy create-buildjdk-interim-image
@@ -815,7 +828,8 @@
all-bundles: product-bundles test-bundles docs-bundles
ALL_TARGETS += buildtools gensrc gendata copy java rmic libs launchers jmods \
- jdk.jdwp.agent-gensrc $(ALL_MODULES) demos samples exploded-image \
+ jdk.jdwp.agent-gensrc $(ALL_MODULES) demos samples \
+ exploded-image-base exploded-image \
create-buildjdk mac-bundles product-images docs-image test-image all-images \
all-bundles
--- a/make/MainSupport.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/make/MainSupport.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -137,7 +137,6 @@
define DeclareRecipeForModuleMakefile
ifeq ($$($1_MULTIPLE_MAKEFILES), true)
$2-$$($1_TARGET_SUFFIX): $2-$$($1_TARGET_SUFFIX)-$$(notdir $3)
- $1 += $2-$$($1_TARGET_SUFFIX)-$$(notdir $3)
$2-$$($1_TARGET_SUFFIX)-$$(notdir $3):
else
@@ -173,6 +172,12 @@
# Only declare recipes if there are makefiles to call
ifneq ($$($1_$2_TOPDIRS), )
+ # Add the top dir specific target to target list regardless of if recipe
+ # generation is disabled.
+ ifeq ($$($1_MULTIPLE_MAKEFILES), true)
+ $$(foreach d, $$($1_$2_TOPDIRS), \
+ $$(eval $1 += $2-$$($1_TARGET_SUFFIX)-$$(notdir $$d)))
+ endif
ifeq ($(NO_RECIPES),)
$$(foreach d, $$($1_$2_TOPDIRS), \
$$(eval $$(call DeclareRecipeForModuleMakefile,$1,$2,$$d)))
--- a/make/common/SetupJavaCompilers.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/make/common/SetupJavaCompilers.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -38,7 +38,10 @@
# and the interim javac, to be run by the boot jdk.
$(eval $(call SetupJavaCompiler,BOOT_JAVAC, \
JAVAC := $(JAVAC), \
- FLAGS := $(BOOT_JDK_SOURCETARGET) -XDignore.symbol.file=true -g \
+ FLAGS := \
+ $(JAVA_TOOL_FLAGS_SMALL) \
+ $(BOOT_JDK_SOURCETARGET) \
+ -XDignore.symbol.file=true -g \
-Xlint:all$(COMMA)-deprecation$(COMMA)-options -Werror, \
DISABLE_SJAVAC := true, \
))
--- a/nashorn/.hgtags Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/.hgtags Wed Oct 05 06:28:23 2016 -0700
@@ -371,3 +371,4 @@
cb00d5ef023a18a66fcb4311ed4474d4145c66e9 jdk-9+135
f11b8f5c4ccbf9c87d283815abac6c0117fba3c0 jdk-9+136
17ed43add2f9e3528686cd786ae2ed49c8ed36e9 jdk-9+137
+4a6ee1185fc821df063e4d1537fa7ad2ebe9eb02 jdk-9+138
--- a/nashorn/make/BuildNashorn.gmk Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/make/BuildNashorn.gmk Wed Oct 05 06:28:23 2016 -0700
@@ -26,7 +26,7 @@
# This must be the first rule
default: all
--include $(SPEC)
+include $(SPEC)
include MakeBase.gmk
include JarArchive.gmk
include JavaCompilation.gmk
@@ -42,7 +42,7 @@
# Need to use source and target 8 for nasgen to work.
$(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \
- JVM := $(JAVA), \
+ JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \
FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
--system none --module-source-path "$(MODULESOURCEPATH)", \
@@ -91,7 +91,7 @@
$(MKDIR) -p $(@D)
$(RM) -rf $(@D)/jdk $(@D)/netscape
$(CP) -R -p $(SUPPORT_OUTPUTDIR)/special_classes/jdk.scripting.nashorn/* $(@D)/
- $(JAVA) $(NASGEN_OPTIONS) \
+ $(JAVA_SMALL) $(NASGEN_OPTIONS) \
jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
$(TOUCH) $@
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 05 06:28:23 2016 -0700
@@ -2486,11 +2486,6 @@
}
@Override
- public boolean enterObjectNode(final ObjectNode objectNode) {
- return false;
- }
-
- @Override
public boolean enterDefault(final Node node) {
if (contains) {
return false;
@@ -2562,7 +2557,8 @@
oc = new FieldObjectCreator<Expression>(this, tuples) {
@Override
protected void loadValue(final Expression node, final Type type) {
- loadExpressionAsType(node, type);
+ // Use generic type in order to avoid conversion between object types
+ loadExpressionAsType(node, Type.generic(type));
}};
}
@@ -2578,10 +2574,7 @@
//handler
if (restOfProperty) {
final ContinuationInfo ci = getContinuationInfo();
- // Can be set at most once for a single rest-of method
- assert ci.getObjectLiteralMap() == null;
- ci.setObjectLiteralMap(oc.getMap());
- ci.setObjectLiteralStackDepth(method.getStackSize());
+ ci.setObjectLiteralMap(method.getStackSize(), oc.getMap());
}
method.dup();
@@ -5309,10 +5302,8 @@
private Type[] stackTypes;
// If non-null, this node should perform the requisite type conversion
private Type returnValueType;
- // If we are in the middle of an object literal initialization, we need to update the map
- private PropertyMap objectLiteralMap;
- // Object literal stack depth for object literal - not necessarily top if property is a tree
- private int objectLiteralStackDepth = -1;
+ // If we are in the middle of an object literal initialization, we need to update the property maps
+ private Map<Integer, PropertyMap> objectLiteralMaps;
// The line number at the continuation point
private int lineNumber;
// The active catch label, in case the continuation point is in a try/catch block
@@ -5364,20 +5355,15 @@
this.returnValueType = returnValueType;
}
- int getObjectLiteralStackDepth() {
- return objectLiteralStackDepth;
- }
-
- void setObjectLiteralStackDepth(final int objectLiteralStackDepth) {
- this.objectLiteralStackDepth = objectLiteralStackDepth;
- }
-
- PropertyMap getObjectLiteralMap() {
- return objectLiteralMap;
- }
-
- void setObjectLiteralMap(final PropertyMap objectLiteralMap) {
- this.objectLiteralMap = objectLiteralMap;
+ void setObjectLiteralMap(final int objectLiteralStackDepth, final PropertyMap objectLiteralMap) {
+ if (objectLiteralMaps == null) {
+ objectLiteralMaps = new HashMap<>();
+ }
+ objectLiteralMaps.put(objectLiteralStackDepth, objectLiteralMap);
+ }
+
+ PropertyMap getObjectLiteralMap(final int stackDepth) {
+ return objectLiteralMaps == null ? null : objectLiteralMaps.get(stackDepth);
}
@Override
@@ -5467,10 +5453,9 @@
final int[] stackStoreSpec = ci.getStackStoreSpec();
final Type[] stackTypes = ci.getStackTypes();
final boolean isStackEmpty = stackStoreSpec.length == 0;
- boolean replacedObjectLiteralMap = false;
+ int replacedObjectLiteralMaps = 0;
if(!isStackEmpty) {
// Load arguments on the stack
- final int objectLiteralStackDepth = ci.getObjectLiteralStackDepth();
for(int i = 0; i < stackStoreSpec.length; ++i) {
final int slot = stackStoreSpec[i];
method.load(lvarTypes.get(slot), slot);
@@ -5478,18 +5463,18 @@
// stack: s0=object literal being initialized
// change map of s0 so that the property we are initializing when we failed
// is now ci.returnValueType
- if (i == objectLiteralStackDepth) {
+ final PropertyMap map = ci.getObjectLiteralMap(i);
+ if (map != null) {
method.dup();
- assert ci.getObjectLiteralMap() != null;
assert ScriptObject.class.isAssignableFrom(method.peekType().getTypeClass()) : method.peekType().getTypeClass() + " is not a script object";
- loadConstant(ci.getObjectLiteralMap());
+ loadConstant(map);
method.invoke(ScriptObject.SET_MAP);
- replacedObjectLiteralMap = true;
+ replacedObjectLiteralMaps++;
}
}
}
- // Must have emitted the code for replacing the map of an object literal if we have a set object literal stack depth
- assert ci.getObjectLiteralStackDepth() == -1 || replacedObjectLiteralMap;
+ // Must have emitted the code for replacing all object literal maps
+ assert ci.objectLiteralMaps == null || ci.objectLiteralMaps.size() == replacedObjectLiteralMaps;
// Load RewriteException back.
method.load(rewriteExceptionType, lvarCount);
// Get rid of the stored reference
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Oct 05 06:28:23 2016 -0700
@@ -189,7 +189,8 @@
@Override
protected void loadValue(final Expression expr, final Type type) {
- codegen.loadExpressionAsType(expr, type);
+ // Use generic type in order to avoid conversion between object types
+ codegen.loadExpressionAsType(expr, Type.generic(type));
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Wed Oct 05 06:28:23 2016 -0700
@@ -473,22 +473,6 @@
}
@Override
- protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- if (overrides && super.hasOwnProperty(NashornCallSiteDescriptor.getOperand(desc))) {
- try {
- final GuardedInvocation inv = super.findCallMethodMethod(desc, request);
- if (inv != null) {
- return inv;
- }
- } catch (final Exception e) {
- //ignored
- }
- }
-
- return findHook(desc, __call__);
- }
-
- @Override
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (overrides && super.hasOwnProperty(name)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Oct 05 06:28:23 2016 -0700
@@ -80,7 +80,6 @@
import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
-import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -1883,8 +1882,6 @@
return findCallMethod(desc, request);
case NEW:
return findNewMethod(desc, request);
- case CALL_METHOD:
- return findCallMethodMethod(desc, request);
default:
}
return null;
@@ -1920,32 +1917,6 @@
}
/**
- * Find an implementation for a CALL_METHOD operation. Note that Nashorn internally never uses
- * CALL_METHOD, but instead always emits two call sites in bytecode, one for GET_METHOD, and then another
- * one for CALL. Explicit support for CALL_METHOD is provided for the benefit of potential external
- * callers. The implementation itself actually folds a GET_METHOD method handle into a CALL method handle.
- *
- * @param desc the call site descriptor.
- * @param request the link request
- *
- * @return GuardedInvocation to be invoked at call site.
- */
- protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- // R(P0, P1, ...)
- final MethodType callType = desc.getMethodType();
- // use type Object(P0) for the getter
- final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
- final GuardedInvocation getter = findGetMethod(getterType, request, StandardOperation.GET_METHOD);
-
- // Object(P0) => Object(P0, P1, ...)
- final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
- // R(Object, P0, P1, ...)
- final MethodHandle invoker = Bootstrap.createDynamicInvoker("", NashornCallSiteDescriptor.CALL, callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
- // Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
- return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
- }
-
- /**
* Test whether this object contains in its prototype chain or is itself a with-object.
* @return true if a with-object was found
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Wed Oct 05 06:28:23 2016 -0700
@@ -103,8 +103,6 @@
final String name = NashornCallSiteDescriptor.getOperand(desc);
final String msg = name != null? "not.a.function" : "cant.call.undefined";
throw typeError(msg, name);
- case CALL_METHOD:
- throw lookupTypeError("cant.read.property.of.undefined", desc);
case GET_PROPERTY:
case GET_ELEMENT:
case GET_METHOD:
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Fri Sep 30 02:52:42 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Oct 05 06:28:23 2016 -0700
@@ -86,13 +86,11 @@
private static final MethodHandle EMPTY_ELEM_SETTER =
MH.dropArguments(EMPTY_PROP_SETTER, 0, Object.class);
- private static final MethodHandle THROW_NO_SUCH_FUNCTION;
private static final MethodHandle THROW_STRICT_PROPERTY_SETTER;
private static final MethodHandle THROW_OPTIMISTIC_UNDEFINED;
static {
final Lookup lookup = new Lookup(MethodHandles.lookup());
- THROW_NO_SUCH_FUNCTION = lookup.findOwnStatic("throwNoSuchFunction", Object.class, Object.class, Object.class);
THROW_STRICT_PROPERTY_SETTER = lookup.findOwnStatic("throwStrictPropertySetter", void.class, Object.class, Object.class);
THROW_OPTIMISTIC_UNDEFINED = lookup.findOwnStatic("throwOptimisticUndefined", Object.class, int.class);
}
@@ -130,8 +128,6 @@
if (op != null) {
final String operand = NashornCallSiteDescriptor.getOperand(desc);
switch (op) {
- case CALL_METHOD:
- return adaptThrower(bindOperand(THROW_NO_SUCH_FUNCTION, operand), desc);
case GET_METHOD:
case GET_PROPERTY:
case GET_ELEMENT: {
@@ -172,11 +168,6 @@
}
@SuppressWarnings("unused")
- private static Object throwNoSuchFunction(final Object self, final Object name) {
- throw createTypeError(self, name, "no.such.function");
- }
-
- @SuppressWarnings("unused")
private static void throwStrictPropertySetter(final Object self, final Object name) {
throw createTypeError(self, name, "cant.set.property");
}
@@ -230,7 +221,6 @@
case NEW:
case CALL:
throw typeError("not.a.function", "null");
- case CALL_METHOD:
case GET_METHOD:
throw typeError("no.such.function", getArgument(linkRequest), "null");
case GET_PROPERTY:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8166902.js Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8166902: Nested object literal property maps not reset in optimistic recompilation
+ *
+ * @test
+ * @run
+ */
+
+var o = {
+ a: "A",
+ b: "B"
+};
+
+var m = {
+ x: { z: o.a },
+ y: o.b
+};
+
+Assert.assertEquals(m.x.z, "A");
+Assert.assertEquals(m.y, "B");
+