# HG changeset patch # User prr # Date 1476131508 25200 # Node ID 31882abda8b5af232c852a7e62866be58f7bef39 # Parent ef26c8e40f1e519a31c99e4d889acf081aa4b043# Parent 62969f0fb9c552255b52746df017c95644e1b8d0 Merge diff -r ef26c8e40f1e -r 31882abda8b5 .hgtags --- a/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -380,3 +380,4 @@ e384420383a5b79fa0012ebcb25d8f83cff7f777 jdk-9+135 1b4b5d01aa11edf24b6fadbe3d2f3e411e3b02cd jdk-9+136 9cb87c88ed851c0575b8ead753ea238ed5b544e9 jdk-9+137 +d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 .hgtags-top-repo --- a/.hgtags-top-repo Mon Oct 03 14:10:40 2016 -0700 +++ b/.hgtags-top-repo Mon Oct 10 13:31:48 2016 -0700 @@ -380,3 +380,4 @@ 82b94cb5f342319d2cda77f9fa59703ad7fde576 jdk-9+135 3ec350f5f32af249b59620d7e37b54bdcd77b233 jdk-9+136 d7f519b004254b19e384131d9f0d0e40e31a0fd3 jdk-9+137 +67c4388142bdf58aec8fefa4475faaa8a5d7380c jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 common/autoconf/buildjdk-spec.gmk.in --- a/common/autoconf/buildjdk-spec.gmk.in Mon Oct 03 14:10:40 2016 -0700 +++ b/common/autoconf/buildjdk-spec.gmk.in Mon Oct 10 13:31:48 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@ diff -r ef26c8e40f1e -r 31882abda8b5 common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Mon Oct 03 14:10:40 2016 -0700 +++ b/common/autoconf/generated-configure.sh Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 common/autoconf/lib-std.m4 --- a/common/autoconf/lib-std.m4 Mon Oct 03 14:10:40 2016 -0700 +++ b/common/autoconf/lib-std.m4 Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 corba/.hgtags --- a/corba/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/corba/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -380,3 +380,4 @@ 094d0db606db976045f594dba47d4593b715cc81 jdk-9+135 aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136 258cf18fa7fc59359b874f8743b7168dc48baf73 jdk-9+137 +27bb44be32076861a0951bcefb07a1d92509a4b6 jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 corba/make/gensrc/Gensrc-java.corba.gmk --- a/corba/make/gensrc/Gensrc-java.corba.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/corba/make/gensrc/Gensrc-java.corba.gmk Mon Oct 10 13:31:48 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 ################################################################################ diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/.hgtags --- a/hotspot/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -540,3 +540,4 @@ 3b1c4562953db47e36b237a500f368d5c9746d47 jdk-9+135 a20da289f646ee44440695b81abc0548330e4ca7 jdk-9+136 dfcbf839e299e7e2bba1da69bdb347617ea4c7e8 jdk-9+137 +fc0956308c7a586267c5dd35dff74f773aa9c3eb jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/make/lib/CompileGtest.gmk --- a/hotspot/make/lib/CompileGtest.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/make/lib/CompileGtest.gmk Mon Oct 10 13:31:48 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), \ diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/make/lib/CompileJvm.gmk --- a/hotspot/make/lib/CompileJvm.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/make/lib/CompileJvm.gmk Mon Oct 10 13:31:48 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), \ diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Mon Oct 10 13:31:48 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); } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Mon Oct 10 13:31:48 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); } } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Mon Oct 10 13:31:48 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* list = + new (ResourceObj::C_HEAP, mtModule) GrowableArray(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* list = - new (ResourceObj::C_HEAP, mtModule) GrowableArray(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* list = diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Oct 10 13:31:48 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(); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/klassFactory.cpp --- a/hotspot/src/share/vm/classfile/klassFactory.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/klassFactory.cpp Mon Oct 10 13:31:48 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* 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; } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/klassFactory.hpp --- a/hotspot/src/share/vm/classfile/klassFactory.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/klassFactory.hpp Mon Oct 10 13:31:48 2016 -0700 @@ -75,6 +75,12 @@ const InstanceKlass* host_klass, GrowableArray* 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/moduleEntry.cpp --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp Mon Oct 10 13:31:48 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(); } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/moduleEntry.hpp --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Mon Oct 10 13:31:48 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); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/modules.cpp --- a/hotspot/src/share/vm/classfile/modules.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/modules.cpp Mon Oct 10 13:31:48 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, diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/cms/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Mon Oct 10 13:31:48 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; diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Oct 10 13:31:48 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); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Mon Oct 10 13:31:48 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::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::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::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); } } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Mon Oct 10 13:31:48 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 void iterate(Fn fn); + template 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Mon Oct 10 13:31:48 2016 -0700 @@ -89,14 +89,28 @@ #undef check_mark +#ifndef PRODUCT template -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(obj); } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1OopClosures.hpp --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Mon Oct 10 13:31:48 2016 -0700 @@ -34,7 +34,6 @@ class G1ConcurrentMark; class DirtyCardToOopClosure; class G1CMBitMap; -class G1CMMarkStack; class G1ParScanThreadState; class G1CMTask; class ReferenceProcessor; diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Mon Oct 10 13:31:48 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; } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Mon Oct 10 13:31:48 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) { diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Oct 10 13:31:48 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, diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/heapRegionManager.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Mon Oct 10 13:31:48 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; } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/g1/heapRegionManager.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Mon Oct 10 13:31:48 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 { 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/shared/collectedHeap.hpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Mon Oct 10 13:31:48 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()); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/gc/shared/workgroup.hpp --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/allocation.hpp --- a/hotspot/src/share/vm/memory/allocation.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/allocation.hpp Mon Oct 10 13:31:48 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); }; diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/allocation.inline.hpp --- a/hotspot/src/share/vm/memory/allocation.inline.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Mon Oct 10 13:31:48 2016 -0700 @@ -153,6 +153,24 @@ } template +E* MmapArrayAllocator::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 E* MmapArrayAllocator::allocate(size_t length) { size_t size = size_for(length); int alignment = os::vm_allocation_granularity(); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/filemap.cpp --- a/hotspot/src/share/vm/memory/filemap.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/filemap.cpp Mon Oct 10 13:31:48 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"); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/filemap.hpp --- a/hotspot/src/share/vm/memory/filemap.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/filemap.hpp Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/metaspace.cpp --- a/hotspot/src/share/vm/memory/metaspace.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/metaspace.cpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/metaspaceShared.cpp --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Mon Oct 10 13:31:48 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 *_class_promote_order; VirtualSpace _md_vs; VirtualSpace _mc_vs; + VirtualSpace _od_vs; GrowableArray *_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(); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/memory/metaspaceShared.hpp --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Oct 10 13:31:48 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; }; diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/klass.cpp Mon Oct 10 13:31:48 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)); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/oop.hpp --- a/hotspot/src/share/vm/oops/oop.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/oop.hpp Mon Oct 10 13:31:48 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; diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Mon Oct 10 13:31:48 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()); } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/oops/typeArrayKlass.cpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Mon Oct 10 13:31:48 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 { diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/prims/unsafe.cpp --- a/hotspot/src/share/vm/prims/unsafe.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Mon Oct 10 13:31:48 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(v = *(volatile oop*) addr); } + ensure_satb_referent_alive(p, offset, v); + OrderAccess::acquire(); return JNIHandles::make_local(env, v); } UNSAFE_END diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Mon Oct 10 13:31:48 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") \ diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Mon Oct 10 13:31:48 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); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Mon Oct 10 13:31:48 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; } } diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Mon Oct 10 13:31:48 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, diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/utilities/debug.cpp --- a/hotspot/src/share/vm/utilities/debug.cpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/utilities/debug.cpp Mon Oct 10 13:31:48 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", diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/utilities/debug.hpp --- a/hotspot/src/share/vm/utilities/debug.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/utilities/debug.hpp Mon Oct 10 13:31:48 2016 -0700 @@ -271,7 +271,8 @@ SharedReadOnly, SharedReadWrite, SharedMiscData, - SharedMiscCode + SharedMiscCode, + SharedOptional }; void report_out_of_shared_space(SharedSpaceType space_type); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/src/share/vm/utilities/hashtable.inline.hpp --- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp Mon Oct 10 13:31:48 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 inline void HashtableBucket::set_entry(BasicHashtableEntry* 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 inline BasicHashtableEntry* HashtableBucket::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*) OrderAccess::load_ptr_acquire(&_entry); diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Mon Oct 03 14:10:40 2016 -0700 +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java Mon Oct 10 13:31:48 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); + } + } + } + +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java Mon Oct 10 13:31:48 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); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java Mon Oct 10 13:31:48 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); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java Mon Oct 10 13:31:48 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(); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java Mon Oct 10 13:31:48 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); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java Mon Oct 10 13:31:48 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; + } +} + diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java Mon Oct 10 13:31:48 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 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); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java Mon Oct 10 13:31:48 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. diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java Mon Oct 10 13:31:48 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); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java Mon Oct 10 13:31:48 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"); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java Mon Oct 10 13:31:48 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(); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/serviceability/jdwp/AllModulesCommandTest.java diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/serviceability/jdwp/JdwpCmd.java diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/testlibrary/jvmti/TransformUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jvmti/TransformUtil.java Mon Oct 10 13:31:48 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 from 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; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/testlibrary/jvmti/TransformerAgent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.java Mon Oct 10 13:31:48 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 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; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 hotspot/test/testlibrary/jvmti/TransformerAgent.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.mf Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Premain-Class: TransformerAgent +Agent-Class: TransformerAgent +Can-Retransform-Classes: true +Can-Redefine-Classes: false diff -r ef26c8e40f1e -r 31882abda8b5 jaxp/.hgtags --- a/jaxp/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/jaxp/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -380,3 +380,4 @@ f695240370c77a25fed88225a392e7d530cb4d78 jdk-9+135 f1eafcb0eb7182b937bc93f214d8cabd01ec4d59 jdk-9+136 a8d5fe567ae72b4931040e59dd4478363f9004f5 jdk-9+137 +69c3b12ba75b2e321dee731ac545e7fbff608451 jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 jaxws/.hgtags --- a/jaxws/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/jaxws/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -383,3 +383,4 @@ 22631824f55128a7ab6605493b3001a37af6a168 jdk-9+135 09ec13a99f50a4a346180d1e3b0fd8bc1ee399ce jdk-9+136 297c16d401c534cb879809d2a746d21ca99d2954 jdk-9+137 +7d3a8f52b124db26ba8425c2931b748dd9d2791b jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/.hgtags --- a/jdk/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -381,3 +381,4 @@ 54c5931849a33a363e03fdffa141503f5cc4779d jdk-9+136 e72df94364e3686e7d62059ce0d6b187b82da713 jdk-9+137 665096863382bf23ce891307cf2a7511e77c1c88 jdk-9+138 +5518ac2f2ead5e594bd983f2047178136aafdfd0 jdk-9+139 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/ASSEMBLY_EXCEPTION --- a/jdk/ASSEMBLY_EXCEPTION Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/ASSEMBLY_EXCEPTION Mon Oct 10 13:31:48 2016 -0700 @@ -1,27 +1,27 @@ OPENJDK ASSEMBLY EXCEPTION -The OpenJDK source code made available by Sun at openjdk.java.net and -openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the -GNU General Public License version 2 +The OpenJDK source code made available by Oracle America, Inc. (Oracle) at +openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU +General Public License version 2 only ("GPL2"), with the following clarification and special exception. Linking this OpenJDK Code statically or dynamically with other code is making a combined work based on this library. Thus, the terms and conditions of GPL2 cover the whole combination. - As a special exception, Sun gives you permission to link this - OpenJDK Code with certain code licensed by Sun as indicated at + As a special exception, Oracle gives you permission to link this + OpenJDK Code with certain code licensed by Oracle as indicated at http://openjdk.java.net/legal/exception-modules-2007-05-08.html ("Designated Exception Modules") to produce an executable, regardless of the license terms of the Designated Exception Modules, and to copy and distribute the resulting executable under GPL2, provided that the Designated Exception Modules continue to be - governed by the licenses under which they were offered by Sun. + governed by the licenses under which they were offered by Oracle. -As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to -build an executable that includes those portions of necessary code that Sun -could not provide under GPL2 (or that Sun has provided under GPL2 with the -Classpath exception). If you modify or add to the OpenJDK code, that new -GPL2 code may still be combined with Designated Exception Modules if the -new code is made subject to this exception by its copyright holder. +As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code +to build an executable that includes those portions of necessary code that +Oracle could not provide under GPL2 (or that Oracle has provided under GPL2 +with the Classpath exception). If you modify or add to the OpenJDK code, +that new GPL2 code may still be combined with Designated Exception Modules +if the new code is made subject to this exception by its copyright holder. diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/CompileDemos.gmk --- a/jdk/make/CompileDemos.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/CompileDemos.gmk Mon Oct 10 13:31:48 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) diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/CompileModuleTools.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/CompileModuleTools.gmk Mon Oct 10 13:31:48 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 \ +)) diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/Import.gmk --- a/jdk/make/Import.gmk Mon Oct 03 14:10:40 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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/ModuleTools.gmk --- a/jdk/make/ModuleTools.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/ModuleTools.gmk Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/VERSION --- a/jdk/make/data/tzdata/VERSION Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/VERSION Mon Oct 10 13:31:48 2016 -0700 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016f +tzdata2016g diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/africa --- a/jdk/make/data/tzdata/africa Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/africa Mon Oct 10 13:31:48 2016 -0700 @@ -487,7 +487,7 @@ # http://www.libyaherald.com/2013/10/24/correction-no-time-change-tomorrow/ # # From Paul Eggert (2013-10-25): -# For now, assume they're reverting to the pre-2012 rules of permanent UTC+2. +# For now, assume they're reverting to the pre-2012 rules of permanent UT +02. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Libya 1951 only - Oct 14 2:00 1:00 S diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/antarctica --- a/jdk/make/data/tzdata/antarctica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/antarctica Mon Oct 10 13:31:48 2016 -0700 @@ -33,9 +33,7 @@ # http://www.spri.cam.ac.uk/bob/periant.htm # for information. # Unless otherwise specified, we have no time zone information. -# -# Except for the French entries, -# I made up all time zone abbreviations mentioned here; corrections welcome! + # FORMAT is '-00' and GMTOFF is 0 for locations while uninhabited. # Argentina - year-round bases @@ -52,7 +50,7 @@ # previously sealers and scientific personnel wintered # Margaret Turner reports # http://web.archive.org/web/20021204222245/http://www.dstc.qut.edu.au/DST/marg/daylight.html -# (1999-09-30) that they're UTC+5, with no DST; +# (1999-09-30) that they're UT +05, with no DST; # presumably this is when they have visitors. # # year-round bases @@ -91,23 +89,22 @@ # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 - 8:00 - AWST 2009 Oct 18 2:00 - # Australian Western Std Time - 11:00 - CAST 2010 Mar 5 2:00 # Casey Time - 8:00 - AWST 2011 Oct 28 2:00 - 11:00 - CAST 2012 Feb 21 17:00u - 8:00 - AWST + 8:00 - +08 2009 Oct 18 2:00 + 11:00 - +11 2010 Mar 5 2:00 + 8:00 - +08 2011 Oct 28 2:00 + 11:00 - +11 2012 Feb 21 17:00u + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 - 7:00 - DAVT 1964 Nov # Davis Time + 7:00 - +07 1964 Nov 0 - -00 1969 Feb - 7:00 - DAVT 2009 Oct 18 2:00 - 5:00 - DAVT 2010 Mar 10 20:00u - 7:00 - DAVT 2011 Oct 28 2:00 - 5:00 - DAVT 2012 Feb 21 20:00u - 7:00 - DAVT + 7:00 - +07 2009 Oct 18 2:00 + 5:00 - +05 2010 Mar 10 20:00u + 7:00 - +07 2011 Oct 28 2:00 + 5:00 - +05 2012 Feb 21 20:00u + 7:00 - +07 Zone Antarctica/Mawson 0 - -00 1954 Feb 13 - 6:00 - MAWT 2009 Oct 18 2:00 # Mawson Time - 5:00 - MAWT + 6:00 - +06 2009 Oct 18 2:00 + 5:00 - +05 # References: # Casey Weather (1998-02-26) # http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html @@ -161,7 +158,7 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français - 5:00 - TFT # ISO code TF Time + 5:00 - +05 # # year-round base in the main continent # Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11 @@ -172,9 +169,9 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/DumontDUrville 0 - -00 1947 - 10:00 - PMT 1952 Jan 14 # Port-Martin Time + 10:00 - +10 1952 Jan 14 0 - -00 1956 Nov - 10:00 - DDUT # Dumont-d'Urville Time + 10:00 - +10 # France & Italy - year-round base # Concordia, -750600+1232000, since 2005 @@ -200,7 +197,7 @@ # station of Japan, it's appropriate for the principal location. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Syowa 0 - -00 1957 Jan 29 - 3:00 - SYOT # Syowa Time + 3:00 - +03 # See: # NIPR Antarctic Research Activities (1999-08-17) # http://www.nipr.ac.jp/english/ara01.html @@ -237,17 +234,17 @@ # correct, but they should be quite close to the actual dates. # # From Paul Eggert (2014-03-21): -# The CET-switching Troll rules require zic from tzcode 2014b or later, so as +# The CET-switching Troll rules require zic from tz 2014b or later, so as # suggested by Bengt-Inge Larsson comment them out for now, and approximate # with only UTC and CEST. Uncomment them when 2014b is more prevalent. # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -#Rule Troll 2005 max - Mar 1 1:00u 1:00 CET -Rule Troll 2005 max - Mar lastSun 1:00u 2:00 CEST -#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 CET -#Rule Troll 2004 max - Nov 7 1:00u 0:00 UTC +#Rule Troll 2005 max - Mar 1 1:00u 1:00 +01 +Rule Troll 2005 max - Mar lastSun 1:00u 2:00 +02 +#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 +01 +#Rule Troll 2004 max - Nov 7 1:00u 0:00 +00 # Remove the following line when uncommenting the above '#Rule' lines. -Rule Troll 2004 max - Oct lastSun 1:00u 0:00 UTC +Rule Troll 2004 max - Oct lastSun 1:00u 0:00 +00 # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Troll 0 - -00 2005 Feb 12 0:00 Troll %s @@ -288,10 +285,10 @@ # changes during the year and does not necessarily correspond to mean # solar noon. So the Vostok time might have been whatever the clocks # happened to be during their visit. So we still don't really know what time -# it is at Vostok. But we'll guess UTC+6. +# it is at Vostok. But we'll guess +06. # Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 6:00 - VOST # Vostok time + 6:00 - +06 # S Africa - year-round bases # Marion Island, -4653+03752 @@ -324,7 +321,7 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Rothera 0 - -00 1976 Dec 1 - -3:00 - ROTT # Rothera time + -3:00 - -03 # Uruguay - year round base # Artigas, King George Island, -621104-0585107 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/asia --- a/jdk/make/data/tzdata/asia Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/asia Mon Oct 10 13:31:48 2016 -0700 @@ -139,13 +139,11 @@ # http://www.worldtimezone.com/dst_news/dst_news_armenia03.html # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2 - 3:00 - YERT 1957 Mar # Yerevan Time - 4:00 RussiaAsia YER%sT 1991 Mar 31 2:00s - 3:00 1:00 YERST 1991 Sep 23 # independence - 3:00 RussiaAsia AM%sT 1995 Sep 24 2:00s - 4:00 - AMT 1997 - 4:00 RussiaAsia AM%sT 2012 Feb 9 - 4:00 - AMT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s + 4:00 - +04 1997 + 4:00 RussiaAsia +04/+05 # Azerbaijan @@ -166,13 +164,12 @@ Rule Azer 1997 2015 - Oct lastSun 5:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Baku 3:19:24 - LMT 1924 May 2 - 3:00 - BAKT 1957 Mar # Baku Time - 4:00 RussiaAsia BAK%sT 1991 Mar 31 2:00s - 3:00 1:00 BAKST 1991 Aug 30 # independence - 3:00 RussiaAsia AZ%sT 1992 Sep lastSun 2:00s - 4:00 - AZT 1996 # Azerbaijan Time - 4:00 EUAsia AZ%sT 1997 - 4:00 Azer AZ%sT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s + 4:00 - +04 1996 + 4:00 EUAsia +04/+05 1997 + 4:00 Azer +04/+05 # Bahrain # See Asia/Qatar. @@ -291,7 +288,7 @@ # Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon. # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Asia/Rangoon 6:24:40 - LMT 1880 # or Yangon +Zone Asia/Yangon 6:24:40 - LMT 1880 # or Rangoon 6:24:40 - RMT 1920 # Rangoon Mean Time? 6:30 - BURT 1942 May # Burma Time 9:00 - JST 1945 May 3 @@ -406,7 +403,7 @@ # Lewiston (ME) Daily Sun (1939-05-29), p 17, said "Even the time is # different - the occupied districts going by Tokyo time, an hour # ahead of that prevailing in the rest of Shanghai." Guess that the -# Xujiahui Observatory was under French control and stuck with UT+8. +# Xujiahui Observatory was under French control and stuck with UT +08. # # In earlier versions of this file, China had many separate Zone entries, but # this was based on what were apparently incorrect data in Shanks & Pottenger. @@ -415,26 +412,26 @@ # Proposed in 1918 and theoretically in effect until 1949 (although in practice # mainly observed in coastal areas), the five zones were: # -# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT+8.5 +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT +08:30 # Asia/Harbin (currently a link to Asia/Shanghai) # Heilongjiang (except Mohe county), Jilin # -# Zhongyuan Time ("Central plain Time") UT+8 +# Zhongyuan Time ("Central plain Time") UT +08 # Asia/Shanghai # most of China # This currently represents most other zones as well, # as apparently these regions have been the same since 1970. # Milne gives 8:05:43.2 for Xujiahui Observatory time; round to nearest. -# Guo says Shanghai switched to UT+8 "from the end of the 19th century". +# Guo says Shanghai switched to UT +08 "from the end of the 19th century". # -# Long-shu Time (probably due to Long and Shu being two names of that area) UT+7 +# Long-shu Time (probably due to Long and Shu being two names of the area) UT +07 # Asia/Chongqing (currently a link to Asia/Shanghai) # Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan; # most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong # counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing, # Yangchun, Yangjiang, Yu'nan, and Yunfu. # -# Xin-zang Time ("Xinjiang-Tibet Time") UT+6 +# Xin-zang Time ("Xinjiang-Tibet Time") UT +06 # Asia/Urumqi # This currently represents Kunlun Time as well, # as apparently the two regions have been the same since 1970. @@ -447,7 +444,7 @@ # Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami, # Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan. # -# Kunlun Time UT+5.5 +# Kunlun Time UT +05:30 # Asia/Kashgar (currently a link to Asia/Urumqi) # West Tibet, including Pulan, Aheqi, Shufu, Shule; # West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke, @@ -463,7 +460,7 @@ # # On the other hand, ethnic Uyghurs, who make up about half the # population of Xinjiang, typically use "Xinjiang time" which is two -# hours behind Beijing time, or UTC +0600. The government of the Xinjiang +# hours behind Beijing time, or UT +06. The government of the Xinjiang # Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as # local governments such as the Ürümqi city government use both times in # publications, referring to what is popularly called Xinjiang time as @@ -519,8 +516,8 @@ # having the same time as Beijing. # From Paul Eggert (2014-06-30): -# In the early days of the PRC, Tibet was given its own time zone (UT+6) but -# this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, +# In the early days of the PRC, Tibet was given its own time zone (UT +06) +# but this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, # Memories of life in Lhasa under Chinese Rule, Columbia U Press, ISBN # 978-0231142861 (2008), translator's introduction by Matthew Akester, p x. # As this is before our 1970 cutoff, Tibet doesn't need a separate zone. @@ -534,12 +531,12 @@ # Republics, the Soviet Union, the Kuomintang, and the People's Republic of # China, and tracking down all these organizations' timekeeping rules would be # quite a trick. Approximate this lost history by a transition from LMT to -# XJT at the start of 1928, the year of accession of the warlord Jin Shuren, +# UT +06 at the start of 1928, the year of accession of the warlord Jin Shuren, # which happens to be the date given by Shanks & Pottenger (no doubt as a -# guess) as the transition from LMT. Ignore the usage of UT+8 before -# 1986-02-01 under the theory that the transition date to UT+8 is unknown and +# guess) as the transition from LMT. Ignore the usage of +08 before +# 1986-02-01 under the theory that the transition date to +08 is unknown and # that the sort of users who prefer Asia/Urumqi now typically ignored the -# UT+8 mandate back then. +# +08 mandate back then. # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Beijing time, used throughout China; represented by Shanghai. @@ -744,7 +741,7 @@ # be found from historical government announcement database. # From Paul Eggert (2014-07-03): -# As per Yu-Cheng Chuang, say that Taiwan was at UT+9 from 1937-10-01 +# As per Yu-Cheng Chuang, say that Taiwan was at UT +09 from 1937-10-01 # until 1945-09-21 at 01:00, overriding Shanks & Pottenger. # Likewise, use Yu-Cheng Chuang's data for DST in Taiwan. @@ -858,16 +855,15 @@ # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Tbilisi 2:59:11 - LMT 1880 2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time - 3:00 - TBIT 1957 Mar # Tbilisi Time - 4:00 RussiaAsia TBI%sT 1991 Mar 31 2:00s - 3:00 1:00 TBIST 1991 Apr 9 # independence - 3:00 RussiaAsia GE%sT 1992 # Georgia Time - 3:00 E-EurAsia GE%sT 1994 Sep lastSun - 4:00 E-EurAsia GE%sT 1996 Oct lastSun - 4:00 1:00 GEST 1997 Mar lastSun - 4:00 E-EurAsia GE%sT 2004 Jun 27 - 3:00 RussiaAsia GE%sT 2005 Mar lastSun 2:00 - 4:00 - GET + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 + 3:00 E-EurAsia +03/+04 1994 Sep lastSun + 4:00 E-EurAsia +04/+05 1996 Oct lastSun + 4:00 1:00 +05 1997 Mar lastSun + 4:00 E-EurAsia +04/+05 2004 Jun 27 + 3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00 + 4:00 - +04 # East Timor @@ -944,7 +940,7 @@ # These would be the earliest possible times for a change. # Régimes horaires pour le monde entier, by Henri Le Corre, (Éditions # Traditionnelles, 1987, Paris) says that Java and Madura switched -# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura +# from UT +09 to +07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura # (Hollandia). For now, assume all Indonesian locations other than Jayapura # switched on 1945-09-23. # @@ -955,11 +951,11 @@ # summary published by the Time and Frequency Laboratory of the # Research Center for Calibration, Instrumentation and Metrology, # Indonesia, (2006-09-29). -# The abbreviations are: +# The time zone abbreviations and UT offsets are: # -# WIB - UTC+7 - Waktu Indonesia Barat (Indonesia western time) -# WITA - UTC+8 - Waktu Indonesia Tengah (Indonesia central time) -# WIT - UTC+9 - Waktu Indonesia Timur (Indonesia eastern time) +# WIB - +07 - Waktu Indonesia Barat (Indonesia western time) +# WITA - +08 - Waktu Indonesia Tengah (Indonesia central time) +# WIT - +09 - Waktu Indonesia Timur (Indonesia eastern time) # # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Java, Sumatra @@ -1848,11 +1844,11 @@ Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2 - 5:00 - FRUT 1930 Jun 21 # Frunze Time - 6:00 RussiaAsia FRU%sT 1991 Mar 31 2:00s - 5:00 1:00 FRUST 1991 Aug 31 2:00 # independence - 5:00 Kyrgyz KG%sT 2005 Aug 12 # Kyrgyzstan Time - 6:00 - KGT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 RussiaAsia +05/+06 1991 Aug 31 2:00 + 5:00 Kyrgyz +05/+06 2005 Aug 12 + 6:00 - +06 ############################################################################### @@ -1891,25 +1887,24 @@ Rule ROK 1987 1988 - May Sun>=8 2:00 1:00 D Rule ROK 1987 1988 - Oct Sun>=8 3:00 0 S -# From Paul Eggert (2014-10-30): +# From Paul Eggert (2016-08-23): # The Korean Wikipedia entry gives the following sources for UT offsets: # -# 1908: Official Journal Article No. 3994 (Edict No. 5) +# 1908: Official Journal Article No. 3994 (decree No. 5) # 1912: Governor-General of Korea Official Gazette Issue No. 367 # (Announcement No. 338) # 1954: Presidential Decree No. 876 (1954-03-17) # 1961: Law No. 676 (1961-08-07) -# 1987: Law No. 3919 (1986-12-31) # -# The Wikipedia entry also has confusing information about a change -# to UT+9 in April 1910, but then what would be the point of the later change -# to UT+9 on 1912-01-01? Omit the 1910 change for now. +# (Another source "1987: Law No. 3919 (1986-12-31)" was in the 2014-10-30 +# edition of the Korean Wikipedia entry.) # # I guessed that time zone abbreviations through 1945 followed the same # rules as discussed under Taiwan, with nominal switches from JST to KST # when the respective cities were taken over by the Allies after WWII. # -# For Pyongyang we have no information; guess no changes since World War II. +# For Pyongyang, guess no changes from World War II until 2015, as we +# have no information otherwise. # From Steffen Thorsen (2015-08-07): # According to many news sources, North Korea is going to change to @@ -2069,7 +2064,7 @@ # Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says # there is only one time zone and that DST is observed, citing Microsoft # Windows XP as the source. Risto Nykänen (2005-05-16) reports that -# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST. +# travelmongolia.org says there are two time zones (UT +07, +08) with no DST. # Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in # Washington, DC says there are two time zones, with DST observed. # He also found @@ -2705,7 +2700,7 @@ # earlier date. # # Shanks & Pottenger also state that until 1968-05-01 Saudi Arabia had two -# time zones; the other zone, at UTC+4, was in the far eastern part of +# time zones; the other zone, at UT +04, was in the far eastern part of # the country. Ignore this, as it's before our 1970 cutoff. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2974,10 +2969,10 @@ # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 - 5:00 - DUST 1930 Jun 21 # Dushanbe Time - 6:00 RussiaAsia DUS%sT 1991 Mar 31 2:00s - 5:00 1:00 DUSST 1991 Sep 9 2:00s - 5:00 - TJT # Tajikistan Time + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 1:00 +05/+06 1991 Sep 9 2:00s + 5:00 - +05 # Thailand # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2991,11 +2986,10 @@ # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad - 4:00 - ASHT 1930 Jun 21 # Ashkhabad Time - 5:00 RussiaAsia ASH%sT 1991 Mar 31 2:00 - 4:00 RussiaAsia ASH%sT 1991 Oct 27 # independence - 4:00 RussiaAsia TM%sT 1992 Jan 19 2:00 - 5:00 - TMT + 4:00 - +04 1930 Jun 21 + 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00 + 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 + 5:00 - +05 # United Arab Emirates # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -3007,20 +3001,18 @@ # Byalokoz 1919 says Uzbekistan was 4:27:53. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2 - 4:00 - SAMT 1930 Jun 21 # Samarkand Time - 5:00 - SAMT 1981 Apr 1 - 5:00 1:00 SAMST 1981 Oct 1 - 6:00 - TAST 1982 Apr 1 # Tashkent Time - 5:00 RussiaAsia SAM%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 4:00 - +04 1930 Jun 21 + 5:00 - +05 1981 Apr 1 + 5:00 1:00 +06 1981 Oct 1 + 6:00 - +06 1982 Apr 1 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Milne says Tashkent was 4:37:10.8; round to nearest. Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 - 5:00 - TAST 1930 Jun 21 # Tashkent Time - 6:00 RussiaAsia TAS%sT 1991 Mar 31 2:00 - 5:00 RussiaAsia TAS%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Vietnam diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/australasia --- a/jdk/make/data/tzdata/australasia Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/australasia Mon Oct 10 13:31:48 2016 -0700 @@ -568,7 +568,7 @@ # Base the Bougainville entry on the Arawa-Kieta region, which appears to have # the most people even though it was devastated in the Bougainville Civil War. # -# Although Shanks gives 1942-03-15 / 1943-11-01 for JST, these dates +# Although Shanks gives 1942-03-15 / 1943-11-01 for UT +09, these dates # are apparently rough guesswork from the starts of military campaigns. # The World War II entries below are instead based on Arawa-Kieta. # The Japanese occupied Kieta in July 1942, @@ -576,8 +576,8 @@ # http://pwencycl.kgbudge.com/B/o/Bougainville.htm # and seem to have controlled it until their 1945-08-21 surrender. # -# The Autonomous Region of Bougainville plans to switch from UTC+10 to UTC+11 -# on 2014-12-28 at 02:00. They call UTC+11 "Bougainville Standard Time"; +# The Autonomous Region of Bougainville switched from UT +10 to +11 +# on 2014-12-28 at 02:00. They call +11 "Bougainville Standard Time"; # abbreviate this as BST. See: # http://www.bougainville24.com/bougainville-issues/bougainville-gets-own-timezone/ # @@ -643,7 +643,7 @@ # From Paul Eggert (2014-06-27): # The International Date Line Act 2011 # http://www.parliament.gov.ws/images/ACTS/International_Date_Line_Act__2011_-_Eng.pdf -# changed Samoa from UTC-11 to UTC+13, effective "12 o'clock midnight, on +# changed Samoa from UT -11 to +13, effective "12 o'clock midnight, on # Thursday 29th December 2011". The International Date Line was adjusted # accordingly. @@ -738,7 +738,7 @@ # 1886-1891; Baker was similar but exact dates are not known. # Inhabited by civilians 1935-1942; U.S. military bases 1943-1944; # uninhabited thereafter. -# Howland observed Hawaii Standard Time (UT-10:30) in 1937; +# Howland observed Hawaii Standard Time (UT -10:30) in 1937; # see page 206 of Elgen M. Long and Marie K. Long, # Amelia Earhart: the Mystery Solved, Simon & Schuster (2000). # So most likely Howland and Baker observed Hawaii Time from 1935 @@ -1496,7 +1496,7 @@ # Zealand time. I understand that is the time they keep locally, anyhow." # For now, assume this practice goes back to the introduction of standard time # in New Zealand, as this would make Chatham Islands time almost exactly match -# LMT back when New Zealand was at UTC+11:30; also, assume Chatham Islands did +# LMT back when New Zealand was at UT +11:30; also, assume Chatham Islands did # not observe New Zealand's prewar DST. ############################################################################### @@ -1552,7 +1552,7 @@ # For now, we assume the Ladrones switched at the same time as the Philippines; # see Asia/Manila. -# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time, +# US Public Law 106-564 (2000-12-23) made UT +10 the official standard time, # under the name "Chamorro Standard Time". There is no official abbreviation, # but Congressman Robert A. Underwood, author of the bill that became law, # wrote in a press release (2000-12-27) that he will seek the use of "ChST". @@ -1564,15 +1564,15 @@ # "I am certain, having lived there for the past decade, that 'Truk' # (now properly known as Chuuk) ... is in the time zone GMT+10." # -# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11 +# Shanks & Pottenger write that Truk switched from UT +10 to +11 # on 1978-10-01; ignore this for now. # From Paul Eggert (1999-10-29): # The Federated States of Micronesia Visitors Board writes in # The Federated States of Micronesia - Visitor Information (1999-01-26) # http://www.fsmgov.org/info/clocks.html -# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11. -# We don't know when Kosrae switched from UTC+12; assume January 1 for now. +# that Truk and Yap are UT +10, and Ponape and Kosrae are +11. +# We don't know when Kosrae switched from +12; assume January 1 for now. # Midway @@ -1638,11 +1638,11 @@ # ordaining - by a masterpiece of diplomatic flattery - that # the Fourth of July should be celebrated twice in that year." -# Although Shanks & Pottenger says they both switched to UTC-11:30 -# in 1911, and to UTC-11 in 1950. many earlier sources give UTC-11 +# Although Shanks & Pottenger says they both switched to UT -11:30 +# in 1911, and to -11 in 1950. many earlier sources give -11 # for American Samoa, e.g., the US National Bureau of Standards # circular "Standard Time Throughout the World", 1932. -# Assume American Samoa switched to UTC-11 in 1911, not 1950, +# Assume American Samoa switched to -11 in 1911, not 1950, # and that after 1950 they agreed until (western) Samoa skipped a # day in 2011. Assume also that the Samoas follow the US and New # Zealand's "ST"/"DT" style of daylight-saving abbreviations. diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/backward --- a/jdk/make/data/tzdata/backward Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/backward Mon Oct 10 13:31:48 2016 -0700 @@ -59,6 +59,7 @@ Link Asia/Urumqi Asia/Kashgar Link Asia/Kathmandu Asia/Katmandu Link Asia/Macau Asia/Macao +Link Asia/Yangon Asia/Rangoon Link Asia/Ho_Chi_Minh Asia/Saigon Link Asia/Jerusalem Asia/Tel_Aviv Link Asia/Thimphu Asia/Thimbu diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/etcetera --- a/jdk/make/data/tzdata/etcetera Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/etcetera Mon Oct 10 13:31:48 2016 -0700 @@ -31,6 +31,13 @@ # need now for the entries that are not on UTC are for ships at sea # that cannot use POSIX TZ settings. +# Starting with POSIX 1003.1-2001, the entries below are all +# unnecessary as settings for the TZ environment variable. E.g., +# instead of TZ='Etc/GMT+4' one can use the POSIX setting TZ='<-04>+4'. +# +# Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours +# behind GMT but uses the completely misleading abbreviation "GMT". + Zone Etc/GMT 0 - GMT Zone Etc/UTC 0 - UTC Zone Etc/UCT 0 - UCT @@ -49,23 +56,13 @@ Link Etc/GMT Etc/GMT+0 Link Etc/GMT Etc/GMT0 -# We use POSIX-style signs in the Zone names and the output abbreviations, +# Be consistent with POSIX TZ settings in the Zone names, # even though this is the opposite of what many people expect. # POSIX has positive signs west of Greenwich, but many people expect # positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses -# the abbreviation "GMT+4" and corresponds to 4 hours behind UT +# the abbreviation "-04" and corresponds to 4 hours behind UT # (i.e. west of Greenwich) even though many people would expect it to # mean 4 hours ahead of UT (i.e. east of Greenwich). -# -# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for -# TZ='+4'; if you want time zone abbreviations conforming to -# ISO 8601 you can use TZ='<-0400>+4'. Thus the commonly-expected -# offset is kept within the angle bracket (and is used for display) -# while the POSIX sign is kept outside the angle bracket (and is used -# for calculation). -# -# Do not use a TZ setting like TZ='GMT+4', which is four hours behind -# GMT but uses the completely misleading abbreviation "GMT". # Earlier incarnations of this package were not POSIX-compliant, # and had lines such as @@ -74,30 +71,31 @@ # way does a # zic -l GMT-12 # so we moved the names into the Etc subdirectory. +# Also, the time zone abbreviations are now compatible with %z. -Zone Etc/GMT-14 14 - GMT-14 # 14 hours ahead of GMT -Zone Etc/GMT-13 13 - GMT-13 -Zone Etc/GMT-12 12 - GMT-12 -Zone Etc/GMT-11 11 - GMT-11 -Zone Etc/GMT-10 10 - GMT-10 -Zone Etc/GMT-9 9 - GMT-9 -Zone Etc/GMT-8 8 - GMT-8 -Zone Etc/GMT-7 7 - GMT-7 -Zone Etc/GMT-6 6 - GMT-6 -Zone Etc/GMT-5 5 - GMT-5 -Zone Etc/GMT-4 4 - GMT-4 -Zone Etc/GMT-3 3 - GMT-3 -Zone Etc/GMT-2 2 - GMT-2 -Zone Etc/GMT-1 1 - GMT-1 -Zone Etc/GMT+1 -1 - GMT+1 -Zone Etc/GMT+2 -2 - GMT+2 -Zone Etc/GMT+3 -3 - GMT+3 -Zone Etc/GMT+4 -4 - GMT+4 -Zone Etc/GMT+5 -5 - GMT+5 -Zone Etc/GMT+6 -6 - GMT+6 -Zone Etc/GMT+7 -7 - GMT+7 -Zone Etc/GMT+8 -8 - GMT+8 -Zone Etc/GMT+9 -9 - GMT+9 -Zone Etc/GMT+10 -10 - GMT+10 -Zone Etc/GMT+11 -11 - GMT+11 -Zone Etc/GMT+12 -12 - GMT+12 +Zone Etc/GMT-14 14 - +14 +Zone Etc/GMT-13 13 - +13 +Zone Etc/GMT-12 12 - +12 +Zone Etc/GMT-11 11 - +11 +Zone Etc/GMT-10 10 - +10 +Zone Etc/GMT-9 9 - +09 +Zone Etc/GMT-8 8 - +08 +Zone Etc/GMT-7 7 - +07 +Zone Etc/GMT-6 6 - +06 +Zone Etc/GMT-5 5 - +05 +Zone Etc/GMT-4 4 - +04 +Zone Etc/GMT-3 3 - +03 +Zone Etc/GMT-2 2 - +02 +Zone Etc/GMT-1 1 - +01 +Zone Etc/GMT+1 -1 - -01 +Zone Etc/GMT+2 -2 - -02 +Zone Etc/GMT+3 -3 - -03 +Zone Etc/GMT+4 -4 - -04 +Zone Etc/GMT+5 -5 - -05 +Zone Etc/GMT+6 -6 - -06 +Zone Etc/GMT+7 -7 - -07 +Zone Etc/GMT+8 -8 - -08 +Zone Etc/GMT+9 -9 - -09 +Zone Etc/GMT+10 -10 - -10 +Zone Etc/GMT+11 -11 - -11 +Zone Etc/GMT+12 -12 - -12 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/europe --- a/jdk/make/data/tzdata/europe Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/europe Mon Oct 10 13:31:48 2016 -0700 @@ -98,8 +98,7 @@ # 1:00 CET CEST CEMT Central Europe # 1:00:14 SET Swedish (1879-1899)* # 2:00 EET EEST Eastern Europe -# 3:00 FET Further-eastern Europe (2011-2014)* -# 3:00 MSK MSD MSM* Minsk, Moscow +# 3:00 MSK MSD Moscow # From Peter Ilieve (1994-12-04), # The original six [EU members]: Belgium, France, (West) Germany, Italy, @@ -606,16 +605,33 @@ Rule E-Eur 1981 max - Mar lastSun 0:00 1:00 S Rule E-Eur 1996 max - Oct lastSun 0:00 0 - + +# Daylight saving time for Russia and the Soviet Union +# +# The 1917-1921 decree URLs are from Alexander Belopolsky (2016-08-23). + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Russia 1917 only - Jul 1 23:00 1:00 MST # Moscow Summer Time +# +# Decree No. 142 (1917-12-22) http://istmat.info/node/28137 Rule Russia 1917 only - Dec 28 0:00 0 MMT # Moscow Mean Time +# +# Decree No. 497 (1918-05-30) http://istmat.info/node/30001 Rule Russia 1918 only - May 31 22:00 2:00 MDST # Moscow Double Summer Time Rule Russia 1918 only - Sep 16 1:00 1:00 MST +# +# Decree No. 258 (1919-05-29) http://istmat.info/node/37949 Rule Russia 1919 only - May 31 23:00 2:00 MDST -Rule Russia 1919 only - Jul 1 2:00 1:00 MSD +# +Rule Russia 1919 only - Jul 1 0:00u 1:00 MSD Rule Russia 1919 only - Aug 16 0:00 0 MSK +# +# Decree No. 63 (1921-02-03) http://istmat.info/node/45840 Rule Russia 1921 only - Feb 14 23:00 1:00 MSD -Rule Russia 1921 only - Mar 20 23:00 2:00 MSM # Midsummer +# +# Decree No. 121 (1921-03-07) http://istmat.info/node/45949 +Rule Russia 1921 only - Mar 20 23:00 2:00 +05 +# Rule Russia 1921 only - Sep 1 0:00 1:00 MSD Rule Russia 1921 only - Oct 1 0:00 0 - # Act No. 925 of the Council of Ministers of the USSR (1980-10-24): @@ -798,8 +814,6 @@ # From Alexander Bokovoy (2014-10-09): # Belarussian government decided against changing to winter time.... # http://eng.belta.by/all_news/society/Belarus-decides-against-adjusting-time-in-Russias-wake_i_76335.html -# From Paul Eggert (2014-10-08): -# Hence Belarus can share time zone abbreviations with Moscow again. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Minsk 1:50:16 - LMT 1880 @@ -810,8 +824,7 @@ 3:00 Russia MSK/MSD 1990 3:00 - MSK 1991 Mar 31 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 1:00s - 3:00 - MSK + 3:00 - +03 # Belgium # @@ -1319,7 +1332,7 @@ # http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf # says that Bersarin issued an order to use Moscow time on May 20. # However, Moscow did not observe daylight saving in 1945, so -# this was equivalent to CEMT (GMT+3), not GMT+4. +# this was equivalent to UT +03, not +04. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S @@ -2283,7 +2296,6 @@ # http://www.worldtimezone.com/dst_news/dst_news_russia-map-2014-07.html # From Paul Eggert (2006-03-22): -# Except for Moscow after 1919-07-01, I invented the time zone abbreviations. # Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991, # are from Andrey A. Chernov. The rest is from Shanks & Pottenger, # except we follow Chernov's report that 1992 DST transitions were Sat @@ -2359,7 +2371,7 @@ 2:00 Poland CE%sT 1946 3:00 Russia MSK/MSD 1989 Mar 26 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 2:00s + 3:00 - +03 2014 Oct 26 2:00s 2:00 - EET @@ -2412,6 +2424,16 @@ # 78 RU-SPE Saint Petersburg # 83 RU-NEN Nenets Autonomous Okrug +# From Paul Eggert (2016-08-23): +# The Soviets switched to UT-based time in 1919. Decree No. 59 +# (1919-02-08) http://istmat.info/node/35567 established UT-based time +# zones, and Decree No. 147 (1919-03-29) http://istmat.info/node/35854 +# specified a transition date of 1919-07-01, apparently at 00:00 UT. +# No doubt only the Soviet-controlled regions switched on that date; +# later transitions to UT-based time in other parts of Russia are +# taken from what appear to be guesses by Shanks. +# (Thanks to Alexander Belopolsky for pointers to the decrees.) + # From Stepan Golosunov (2016-03-07): # 11. Regions-violators, 1981-1982. # Wikipedia refers to @@ -2453,7 +2475,7 @@ # attributes the 1982 changes to the Act of the Council of Ministers # of the USSR No. 126 from 18.02.1982. 1980-925.txt also adds # Udmurtia to the list of affected territories and lists Khatangsky -# district separately from Taymyr Autonomous Okurg. Probably erroneously. +# district separately from Taymyr Autonomous Okrug. Probably erroneously. # # The affected territories are currently listed under Europe/Moscow, # Asia/Yekaterinburg and Asia/Krasnoyarsk. @@ -2513,7 +2535,7 @@ Zone Europe/Moscow 2:30:17 - LMT 1880 2:30:17 - MMT 1916 Jul 3 # Moscow Mean Time - 2:31:19 Russia %s 1919 Jul 1 2:00 + 2:31:19 Russia %s 1919 Jul 1 0:00u 3:00 Russia %s 1921 Oct 3:00 Russia MSK/MSD 1922 Oct 2:00 - EET 1930 Jun 21 @@ -2596,22 +2618,21 @@ # The 1988 transition is from USSR act No. 5 (1988-01-04). Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 - 3:00 - TSAT 1925 Apr 6 # Tsaritsyn Time - 3:00 - STAT 1930 Jun 21 # Stalingrad Time - 4:00 - STAT 1961 Nov 11 - 4:00 Russia VOL%sT 1988 Mar 27 2:00s # Volgograd T - 3:00 Russia VOL%sT 1991 Mar 31 2:00s - 4:00 - VOLT 1992 Mar 29 2:00s - 3:00 Russia MSK/MSD 2011 Mar 27 2:00s - 4:00 - MSK 2014 Oct 26 2:00s - 3:00 - MSK + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1961 Nov 11 + 4:00 Russia +04/+05 1988 Mar 27 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 4:00 - +04 1992 Mar 29 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 2014 Oct 26 2:00s + 3:00 - +03 # From Paul Eggert (2016-03-18): # Europe/Kirov covers: # 43 RU-KIR Kirov Oblast # The 1989 transition is from USSR act No. 227 (1989-03-14). # -Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 2:00 +Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2629,16 +2650,16 @@ # Byalokoz 1919 says Samara was 3:20:20. # The 1989 transition is from USSR act No. 227 (1989-03-14). -Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 2:00 - 3:00 - SAMT 1930 Jun 21 # Samara Time - 4:00 - SAMT 1935 Jan 27 - 4:00 Russia KUY%sT 1989 Mar 26 2:00s # Kuybyshev - 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 2:00 Russia EE%sT 1991 Sep 29 2:00s - 3:00 - SAMT 1991 Oct 20 3:00 - 4:00 Russia SAM%sT 2010 Mar 28 2:00s - 3:00 Russia SAM%sT 2011 Mar 27 2:00s - 4:00 - SAMT +Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1935 Jan 27 + 4:00 Russia +04/+05 1989 Mar 26 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 2:00 Russia +02/+03 1991 Sep 29 2:00s + 3:00 - +03 1991 Oct 20 3:00 + 4:00 Russia +04/+05 2010 Mar 28 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 # From Paul Eggert (2016-03-18): # Europe/Ulyanovsk covers: @@ -2653,7 +2674,7 @@ # From Matt Johnson (2016-03-09): # http://publication.pravo.gov.ru/Document/View/0001201603090051 -Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 2:00 +Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2685,12 +2706,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 3:45:05 - PMT 1919 Jul 15 4:00 - 4:00 - SVET 1930 Jun 21 # Sverdlovsk Time - 5:00 Russia SVE%sT 1991 Mar 31 2:00s - 4:00 Russia SVE%sT 1992 Jan 19 2:00s - 5:00 Russia YEK%sT 2011 Mar 27 2:00s - 6:00 - YEKT 2014 Oct 26 2:00s - 5:00 - YEKT + 4:00 - +04 1930 Jun 21 + 5:00 Russia +05/+06 1991 Mar 31 2:00s + 4:00 Russia +04/+05 1992 Jan 19 2:00s + 5:00 Russia +05/+06 2011 Mar 27 2:00s + 6:00 - +06 2014 Oct 26 2:00s + 5:00 - +05 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2700,12 +2721,12 @@ # Byalokoz 1919 says Omsk was 4:53:30. Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 - 5:00 - OMST 1930 Jun 21 # Omsk Time - 6:00 Russia OMS%sT 1991 Mar 31 2:00s - 5:00 Russia OMS%sT 1992 Jan 19 2:00s - 6:00 Russia OMS%sT 2011 Mar 27 2:00s - 7:00 - OMST 2014 Oct 26 2:00s - 6:00 - OMST + 5:00 - +05 1930 Jun 21 + 6:00 Russia +06/+07 1991 Mar 31 2:00s + 5:00 Russia +05/+06 1992 Jan 19 2:00s + 6:00 Russia +06/+07 2011 Mar 27 2:00s + 7:00 - +07 2014 Oct 26 2:00s + 6:00 - +06 # From Paul Eggert (2016-02-22): # Asia/Barnaul covers: @@ -2785,7 +2806,7 @@ # Note that time belts (numbered from 2 (Moscow) to 12 according to their # GMT/UTC offset and having too many exceptions like regions formally # belonging to one belt but using time from another) were replaced -# with time zones in 2011 with different numberings (there was a +# with time zones in 2011 with different numbering (there was a # 2-hour gap between second and third zones in 2011-2014). # From Stepan Golosunov (2016-04-12): @@ -2868,12 +2889,12 @@ # Byalokoz 1919 says Krasnoyarsk was 6:11:26. Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 - 6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time - 7:00 Russia KRA%sT 1991 Mar 31 2:00s - 6:00 Russia KRA%sT 1992 Jan 19 2:00s - 7:00 Russia KRA%sT 2011 Mar 27 2:00s - 8:00 - KRAT 2014 Oct 26 2:00s - 7:00 - KRAT + 6:00 - +06 1930 Jun 21 + 7:00 Russia +07/+08 1991 Mar 31 2:00s + 6:00 Russia +06/+07 1992 Jan 19 2:00s + 7:00 Russia +07/+08 2011 Mar 27 2:00s + 8:00 - +08 2014 Oct 26 2:00s + 7:00 - +07 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2890,12 +2911,12 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880 6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time - 7:00 - IRKT 1930 Jun 21 # Irkutsk Time - 8:00 Russia IRK%sT 1991 Mar 31 2:00s - 7:00 Russia IRK%sT 1992 Jan 19 2:00s - 8:00 Russia IRK%sT 2011 Mar 27 2:00s - 9:00 - IRKT 2014 Oct 26 2:00s - 8:00 - IRKT + 7:00 - +07 1930 Jun 21 + 8:00 Russia +08/+09 1991 Mar 31 2:00s + 7:00 Russia +07/+08 1992 Jan 19 2:00s + 8:00 Russia +08/+09 2011 Mar 27 2:00s + 9:00 - +09 2014 Oct 26 2:00s + 8:00 - +08 # From Tim Parenti (2014-07-06): @@ -2912,13 +2933,13 @@ # http://publication.pravo.gov.ru/Document/View/0001201512300107 Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 8:00 - IRKT 2016 Mar 27 2:00 - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 8:00 - +08 2016 Mar 27 2:00 + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2958,12 +2979,12 @@ # Byalokoz 1919 says Yakutsk was 8:38:58. Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2981,12 +3002,12 @@ # Go with Byalokoz. Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 - 9:00 - VLAT 1930 Jun 21 # Vladivostok Time - 10:00 Russia VLA%sT 1991 Mar 31 2:00s - 9:00 Russia VLA%sT 1992 Jan 19 2:00s - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 9:00 - +09 1930 Jun 21 + 10:00 Russia +10/+11 1991 Mar 31 2:00s + 9:00 Russia +09/+10 1992 Jan 19 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03): @@ -3004,14 +3025,14 @@ # This transition is no doubt wrong, but we have no better info. Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2004 - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2011 Sep 13 0:00s # Decree 725? - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2004 + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2011 Sep 13 0:00s # Decree 725? + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03): @@ -3027,15 +3048,14 @@ # The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long. Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 - 9:00 - JCST 1937 Oct 1 - 9:00 - JST 1945 Aug 25 - 11:00 Russia SAK%sT 1991 Mar 31 2:00s # Sakhalin T - 10:00 Russia SAK%sT 1992 Jan 19 2:00s - 11:00 Russia SAK%sT 1997 Mar lastSun 2:00s - 10:00 Russia SAK%sT 2011 Mar 27 2:00s - 11:00 - SAKT 2014 Oct 26 2:00s - 10:00 - SAKT 2016 Mar 27 2:00s - 11:00 - SAKT + 9:00 - +09 1945 Aug 25 + 11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 1997 Mar lastSun 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 2016 Mar 27 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3058,13 +3078,13 @@ # http://publication.pravo.gov.ru/Document/View/0001201604050038 Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 10:00 - MAGT 2016 Apr 24 2:00s - 11:00 - MAGT + 10:00 - +10 1930 Jun 21 # Magadan Time + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 10:00 - +10 2016 Apr 24 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-06): @@ -3107,17 +3127,14 @@ # in Russian.) In addition, Srednekolymsk appears to be a much older # settlement and the population of Zyryanka seems to be declining. # Go with Srednekolymsk. -# -# Since Magadan Oblast moves to UTC+10 on 2014-10-26, we cannot keep using MAGT -# as the abbreviation. Use SRET instead. Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 11:00 - SRET # Srednekolymsk Time + 10:00 - +10 1930 Jun 21 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03): @@ -3135,14 +3152,14 @@ # UTC+12 since at least then, too. Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAKT 1981 Apr 1 - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2011 Sep 13 0:00s # Decree 725? - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1981 Apr 1 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2011 Sep 13 0:00s # Decree 725? + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3155,12 +3172,12 @@ # The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps # Asia/Petropavlovsk-Kamchatsky, but these are too long. Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 - 11:00 - PETT 1930 Jun 21 # P-K Time - 12:00 Russia PET%sT 1991 Mar 31 2:00s - 11:00 Russia PET%sT 1992 Jan 19 2:00s - 12:00 Russia PET%sT 2010 Mar 28 2:00s - 11:00 Russia PET%sT 2011 Mar 27 2:00s - 12:00 - PETT + 11:00 - +11 1930 Jun 21 + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # From Tim Parenti (2014-07-03): @@ -3168,13 +3185,13 @@ # 87 RU-CHU Chukotka Autonomous Okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 - 12:00 - ANAT 1930 Jun 21 # Anadyr Time - 13:00 Russia ANA%sT 1982 Apr 1 0:00s - 12:00 Russia ANA%sT 1991 Mar 31 2:00s - 11:00 Russia ANA%sT 1992 Jan 19 2:00s - 12:00 Russia ANA%sT 2010 Mar 28 2:00s - 11:00 Russia ANA%sT 2011 Mar 27 2:00s - 12:00 - ANAT + 12:00 - +12 1930 Jun 21 + 13:00 Russia +13/+14 1982 Apr 1 0:00s + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # San Marino @@ -3495,6 +3512,14 @@ # Engineered Standard Time," said Twitter user @aysekarahasan. # http://www.bbc.com/news/world-europe-34631326 +# From Burak AYDIN (2016-09-08): +# Turkey will stay in Daylight Saving Time even in winter.... +# http://www.resmigazete.gov.tr/eskiler/2016/09/20160908-2.pdf +# +# From Paul Eggert (2016-09-07): +# The change is permanent, so this is the new standard time in Turkey. +# It takes effect today, which is not much notice. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Turkey 1916 only - May 1 0:00 1:00 S Rule Turkey 1916 only - Oct 1 0:00 0 - @@ -3558,7 +3583,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 1:56:56 - IMT 1910 Oct # Istanbul Mean Time? 2:00 Turkey EE%sT 1978 Oct 15 - 3:00 Turkey TR%sT 1985 Apr 20 # Turkey Time + 3:00 Turkey +03/+04 1985 Apr 20 2:00 Turkey EE%sT 2007 2:00 EU EE%sT 2011 Mar 27 1:00u 2:00 - EET 2011 Mar 28 1:00u @@ -3566,7 +3591,8 @@ 2:00 - EET 2014 Mar 31 1:00u 2:00 EU EE%sT 2015 Oct 25 1:00u 2:00 1:00 EEST 2015 Nov 8 1:00u - 2:00 EU EE%sT + 2:00 EU EE%sT 2016 Sep 7 + 3:00 - +03 Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. # Ukraine diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/factory --- a/jdk/make/data/tzdata/factory Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/factory Mon Oct 10 13:31:48 2016 -0700 @@ -24,9 +24,10 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -# For companies who don't want to put time zone specification in -# their installation procedures. When users run date, they'll get the message. -# Also useful for the "comp.sources" version. +# For distributors who don't want to put time zone specification in +# their installation procedures. Users that run 'date' will get the +# time zone abbreviation "-00", indicating that the actual time zone +# is unknown. # Zone NAME GMTOFF RULES FORMAT -Zone Factory 0 - "Local time zone must be set--see zic manual page" +Zone Factory 0 - -00 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/leapseconds --- a/jdk/make/data/tzdata/leapseconds Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/leapseconds Mon Oct 10 13:31:48 2016 -0700 @@ -79,6 +79,7 @@ Leap 2008 Dec 31 23:59:60 + S Leap 2012 Jun 30 23:59:60 + S Leap 2015 Jun 30 23:59:60 + S +Leap 2016 Dec 31 23:59:60 + S -# Updated through IERS Bulletin C51 -# File expires on: 28 December 2016 +# Updated through IERS Bulletin C52 +# File expires on: 28 June 2017 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/northamerica --- a/jdk/make/data/tzdata/northamerica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/northamerica Mon Oct 10 13:31:48 2016 -0700 @@ -436,11 +436,42 @@ # north of the Salmon River, and the towns of Burgdorf and Warren), # Nevada (except West Wendover), Oregon (except the northern 3/4 of # Malheur county), and Washington + +# From Paul Eggert (2016-08-20): +# In early February 1948, in response to California's electricity shortage, +# PG&E changed power frequency from 60 to 59.5 Hz during daylight hours, +# causing electric clocks to lose six minutes per day. (This did not change +# legal time, and is not part of the data here.) See: +# Ross SA. An energy crisis from the past: Northern California in 1948. +# Working Paper No. 8, Institute of Governmental Studies, UC Berkeley, +# 1973-11. http://escholarship.org/uc/item/8x22k30c +# +# In another measure to save electricity, DST was instituted from 1948-03-14 +# at 02:01 to 1949-01-16 at 02:00, with the governor having the option to move +# the fallback transition earlier. See pages 3-4 of: +# http://clerk.assembly.ca.gov/sites/clerk.assembly.ca.gov/files/archive/Statutes/1948/48Vol1_Chapters.pdf +# +# In response: +# +# Governor Warren received a torrent of objecting mail, and it is not too much +# to speculate that the objections to Daylight Saving Time were one important +# factor in the defeat of the Dewey-Warren Presidential ticket in California. +# -- Ross, p 25 +# +# On December 8 the governor exercised the option, setting the date to January 1 +# (LA Times 1948-12-09). The transition time was 02:00 (LA Times 1949-01-01). +# +# Despite the controversy, in 1949 California voters approved Proposition 12, +# which established DST from April's last Sunday at 01:00 until September's +# last Sunday at 02:00. This was amended by 1962's Proposition 6, which changed +# the fall-back date to October's last Sunday. See: +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1501&context=ca_ballot_props +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1636&context=ca_ballot_props # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER -Rule CA 1948 only - Mar 14 2:00 1:00 D +Rule CA 1948 only - Mar 14 2:01 1:00 D Rule CA 1949 only - Jan 1 2:00 0 S -Rule CA 1950 1966 - Apr lastSun 2:00 1:00 D +Rule CA 1950 1966 - Apr lastSun 1:00 1:00 D Rule CA 1950 1961 - Sep lastSun 2:00 0 S Rule CA 1962 1966 - Oct lastSun 2:00 0 S # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -3304,7 +3335,7 @@ # indicating that the normal ET rules are followed. # # From Paul Eggert (2014-08-19): -# The 2014-08-13 Cabinet meeting decided to stay on UTC-4 year-round. See: +# The 2014-08-13 Cabinet meeting decided to stay on UT -04 year-round. See: # http://tcweeklynews.com/daylight-savings-time-to-be-maintained-p5353-127.htm # Model this as a switch from EST/EDT to AST ... # From Chris Walton (2014-11-04): diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/southamerica --- a/jdk/make/data/tzdata/southamerica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/southamerica Mon Oct 10 13:31:48 2016 -0700 @@ -433,9 +433,9 @@ # stuck on Summer daylight savings time even though the summer is over. # From Paul Eggert (2013-09-05): -# Perhaps San Luis operates on the legal fiction that it is at UTC-4 +# Perhaps San Luis operates on the legal fiction that it is at -04 # with perpetual summer time, but ordinary usage typically seems to -# just say it's at UTC-3; see, for example, +# just say it's at -03; see, for example, # http://es.wikipedia.org/wiki/Hora_oficial_argentina # We've documented similar situations as being plain changes to # standard time, so let's do that here too. This does not change UTC diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/data/tzdata/zone.tab --- a/jdk/make/data/tzdata/zone.tab Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/data/tzdata/zone.tab Mon Oct 10 13:31:48 2016 -0700 @@ -284,7 +284,7 @@ MH +0905+16720 Pacific/Kwajalein Kwajalein MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako -MM +1647+09610 Asia/Rangoon +MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/lib/CoreLibraries.gmk --- a/jdk/make/lib/CoreLibraries.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/lib/CoreLibraries.gmk Mon Oct 10 13:31:48 2016 -0700 @@ -218,7 +218,7 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_windows := -export:ZIP_Open -export:ZIP_Close -export:ZIP_FindEntry \ -export:ZIP_ReadEntry -export:ZIP_GetNextEntry \ - -export:ZIP_InflateFully -export:ZIP_CRC32, \ + -export:ZIP_InflateFully -export:ZIP_CRC32 -export:ZIP_FreeEntry, \ LIBS_unix := -ljvm -ljava $(LIBZ), \ LIBS_solaris := -lc, \ LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \ diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/mapfiles/libzip/mapfile-vers --- a/jdk/make/mapfiles/libzip/mapfile-vers Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/mapfiles/libzip/mapfile-vers Mon Oct 10 13:31:48 2016 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 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 @@ -49,6 +49,7 @@ Java_java_util_zip_Inflater_setDictionary; ZIP_Close; ZIP_CRC32; + ZIP_FreeEntry; ZIP_FindEntry; ZIP_GetEntry; ZIP_GetNextEntry; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/rmic/RmicCommon.gmk --- a/jdk/make/rmic/RmicCommon.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/make/rmic/RmicCommon.gmk Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java Mon Oct 10 13:31:48 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 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 omref = finder.find(mn); + if (omref.isPresent()) { + Set packages = omref.get().descriptor().conceals(); + addPackagesAttribute(mi, packages); + } + } + } + } + } + + static void addPackagesAttribute(Path mi, Set 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); + } + +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/io/FilePermission.java --- a/jdk/src/java.base/share/classes/java/io/FilePermission.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java Mon Oct 10 13:31:48 2016 -0700 @@ -25,11 +25,20 @@ package java.io; +import java.net.URI; +import java.nio.file.*; import java.security.*; import java.util.Enumeration; +import java.util.Objects; import java.util.StringJoiner; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; + +import jdk.internal.misc.JavaIOFilePermissionAccess; +import jdk.internal.misc.SharedSecrets; +import sun.nio.fs.DefaultFileSystemProvider; +import sun.security.action.GetPropertyAction; +import sun.security.util.FilePermCompat; import sun.security.util.SecurityConstants; /** @@ -41,8 +50,11 @@ * the file separator character, File.separatorChar) indicates * all the files and directories contained in that directory. A pathname * that ends with "/-" indicates (recursively) all files - * and subdirectories contained in that directory. A pathname consisting of - * the special token "<<ALL FILES>>" matches any file. + * and subdirectories contained in that directory. Such a pathname is called + * a wildcard pathname. Otherwise, it's a simple pathname. + *

+ * A pathname consisting of the special token {@literal "<>"} + * matches any file. *

* Note: A pathname consisting of a single "*" indicates all the files * in the current directory, while a pathname consisting of a single "-" @@ -75,12 +87,12 @@ *

* Be careful when granting FilePermissions. Think about the implications * of granting read and especially write access to various files and - * directories. The "<<ALL FILES>>" permission with write action is + * directories. The {@literal "<>"} permission with write action is * especially dangerous. This grants permission to write to the entire * file system. One thing this effectively allows is replacement of the * system binary, including the JVM runtime environment. - * - *

Please note: Code can always read a file from the same + *

+ * Please note: Code can always read a file from the same * directory it's in (or a subdirectory of that directory); it does not * need explicit permission to do so. * @@ -145,34 +157,127 @@ private String actions; // Left null as long as possible, then // created and re-used in the getAction function. - // canonicalized dir path. In the case of - // directories, it is the name "/blah/*" or "/blah/-" without - // the last character (the "*" or "-"). + // canonicalized dir path. used by the "old" behavior (nb == false). + // In the case of directories, it is the name "/blah/*" or "/blah/-" + // without the last character (the "*" or "-"). private transient String cpath; + // Following fields used by the "new" behavior (nb == true), in which + // input path is not canonicalized. For compatibility (so that granting + // FilePermission on "x" allows reading "`pwd`/x", an alternative path + // can be added so that both can be used in an implies() check. Please note + // the alternative path only deals with absolute/relative path, and does + // not deal with symlink/target. + + private transient Path npath; // normalized dir path. + private transient Path npath2; // alternative normalized dir path. + private transient boolean allFiles; // whether this is <> + // static Strings used by init(int mask) private static final char RECURSIVE_CHAR = '-'; private static final char WILD_CHAR = '*'; -/* - public String toString() - { - StringBuffer sb = new StringBuffer(); - sb.append("***\n"); - sb.append("cpath = "+cpath+"\n"); - sb.append("mask = "+mask+"\n"); - sb.append("actions = "+getActions()+"\n"); - sb.append("directory = "+directory+"\n"); - sb.append("recursive = "+recursive+"\n"); - sb.append("***\n"); - return sb.toString(); - } -*/ +// public String toString() { +// StringBuffer sb = new StringBuffer(); +// sb.append("*** FilePermission on " + getName() + " ***"); +// for (Field f : FilePermission.class.getDeclaredFields()) { +// if (!Modifier.isStatic(f.getModifiers())) { +// try { +// sb.append(f.getName() + " = " + f.get(this)); +// } catch (Exception e) { +// sb.append(f.getName() + " = " + e.toString()); +// } +// sb.append('\n'); +// } +// } +// sb.append("***\n"); +// return sb.toString(); +// } private static final long serialVersionUID = 7930732926638008763L; /** + * Always use the internal default file system, in case it was modified + * with java.nio.file.spi.DefaultFileSystemProvider. + */ + private static final java.nio.file.FileSystem builtInFS = + DefaultFileSystemProvider.create() + .getFileSystem(URI.create("file:///")); + + /** + * Creates FilePermission objects with special internals. + * See {@link FilePermCompat#newPermPlusAltPath(Permission)} and + * {@link FilePermCompat#newPermUsingAltPath(Permission)}. + */ + + private static final Path here = builtInFS.getPath( + GetPropertyAction.privilegedGetProperty("user.dir")); + + /** + * A private constructor like a clone, only npath2 is not touched. + * @param input + */ + private FilePermission(FilePermission input) { + super(input.getName()); + this.npath = input.npath; + this.actions = input.actions; + this.allFiles = input.allFiles; + this.recursive = input.recursive; + this.directory = input.directory; + this.cpath = input.cpath; + this.mask = input.mask; + } + + /** + * Returns the alternative path as a Path object, i.e. absolute path + * for a relative one, or vice versa. + * + * @param in a real path w/o "-" or "*" at the end, and not <>. + * @return the alternative path, or null if cannot find one. + */ + private static Path altPath(Path in) { + try { + if (!in.isAbsolute()) { + return here.resolve(in).normalize(); + } else { + return here.relativize(in).normalize(); + } + } catch (IllegalArgumentException e) { + return null; + } + } + + static { + SharedSecrets.setJavaIOFilePermissionAccess( + new JavaIOFilePermissionAccess() { + public FilePermission newPermPlusAltPath(FilePermission input) { + if (input.npath2 == null && !input.allFiles) { + Path npath2 = altPath(input.npath); + if (npath2 != null) { + FilePermission np = new FilePermission(input); + np.npath2 = npath2; + return np; + } + } + return input; + } + public FilePermission newPermUsingAltPath(FilePermission input) { + if (!input.allFiles) { + Path npath2 = altPath(input.npath); + if (npath2 != null) { + FilePermission np = new FilePermission(input); + np.npath = npath2; + return np; + } + } + return null; + } + } + ); + } + + /** * initialize a FilePermission object. Common to all constructors. * Also called during de-serialization. * @@ -186,60 +291,106 @@ if (mask == NONE) throw new IllegalArgumentException("invalid actions mask"); - if ((cpath = getName()) == null) + if (FilePermCompat.nb) { + String name = getName(); + + if (name == null) + throw new NullPointerException("name can't be null"); + + this.mask = mask; + + if (name.equals("<>")) { + allFiles = true; + npath = builtInFS.getPath(""); + // other fields remain default + return; + } + + boolean rememberStar = false; + if (name.endsWith("*")) { + rememberStar = true; + recursive = false; + name = name.substring(0, name.length()-1) + "-"; + } + + try { + // new File() can "normalize" some name, for example, "/C:/X" on + // Windows. Some JDK codes generate such illegal names. + npath = builtInFS.getPath(new File(name).getPath()) + .normalize(); + } catch (InvalidPathException ipe) { + // Still invalid. For compatibility reason, accept it + // but make this permission useless. + npath = builtInFS.getPath("-u-s-e-l-e-s-s-"); + this.mask = NONE; + } + + // lastName should always be non-null now + Path lastName = npath.getFileName(); + if (lastName != null && lastName.toString().equals("-")) { + directory = true; + recursive = !rememberStar; + npath = npath.getParent(); + } + if (npath == null) { + npath = builtInFS.getPath(""); + } + } else { + if ((cpath = getName()) == null) throw new NullPointerException("name can't be null"); - this.mask = mask; + this.mask = mask; - if (cpath.equals("<>")) { - directory = true; - recursive = true; - cpath = ""; - return; - } + if (cpath.equals("<>")) { + directory = true; + recursive = true; + cpath = ""; + return; + } - // store only the canonical cpath if possible - cpath = AccessController.doPrivileged(new PrivilegedAction<>() { - public String run() { - try { - String path = cpath; - if (cpath.endsWith("*")) { - // call getCanonicalPath with a path with wildcard character - // replaced to avoid calling it with paths that are - // intended to match all entries in a directory - path = path.substring(0, path.length()-1) + "-"; - path = new File(path).getCanonicalPath(); - return path.substring(0, path.length()-1) + "*"; - } else { - return new File(path).getCanonicalPath(); + // store only the canonical cpath if possible + cpath = AccessController.doPrivileged(new PrivilegedAction<>() { + public String run() { + try { + String path = cpath; + if (cpath.endsWith("*")) { + // call getCanonicalPath with a path with wildcard character + // replaced to avoid calling it with paths that are + // intended to match all entries in a directory + path = path.substring(0, path.length() - 1) + "-"; + path = new File(path).getCanonicalPath(); + return path.substring(0, path.length() - 1) + "*"; + } else { + return new File(path).getCanonicalPath(); + } + } catch (IOException ioe) { + return cpath; } - } catch (IOException ioe) { - return cpath; } - } - }); + }); - int len = cpath.length(); - char last = ((len > 0) ? cpath.charAt(len - 1) : 0); + int len = cpath.length(); + char last = ((len > 0) ? cpath.charAt(len - 1) : 0); - if (last == RECURSIVE_CHAR && - cpath.charAt(len - 2) == File.separatorChar) { - directory = true; - recursive = true; - cpath = cpath.substring(0, --len); - } else if (last == WILD_CHAR && - cpath.charAt(len - 2) == File.separatorChar) { - directory = true; - //recursive = false; - cpath = cpath.substring(0, --len); - } else { - // overkill since they are initialized to false, but - // commented out here to remind us... - //directory = false; - //recursive = false; + if (last == RECURSIVE_CHAR && + cpath.charAt(len - 2) == File.separatorChar) { + directory = true; + recursive = true; + cpath = cpath.substring(0, --len); + } else if (last == WILD_CHAR && + cpath.charAt(len - 2) == File.separatorChar) { + directory = true; + //recursive = false; + cpath = cpath.substring(0, --len); + } else { + // overkill since they are initialized to false, but + // commented out here to remind us... + //directory = false; + //recursive = false; + } + + // XXX: at this point the path should be absolute. die if it isn't? } - - // XXX: at this point the path should be absolute. die if it isn't? } /** @@ -254,7 +405,7 @@ * indicates all the files and directories contained in that directory. * A pathname that ends with "/-" indicates (recursively) all files and * subdirectories contained in that directory. The special pathname - * "<<ALL FILES>>" matches any file. + * {@literal "<>"} matches any file. * *

A pathname consisting of a single "*" indicates all the files * in the current directory, while a pathname consisting of a single "-" @@ -264,6 +415,28 @@ * *

A pathname containing an empty string represents an empty path. * + * @implNote In this implementation, the + * {@code jdk.io.permissionsUseCanonicalPath} system property dictates how + * the {@code path} argument is processed and stored. + *

+ * If the value of the system property is set to {@code true}, {@code path} + * is canonicalized and stored as a String object named {@code cpath}. + * This means a relative path is converted to an absolute path, a Windows + * DOS-style 8.3 path is expanded to a long path, and a symbolic link is + * resolved to its target, etc. + *

+ * If the value of the system property is set to {@code false}, {@code path} + * is converted to a {@link java.nio.file.Path} object named {@code npath} + * after {@link Path#normalize() normalization}. No canonicalization is + * performed which means the underlying file system is not accessed. + *

+ * In either case, the "*" or "-" character at the end of a wildcard + * {@code path} is removed before canonicalization or normalization. + * It is stored in a separate wildcard flag field. + *

+ * The default value of the {@code jdk.io.permissionsUseCanonicalPath} + * system property is {@code false} in this implementation. + * * @param path the pathname of the file/directory. * @param actions the action string. * @@ -305,6 +478,38 @@ * "/tmp/*" encompasses all files in the "/tmp" directory, * including the one named "foo". * + *

+ * Precisely, a simple pathname implies another simple pathname + * if and only if they are equal. A simple pathname never implies + * a wildcard pathname. A wildcard pathname implies another wildcard + * pathname if and only if all simple pathnames implied by the latter + * are implied by the former. A wildcard pathname implies a simple + * pathname if and only if + *

    + *
  • if the wildcard flag is "*", the simple pathname's path + * must be right inside the wildcard pathname's path. + *
  • if the wildcard flag is "-", the simple pathname's path + * must be recursively inside the wildcard pathname's path. + *
+ *

+ * {@literal "<>"} implies every other pathname. No pathname, + * except for {@literal "<>"} itself, implies + * {@literal "<>"}. + * + * @implNote + * If {@code jdk.io.permissionsUseCanonicalPath} is {@code true}, a + * simple {@code cpath} is inside a wildcard {@code cpath} if and only if + * after removing the base name (the last name in the pathname's name + * sequence) from the former the remaining part equals to the latter, + * a simple {@code cpath} is recursively inside a wildcard {@code cpath} + * if and only if the former starts with the latter. + *

+ * If {@code jdk.io.permissionsUseCanonicalPath} is {@code false}, a + * simple {@code npath} is inside a wildcard {@code npath} if and only if + * {@code simple_npath.relativize(wildcard_npath)} is exactly "..", + * a simple {@code npath} is recursively inside a wildcard {@code npath} + * if and only if {@code simple_npath.relativize(wildcard_npath)} + * is a series of one or more "..". * * @param p the permission to check against. * @@ -334,45 +539,125 @@ * @return the effective mask */ boolean impliesIgnoreMask(FilePermission that) { - if (this.directory) { - if (this.recursive) { - // make sure that.path is longer then path so - // something like /foo/- does not imply /foo - if (that.directory) { - return (that.cpath.length() >= this.cpath.length()) && - that.cpath.startsWith(this.cpath); - } else { - return ((that.cpath.length() > this.cpath.length()) && - that.cpath.startsWith(this.cpath)); + if (FilePermCompat.nb) { + if (allFiles) { + return true; + } + if (that.allFiles) { + return false; + } + // Left at least same level of wildness as right + if ((this.recursive && that.recursive) != that.recursive + || (this.directory && that.directory) != that.directory) { + return false; + } + // Same npath is good as long as both or neither are directories + if (this.npath.equals(that.npath) + && this.directory == that.directory) { + return true; + } + int diff = containsPath(this.npath, that.npath); + // Right inside left is good if recursive + if (diff >= 1 && recursive) { + return true; + } + // Right right inside left if it is element in set + if (diff == 1 && directory && !that.directory) { + return true; + } + + // Hack: if a npath2 field exists, apply the same checks + // on it as a fallback. + if (this.npath2 != null) { + if (this.npath2.equals(that.npath) + && this.directory == that.directory) { + return true; + } + diff = containsPath(this.npath2, that.npath); + if (diff >= 1 && recursive) { + return true; } - } else { - if (that.directory) { - // if the permission passed in is a directory - // specification, make sure that a non-recursive - // permission (i.e., this object) can't imply a recursive - // permission. - if (that.recursive) - return false; - else - return (this.cpath.equals(that.cpath)); + if (diff == 1 && directory && !that.directory) { + return true; + } + } + + return false; + } else { + if (this.directory) { + if (this.recursive) { + // make sure that.path is longer then path so + // something like /foo/- does not imply /foo + if (that.directory) { + return (that.cpath.length() >= this.cpath.length()) && + that.cpath.startsWith(this.cpath); + } else { + return ((that.cpath.length() > this.cpath.length()) && + that.cpath.startsWith(this.cpath)); + } } else { - int last = that.cpath.lastIndexOf(File.separatorChar); - if (last == -1) - return false; - else { - // this.cpath.equals(that.cpath.substring(0, last+1)); - // Use regionMatches to avoid creating new string - return (this.cpath.length() == (last + 1)) && - this.cpath.regionMatches(0, that.cpath, 0, last+1); + if (that.directory) { + // if the permission passed in is a directory + // specification, make sure that a non-recursive + // permission (i.e., this object) can't imply a recursive + // permission. + if (that.recursive) + return false; + else + return (this.cpath.equals(that.cpath)); + } else { + int last = that.cpath.lastIndexOf(File.separatorChar); + if (last == -1) + return false; + else { + // this.cpath.equals(that.cpath.substring(0, last+1)); + // Use regionMatches to avoid creating new string + return (this.cpath.length() == (last + 1)) && + this.cpath.regionMatches(0, that.cpath, 0, last + 1); + } } } + } else if (that.directory) { + // if this is NOT recursive/wildcarded, + // do not let it imply a recursive/wildcarded permission + return false; + } else { + return (this.cpath.equals(that.cpath)); } - } else if (that.directory) { - // if this is NOT recursive/wildcarded, - // do not let it imply a recursive/wildcarded permission - return false; - } else { - return (this.cpath.equals(that.cpath)); + } + } + + /** + * Returns the depth between an outer path p1 and an inner path p2. -1 + * is returned if + * + * - p1 does not contains p2. + * - this is not decidable. For example, p1="../x", p2="y". + * - the depth is not decidable. For example, p1="/", p2="x". + * + * This method can return 2 if the depth is greater than 2. + * + * @param p1 the expected outer path, normalized + * @param p2 the expected inner path, normalized + * @return the depth in between + */ + private static int containsPath(Path p1, Path p2) { + Path p; + try { + p = p2.relativize(p1).normalize(); + if (p.getName(0).toString().isEmpty()) { + return 0; + } else { + for (Path item: p) { + String s = item.toString(); + if (!s.equals("..")) { + return -1; + } + } + return p.getNameCount(); + } + } catch (IllegalArgumentException iae) { + return -1; } } @@ -380,6 +665,12 @@ * Checks two FilePermission objects for equality. Checks that obj is * a FilePermission, and has the same pathname and actions as this object. * + * @implNote More specifically, two pathnames are the same if and only if + * they have the same wildcard flag and their {@code cpath} + * (if {@code jdk.io.permissionsUseCanonicalPath} is {@code true}) or + * {@code npath} (if {@code jdk.io.permissionsUseCanonicalPath} + * is {@code false}) are equal. Or they are both {@literal "<>"}. + * * @param obj the object we are testing for equality with this object. * @return true if obj is a FilePermission, and has the same * pathname and actions as this FilePermission object, @@ -395,10 +686,18 @@ FilePermission that = (FilePermission) obj; - return (this.mask == that.mask) && - this.cpath.equals(that.cpath) && - (this.directory == that.directory) && - (this.recursive == that.recursive); + if (FilePermCompat.nb) { + return (this.mask == that.mask) && + (this.allFiles == that.allFiles) && + this.npath.equals(that.npath) && + (this.directory == that.directory) && + (this.recursive == that.recursive); + } else { + return (this.mask == that.mask) && + this.cpath.equals(that.cpath) && + (this.directory == that.directory) && + (this.recursive == that.recursive); + } } /** @@ -408,7 +707,11 @@ */ @Override public int hashCode() { - return 0; + if (FilePermCompat.nb) { + return Objects.hash(mask, allFiles, directory, recursive, npath); + } else { + return 0; + } } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java Mon Oct 10 13:31:48 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. + *

+ * 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. + *

+ * 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. + * + *

+ * Typically, a custom filter should check if a process-wide filter + * is configured and defer to it if so. For example, + *

{@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;
+ * }
+ *}
+ *

+ * 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. + *

+ * When setting the filter, it should be stateless and idempotent, + * reporting the same result when passed the same arguments. + *

+ * 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) () -> { + 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. + *

+ * 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. + *

    + *
  • maxdepth={@code value} - the maximum depth of a graph
  • + *
  • maxrefs={@code value} - the maximum number of internal references
  • + *
  • maxbytes={@code value} - the maximum number of bytes in the input stream
  • + *
  • maxarray={@code value} - the maximum array length allowed
  • + *
+ *

+ * 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. + *

    + *
  • If the pattern starts with "!", the class is rejected if the remaining pattern is matched; + * otherwise the class 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 pattern is not matched. + *
+ *

+ * 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, 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, 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 = 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; + } + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/io/ObjectInputStream.java --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Mon Oct 10 13:31:48 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. * + *

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}. + * *

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. * + *

The serialization filter is initialized to the value of + * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}. + * *

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. * + *

The serialization filter is initialized to the value of + * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}. + * *

If there is a security manager installed, this method first calls the * security manager's checkPermission method with the * SerializablePermission("enableSubclassImplementation") @@ -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. * + *

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. + * *

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. * + *

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. + * *

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. + *

+ * 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. + *

+ * 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: + *

    + *
  • each object reference previously deserialized from the stream + * (class is {@code null}, arrayLength is -1), + *
  • each regular class (class is not {@code null}, arrayLength is -1), + *
  • each interface of a dynamic proxy and the dynamic proxy class itself + * (class is not {@code null}, arrayLength is -1), + *
  • each array is filtered using the array type and length of the array + * (class is the array type, arrayLength is the requested length), + *
  • 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, + *
  • 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. + *
+ * + * 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. + *

+ * 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() { 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() { 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(); + } } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java --- a/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java Mon Oct 10 13:31:48 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.

* diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/io/SerializablePermission.java --- a/jdk/src/java.base/share/classes/java/io/SerializablePermission.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/io/SerializablePermission.java Mon Oct 10 13:31:48 2016 -0700 @@ -40,7 +40,7 @@ * The target name is the name of the Serializable permission (see below). * *

- * 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. * * + * + * serialFilter + * Setting a filter for ObjectInputStreams. + * Code could remove a configured filter and remove protections + * already established. + * + * * * * @see java.security.BasicPermission diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Mon Oct 10 13:31:48 2016 -0700 @@ -292,9 +292,6 @@ new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, this, null); - // The initiating protection domains for all classes loaded by this loader - private final Set domains; - // Invoked by the VM to record every loaded class with this loader. void addClass(Class c) { classes.addElement(c); @@ -349,13 +346,11 @@ if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>(); - domains = Collections.synchronizedSet(new HashSet<>()); assertionLock = new Object(); } else { // no finer-grained lock; lock on the classloader instance parallelLockMap = null; package2certs = new Hashtable<>(); - domains = new HashSet<>(); assertionLock = this; } } @@ -640,7 +635,6 @@ }, new AccessControlContext(new ProtectionDomain[] {pd})); } } - domains.add(pd); } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/lang/Math.java --- a/jdk/src/java.base/share/classes/java/lang/Math.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/Math.java Mon Oct 10 13:31:48 2016 -0700 @@ -1626,7 +1626,7 @@ * * @since 9 */ - // @HotSpotIntrinsicCandidate + @HotSpotIntrinsicCandidate public static double fma(double a, double b, double c) { /* * Infinity and NaN arithmetic is not quite the same with two @@ -1743,7 +1743,7 @@ * * @since 9 */ - // @HotSpotIntrinsicCandidate + @HotSpotIntrinsicCandidate public static float fma(float a, float b, float c) { /* * Since the double format has more than twice the precision diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/lang/module/ModulePath.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Mon Oct 10 13:31:48 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 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 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); } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/net/MulticastSocket.java --- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Mon Oct 10 13:31:48 2016 -0700 @@ -93,23 +93,19 @@ /** * Create a multicast socket. * - *

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. + *

+ * 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. *

* 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(); + } } } } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/security/AccessControlContext.java --- a/jdk/src/java.base/share/classes/java/security/AccessControlContext.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/security/AccessControlContext.java Mon Oct 10 13:31:48 2016 -0700 @@ -27,7 +27,9 @@ import java.util.ArrayList; import java.util.List; + import sun.security.util.Debug; +import sun.security.util.FilePermCompat; import sun.security.util.SecurityConstants; @@ -175,7 +177,7 @@ /** * package private to allow calls from ProtectionDomain without performing - * the security check for {@linkplain SecurityConstants.CREATE_ACC_PERMISSION} + * the security check for {@linkplain SecurityConstants#CREATE_ACC_PERMISSION} * permission */ AccessControlContext(AccessControlContext acc, @@ -253,7 +255,8 @@ if (perms[i].getClass() == AllPermission.class) { parent = null; } - tmp[i] = perms[i]; + // Add altPath into permission for compatibility. + tmp[i] = FilePermCompat.newPermPlusAltPath(perms[i]); } } @@ -443,7 +446,7 @@ } for (int i=0; i< context.length; i++) { - if (context[i] != null && !context[i].implies(perm)) { + if (context[i] != null && !context[i].impliesWithAltFilePerm(perm)) { if (dumpDebug) { debug.println("access denied " + perm); } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/security/ProtectionDomain.java --- a/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java Mon Oct 10 13:31:48 2016 -0700 @@ -32,13 +32,14 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import jdk.internal.misc.JavaSecurityAccess; import jdk.internal.misc.JavaSecurityProtectionDomainAccess; import static jdk.internal.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; import jdk.internal.misc.SharedSecrets; +import sun.security.provider.PolicyFile; import sun.security.util.Debug; +import sun.security.util.FilePermCompat; import sun.security.util.SecurityConstants; /** @@ -303,11 +304,71 @@ } if (!staticPermissions && - Policy.getPolicyNoCheck().implies(this, perm)) + Policy.getPolicyNoCheck().implies(this, perm)) { + return true; + } + if (permissions != null) { + return permissions.implies(perm); + } + + return false; + } + + /** + * This method has the same logic flow as {@link #implies} except that + * when the {@link FilePermCompat#compat} flag is on it ensures + * FilePermission compatibility after JDK-8164705. {@code implies()} + * is called when compat flag is not on or user has extended + * {@code ProtectionDomain}. + * + * This method is called by {@link AccessControlContext#checkPermission} + * and not intended to be called by an application. + */ + boolean impliesWithAltFilePerm(Permission perm) { + + // If this is a subclass of ProtectionDomain. Call the old method. + if (!FilePermCompat.compat || getClass() != ProtectionDomain.class) { + return implies(perm); + } + + if (hasAllPerm) { + // internal permission collection already has AllPermission - + // no need to go to policy return true; - if (permissions != null) - return permissions.implies(perm); + } + + Permission p2 = null; + boolean p2Calculated = false; + if (!staticPermissions) { + Policy policy = Policy.getPolicyNoCheck(); + if (policy instanceof PolicyFile) { + // The PolicyFile implementation supports compatibility + // inside and it also covers the static permissions. + return policy.implies(this, perm); + } else { + if (policy.implies(this, perm)) { + return true; + } + p2 = FilePermCompat.newPermUsingAltPath(perm); + p2Calculated = true; + if (p2 != null && policy.implies(this, p2)) { + return true; + } + } + } + if (permissions != null) { + if (permissions.implies(perm)) { + return true; + } else { + if (!p2Calculated) { + p2 = FilePermCompat.newPermUsingAltPath(perm); + } + if (p2 != null) { + return permissions.implies(p2); + } + } + } return false; } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/text/DecimalFormat.java --- a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java Mon Oct 10 13:31:48 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, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/time/format/ZoneName.java --- a/jdk/src/java.base/share/classes/java/time/format/ZoneName.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/time/format/ZoneName.java Mon Oct 10 13:31:48 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 @@ -25,11 +25,8 @@ package java.time.format; import java.util.HashMap; -import java.util.HashSet; import java.util.Locale; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; /** * A helper class to map a zone name to metazone and back to the @@ -335,6 +332,7 @@ "America/Eirunepe", "Amazon", "America/Manaus", "Africa/Nairobi", "Africa_Eastern", "Africa/Nairobi", "Asia/Yakutsk", "Yakutsk", "Asia/Yakutsk", + "Asia/Yangon", "Myanmar", "Asia/Rangoon", "America/Goose_Bay", "Atlantic", "America/Halifax", "Africa/Maseru", "Africa_Southern", "Africa/Johannesburg", "America/Swift_Current", "America_Central", "America/Chicago", @@ -770,6 +768,7 @@ "America/Indianapolis", "America/Indiana/Indianapolis", "Europe/Belfast", "Europe/London", "America/Kralendijk", "America/Curacao", + "Asia/Rangoon", "Asia/Yangon", }; private static final Map zidToMzone = new HashMap<>(); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/util/ArrayList.java --- a/jdk/src/java.base/share/classes/java/util/ArrayList.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java Mon Oct 10 13:31:48 2016 -0700 @@ -876,6 +876,7 @@ int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; + // prevent creating a synthetic constructor Itr() {} public boolean hasNext() { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/util/Locale.java --- a/jdk/src/java.base/share/classes/java/util/Locale.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Locale.java Mon Oct 10 13:31:48 2016 -0700 @@ -1027,7 +1027,7 @@ * not contain ALL valid codes that can be used to create Locales. * * - * @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) { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/java/util/spi/ToolProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/java/util/spi/ToolProvider.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,165 @@ +/* + * 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.util.spi; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Objects; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +/** + * An interface for command-line tools to provide a way to + * be invoked without necessarily starting a new VM. + * + *

Tool providers are normally located using the service-provider + * loading facility defined by {@link ServiceLoader}. + * Each provider must provide a name, and a method to run + * an instance of the corresponding tool. When a tool is run, + * it will be provided with an array of string arguments, and a + * pair of streams: one for normal (or expected) output and the other + * for reporting any errors that may occur. + * The interpretation of the string arguments will normally be defined by + * each individual tool provider, but will generally correspond to the + * arguments that could be provided to the tool when invoking the tool + * from the command line. + * + * @since 9 + */ +public interface ToolProvider { + /** + * Returns the name of this tool provider. + * + * @apiNote It is recommended that the name be the same as would be used on + * the command line: for example, "javac", "jar", "jlink". + * + * @return the name of this tool provider + */ + String name(); + + /** + * Runs an instance of the tool, returning zero for a successful run. + * Any non-zero return value indicates a tool-specific error during the + * execution. + * Two streams should be provided, for "expected" output, and for any + * error messages. If it is not necessary to distinguish the output, + * the same stream may be used for both. + * + * @apiNote The interpretation of the arguments will be specific to + * each tool. + * + * @param out a stream to which "expected" output should be written + * + * @param err a stream to which any error messages should be written + * + * @param args the command-line arguments for the tool + * + * @return the result of executing the tool. + * A return value of 0 means the tool did not encounter any errors; + * any other value indicates that at least one error occurred during + * execution. + * + * @throws NullPointerException if any of the arguments are {@code null}, + * or if there are any {@code null} values in the {@code args} array + */ + int run(PrintWriter out, PrintWriter err, String... args); + + /** + * Runs an instance of the tool, returning zero for a successful run. + * Any non-zero return value indicates a tool-specific error during the + * execution. + * Two streams should be provided, for "expected" output, and for any + * error messages. If it is not necessary to distinguish the output, + * the same stream may be used for both. + * + * @apiNote The interpretation of the arguments will be specific to + * each tool. + * + * @implNote This implementation wraps the {@code out} and {@code err} + * streams within {@link PrintWriter}s, and then calls + * {@link run(PrintWriter, PrintWriter, String[])}. + * + * @param out a stream to which "expected" output should be written + * + * @param err a stream to which any error messages should be written + * + * @param args the command-line arguments for the tool + * + * @return the result of executing the tool. + * A return value of 0 means the tool did not encounter any errors; + * any other value indicates that at least one error occurred during + * execution. + * + * @throws NullPointerException if any of the arguments are {@code null}, + * or if there are any {@code null} values in the {@code args} array + */ + default int run(PrintStream out, PrintStream err, String... args) { + Objects.requireNonNull(out); + Objects.requireNonNull(err); + for (String arg : args) { + Objects.requireNonNull(args); + } + + PrintWriter outWriter = new PrintWriter(out); + PrintWriter errWriter = new PrintWriter(err); + try { + try { + return run(outWriter, errWriter, args); + } finally { + outWriter.flush(); + } + } finally { + errWriter.flush(); + } + } + + /** + * Returns the first instance of a {@code ToolProvider} with the given name, + * as loaded by {@link ServiceLoader} using the system class loader. + * + * @param name the name of the desired tool provider + * + * @return an {@code Optional} of the first instance found + * + * @throws NullPointerException if {@code name} is {@code null} + */ + static Optional findFirst(String name) { + Objects.requireNonNull(name); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + return AccessController.doPrivileged( + (PrivilegedAction>) () -> { + ServiceLoader sl = + ServiceLoader.load(ToolProvider.class, systemClassLoader); + return StreamSupport.stream(sl.spliterator(), false) + .filter(p -> p.name().equals(name)) + .findFirst(); + }); + } +} + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java Mon Oct 10 13:31:48 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 stream() { + return zipfile.stream() + .filter(e -> !e.isDirectory()) + .map(Entry::new); + } + + @Override + public void close() throws IOException { + if (zipfile != null) { + zipfile.close(); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/jdk/internal/misc/JavaIOFilePermissionAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaIOFilePermissionAccess.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,48 @@ +/* + * 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.misc; + +import java.io.FilePermission; + +public interface JavaIOFilePermissionAccess { + + /** + * Returns a new FilePermission plus an alternative path. + * + * @param input the input + * @return the new FilePermission plus the alt path (as npath2) + * or the input itself if no alt path is available. + */ + FilePermission newPermPlusAltPath(FilePermission input); + + /** + * Returns a new FilePermission using an alternative path. + * + * @param input the input + * @return the new FilePermission using the alt path (as npath) + * or null if no alt path is available + */ + FilePermission newPermUsingAltPath(FilePermission input); +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Mon Oct 10 13:31:48 2016 -0700 @@ -29,6 +29,7 @@ import java.util.jar.JarFile; import java.io.Console; import java.io.FileDescriptor; +import java.io.FilePermission; import java.io.ObjectInputStream; import java.io.RandomAccessFile; import java.security.ProtectionDomain; @@ -58,6 +59,7 @@ private static JavaNetSocketAccess javaNetSocketAccess; private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; + private static JavaIOFilePermissionAccess javaIOFilePermissionAccess; private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess; private static JavaSecurityAccess javaSecurityAccess; private static JavaUtilZipFileAccess javaUtilZipFileAccess; @@ -201,6 +203,17 @@ javaIOFileDescriptorAccess = jiofda; } + public static JavaIOFilePermissionAccess getJavaIOFilePermissionAccess() { + if (javaIOFilePermissionAccess == null) + unsafe.ensureClassInitialized(FilePermission.class); + + return javaIOFilePermissionAccess; + } + + public static void setJavaIOFilePermissionAccess(JavaIOFilePermissionAccess jiofpa) { + javaIOFilePermissionAccess = jiofpa; + } + public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() { if (javaIOFileDescriptorAccess == null) unsafe.ensureClassInitialized(FileDescriptor.class); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Mon Oct 10 13:31:48 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(); } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/module-info.java --- a/jdk/src/java.base/share/classes/module-info.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/module-info.java Mon Oct 10 13:31:48 2016 -0700 @@ -108,6 +108,7 @@ uses java.util.spi.ResourceBundleControlProvider; uses java.util.spi.ResourceBundleProvider; uses java.util.spi.TimeZoneNameProvider; + uses java.util.spi.ToolProvider; uses javax.security.auth.spi.LoginModule; @@ -124,6 +125,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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java Mon Oct 10 13:31:48 2016 -0700 @@ -41,10 +41,6 @@ import java.util.*; import java.text.SimpleDateFormat; -import sun.security.action.GetPropertyAction; -import sun.security.action.GetIntegerAction; -import sun.security.action.GetBooleanAction; - public class FileURLConnection extends URLConnection { static String CONTENT_LENGTH = "content-length"; @@ -224,8 +220,13 @@ if (File.separatorChar == '/') { permission = new FilePermission(decodedPath, "read"); } else { + // decode could return /c:/x/y/z. + if (decodedPath.length() > 2 && decodedPath.charAt(0) == '/' + && decodedPath.charAt(2) == ':') { + decodedPath = decodedPath.substring(1); + } permission = new FilePermission( - decodedPath.replace('/',File.separatorChar), "read"); + decodedPath.replace('/', File.separatorChar), "read"); } } return permission; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java --- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Mon Oct 10 13:31:48 2016 -0700 @@ -45,11 +45,7 @@ import jdk.internal.misc.JavaSecurityProtectionDomainAccess; import static jdk.internal.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; import jdk.internal.misc.SharedSecrets; -import sun.security.util.PolicyUtil; -import sun.security.util.PropertyExpander; -import sun.security.util.Debug; -import sun.security.util.ResourcesMgr; -import sun.security.util.SecurityConstants; +import sun.security.util.*; import sun.net.www.ParseUtil; /** @@ -534,8 +530,6 @@ /** * Reads a policy configuration into the Policy object using a * Reader object. - * - * @param policyFile the policy Reader object. */ private boolean init(URL policy, PolicyInfo newInfo, boolean defPolicy) { @@ -1099,7 +1093,7 @@ synchronized (pc) { Enumeration e = pc.elements(); while (e.hasMoreElements()) { - perms.add(e.nextElement()); + perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement())); } } } @@ -1127,7 +1121,7 @@ * object with additional permissions granted to the specified * ProtectionDomain. * - * @param perm the Permissions to populate + * @param perms the Permissions to populate * @param pd the ProtectionDomain associated with the caller. * * @return the set of Permissions according to the policy. @@ -1157,8 +1151,8 @@ * object with additional permissions granted to the specified * CodeSource. * - * @param permissions the permissions to populate - * @param codesource the codesource associated with the caller. + * @param perms the permissions to populate + * @param cs the codesource associated with the caller. * This encapsulates the original location of the code (where the code * came from) and the public key(s) of its signer. * @@ -1386,7 +1380,7 @@ accPs, perms); } else { - perms.add(p); + perms.add(FilePermCompat.newPermPlusAltPath(p)); } } } @@ -1458,9 +1452,9 @@ } try { // first try to instantiate the permission - perms.add(getInstance(sp.getSelfType(), + perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(), sb.toString(), - sp.getSelfActions())); + sp.getSelfActions()))); } catch (ClassNotFoundException cnfe) { // ok, the permission is not in the bootclasspath. // before we add an UnresolvedPermission, check to see diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/sun/security/util/FilePermCompat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/FilePermCompat.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,77 @@ +/* + * 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 sun.security.util; + +import sun.security.action.GetPropertyAction; + +import java.io.FilePermission; +import java.security.Permission; +import jdk.internal.misc.SharedSecrets; + +/** + * Take care of FilePermission compatibility after JDK-8164705. + */ +public class FilePermCompat { + /** + * New behavior? Keep compatibility? Both default true. + */ + public static final boolean nb; + public static final boolean compat; + + static { + String flag = GetPropertyAction.privilegedGetProperty( + "jdk.io.permissionsUseCanonicalPath", "false"); + switch (flag) { + case "true": + nb = false; + compat = false; + break; + case "false": + nb = true; + compat = true; + break; + default: + throw new RuntimeException( + "Invalid jdk.io.permissionsUseCanonicalPath: " + flag); + } + } + + public static Permission newPermPlusAltPath(Permission input) { + if (compat && input instanceof FilePermission) { + return SharedSecrets.getJavaIOFilePermissionAccess() + .newPermPlusAltPath((FilePermission) input); + } + return input; + } + + public static Permission newPermUsingAltPath(Permission input) { + if (input instanceof FilePermission) { + return SharedSecrets.getJavaIOFilePermissionAccess() + .newPermUsingAltPath((FilePermission) input); + } + return null; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java --- a/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java Mon Oct 10 13:31:48 2016 -0700 @@ -188,6 +188,9 @@ String MHT[] = new String[] {"Marshall Islands Time", "MHT", "Marshall Islands Summer Time", "MHST", "Marshall Islands Time", "MHT"}; + String MMT[] = new String[] {"Myanmar Time", "MMT", + "Myanmar Summer Time", "MMST", + "Myanmar Time", "MMT"}; String MSK[] = new String[] {"Moscow Standard Time", "MSK", "Moscow Daylight Time", "MSD", "Moscow Time", "MT"}; @@ -683,9 +686,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda Time", "QYZT", "Qyzylorda Summer Time", "QYZST", "Qyzylorda Time", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Myanmar Time", "MMT", - "Myanmar Summer Time", "MMST", - "Myanmar Time", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Sakhalin Time", "SAKT", @@ -718,6 +719,7 @@ "Vladivostok Summer Time", "VLAST", "Vladivostok Time", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Yekaterinburg Time", "YEKT", "Yekaterinburg Summer Time", "YEKST", "Yekaterinburg Time", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/conf/security/java.policy --- a/jdk/src/java.base/share/conf/security/java.policy Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/conf/security/java.policy Mon Oct 10 13:31:48 2016 -0700 @@ -1,5 +1,18 @@ +// +// This system policy file grants a set of default permissions to all domains +// and can be configured to grant additional permissions to modules and other +// code sources. The code source URL scheme for modules linked into a +// run-time image is "jrt". +// +// For example, to grant permission to read the "foo" property to the module +// "com.greetings", the grant entry is: +// +// grant codeBase "jrt:/com.greetings" { +// permission java.util.PropertyPermission "foo", "read"; +// }; +// + // default permissions granted to all domains - grant { // allows anyone to listen on dynamic ports permission java.net.SocketPermission "localhost:0", "listen"; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/conf/security/java.security --- a/jdk/src/java.base/share/conf/security/java.security Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/conf/security/java.security Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/native/libzip/zip_util.c --- a/jdk/src/java.base/share/native/libzip/zip_util.c Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/native/libzip/zip_util.c Mon Oct 10 13:31:48 2016 -0700 @@ -1094,7 +1094,7 @@ * jzentry for each zip. This optimizes a common access pattern. */ -void +void JNICALL ZIP_FreeEntry(jzfile *jz, jzentry *ze) { jzentry *last; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/share/native/libzip/zip_util.h --- a/jdk/src/java.base/share/native/libzip/zip_util.h Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/share/native/libzip/zip_util.h Mon Oct 10 13:31:48 2016 -0700 @@ -270,7 +270,8 @@ void ZIP_Lock(jzfile *zip); void ZIP_Unlock(jzfile *zip); jint ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); -void ZIP_FreeEntry(jzfile *zip, jzentry *ze); +void JNICALL +ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java --- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java Mon Oct 10 13:31:48 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 { - private final DirectoryStream stream; - // true when at EOF private boolean atEof; // next entry to return private Path nextEntry; - UnixDirectoryIterator(DirectoryStream stream) { + UnixDirectoryIterator() { atEof = false; - this.stream = stream; } // Return true if file name is "." or ".." diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c --- a/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c Mon Oct 10 13:31:48 2016 -0700 @@ -790,9 +790,10 @@ pkg_name_buf[len] = '\0'; err = (*jvmti)->GetNamedModule(jvmti, loaderObject, pkg_name_buf, &moduleObject); + free((void*)pkg_name_buf); + check_phase_ret_blob(err, NULL); jplis_assert_msg(err == JVMTI_ERROR_NONE, "error in the JVMTI GetNamedModule"); - free((void*)pkg_name_buf); return moduleObject; } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java --- a/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Mon Oct 10 13:31:48 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. * - *

There are six ways to export remote objects: + *

There are eight ways to export remote objects: * *

    * @@ -67,12 +69,19 @@ * {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory) * exportObject(Remote, port, csf, ssf)} method. * + *
  1. Calling the + * {@link #exportObject(Remote, int, ObjectInputFilter) exportObject(Remote, port, filter)} method. + * + *
  2. Calling the + * {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory, ObjectInputFilter) + * exportObject(Remote, port, csf, ssf, filter)} method. + * *
* *

The fourth technique, {@link #exportObject(Remote)}, * always uses statically generated stubs and is deprecated. * - *

The other five techniques all use the following approach: if the + *

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 @@ * * * + *

+ * 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}. + * + *

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}. + * + *

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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Mon Oct 10 13:31:48 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 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)() -> { + ois.setObjectInputFilter(filter); + return null; + }); + } + } /** * Handle server-side dispatch using the RMI 1.1 stub/skeleton diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java Mon Oct 10 13:31:48 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) diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c --- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c Mon Oct 10 13:31:48 2016 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -343,6 +343,35 @@ debugMonitorExit(invokerLock); } +/* + * Check that method is in the specified clazz or one of its super classes. + * We have to enforce this check at the JDWP layer because the JNI layer + * has different requirements. + */ +static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method) +{ + jclass containing_class = NULL; + jvmtiError error; + + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + (gdata->jvmti, method, &containing_class); + if (error != JVMTI_ERROR_NONE) { + return JVMTI_ERROR_NONE; /* Bad jmethodID ? This will be handled elsewhere */ + } + + if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) { + return JVMTI_ERROR_NONE; + } + + // If not the same class then check that containing_class is a superclass of + // clazz (not a superinterface). + if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) && + referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) { + return JVMTI_ERROR_NONE; + } + return JVMTI_ERROR_INVALID_METHODID; +} + jvmtiError invoker_requestInvoke(jbyte invokeType, jbyte options, jint id, jthread thread, jclass clazz, jmethodID method, @@ -353,6 +382,13 @@ InvokeRequest *request; jvmtiError error = JVMTI_ERROR_NONE; + if (invokeType == INVOKE_STATIC) { + error = check_methodClass(env, clazz, method); + if (error != JVMTI_ERROR_NONE) { + return error; + } + } + debugMonitorEnter(invokerLock); request = threadControl_getInvokeRequest(thread); if (request != NULL) { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java Mon Oct 10 13:31:48 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; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Mon Oct 10 13:31:48 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); } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java Mon Oct 10 13:31:48 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 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) { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Mon Oct 10 13:31:48 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 { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java Mon Oct 10 13:31:48 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 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); } } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Mon Oct 10 13:31:48 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; } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Mon Oct 10 13:31:48 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 packages() { Set 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; } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java Mon Oct 10 13:31:48 2016 -0700 @@ -307,9 +307,10 @@ private boolean filterOutUnsupportedTags(byte[] b) { List locales; + List 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 filterLocales(List locales) { List ret = Locale.filter(priorityList, locales, Locale.FilteringMode.EXTENDED_FILTERING).stream() diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java Mon Oct 10 13:31:48 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(); + } +} + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Mon Oct 10 13:31:48 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 packages) + void writeModuleInfo(JmodOutputStream out, Set packages) throws IOException { Supplier 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 classpaths) + void processClasses(JmodOutputStream zos, List classpaths) throws IOException { if (classpaths == null) @@ -645,7 +613,7 @@ } } - void processSection(ZipOutputStream zos, Section section, List paths) + void processSection(JmodOutputStream zos, Section section, List 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() { @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, Predicate { - 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 { static final ValueConverter INSTANCE = new ClassPathConverter(); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_de.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_de.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_de.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"Marshallinseln Zeit", "MHT", "Marshallinseln Sommerzeit", "MHST", "Marshallinseln Zeit", "MHT"}; + String MMT[] = new String[] {"Myanmar Zeit", "MMT", + "Myanmar Sommerzeit", "MMST", + "Myanmar Zeit", "MMT"}; String MSK[] = new String[] {"Moskauer Normalzeit", "MSK", "Moskauer Sommerzeit", "MSD", "Zeitzone f\u00FCr Moskau", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda Zeit", "QYZT", "Qyzylorda Sommerzeit", "QYZST", "Qyzylorda Zeit", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Myanmar Zeit", "MMT", - "Myanmar Sommerzeit", "MMST", - "Myanmar Zeit", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Sakhalin Zeit", "SAKT", @@ -719,6 +720,7 @@ "Wladiwostok Sommerzeit", "VLAST", "Wladiwostok Zeit", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Jekaterinburger Zeit", "YEKT", "Jekaterinburger Sommerzeit", "YEKST", "Jekaterinburger Zeit", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_es.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_es.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_es.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"Hora de las Islas Marshall", "MHT", "Hora de verano de las Islas Marshall", "MHST", "Hora de Islas Marshall", "MHT"}; + String MMT[] = new String[] {"Hora de Myanmar", "MMT", + "Hora de verano de Myanmar", "MMST", + "Hora de Myanmar", "MMT"}; String MSK[] = new String[] {"Hora est\u00e1ndar de Mosc\u00fa", "MSK", "Hora de verano de Mosc\u00fa", "MSD", "Hora de Mosc\u00FA", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Hora de Qyzylorda", "QYZT", "Hora de verano de Qyzylorda", "QYZST", "Hora de Qyzylorda", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Hora de Myanmar", "MMT", - "Hora de verano de Myanmar", "MMST", - "Hora de Myanmar", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Hora de Sajalin", "SAKT", @@ -719,6 +720,7 @@ "Hora de verano de Vladivostok", "VLAST", "Hora de Vladivostok", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Hora de Ekaterinburgo", "YEKT", "Hora de verano de Ekaterinburgo", "YEKST", "Hora de Ekaterinburgo", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_fr.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_fr.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_fr.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"Heure des Iles Marshall", "MHT", "Heure d'\u00e9t\u00e9 des Iles Marshall", "MHST", "Heure des Iles Marshall", "MHT"}; + String MMT[] = new String[] {"Heure de Myanmar", "MMT", + "Heure d'\u00e9t\u00e9 de Myanmar", "MMST", + "Heure de Myanmar", "MMT"}; String MSK[] = new String[] {"Heure standard de Moscou", "MSK", "Heure avanc\u00e9e de Moscou", "MSD", "Moscou", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Heure de Kyzylorda", "QYZT", "Heure d'\u00e9t\u00e9 de Kyzylorda", "QYZST", "Heure de Kyzylorda", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Heure de Myanmar", "MMT", - "Heure d'\u00e9t\u00e9 de Myanmar", "MMST", - "Heure de Myanmar", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Heure de Sakhalin", "SAKT", @@ -719,6 +720,7 @@ "Heure d'\u00e9t\u00e9 de Vladivostok", "VLAST", "Heure de Vladivostok", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Heure de Yekaterinburg", "YEKT", "Heure d'\u00e9t\u00e9 de Yekaterinburg", "YEKST", "Heure de Yekaterinburg", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_it.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_it.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_it.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"Ora delle Isole Marshall", "MHT", "Ora estiva delle Isole Marshall", "MHST", "Ora delle Isole Marshall", "MHT"}; + String MMT[] = new String[] {"Ora della Birmania/Myanmar", "MMT", + "Ora estiva della Birmania/Myanmar", "MMST", + "Ora della Birmania/Myanmar", "MMT"}; String MSK[] = new String[] {"Ora standard di Mosca", "MSK", "Ora legale di Mosca", "MSD", "Ora Mosca", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Ora di Qyzylorda", "QYZT", "Ora estiva di Qyzylorda", "QYZST", "Ora di Qyzylorda", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Ora della Birmania/Myanmar", "MMT", - "Ora estiva della Birmania/Myanmar", "MMST", - "Ora della Birmania/Myanmar", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Ora di Sakhalin", "SAKT", @@ -719,6 +720,7 @@ "Ora estiva di Vladivostok", "VLAST", "Ora di Vladivostok", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Ora di Ekaterinburg", "YEKT", "Ora estiva di Ekaterinburg", "YEKST", "Ora di Ekaterinburg", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ja.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ja.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ja.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"\u30de\u30fc\u30b7\u30e3\u30eb\u5cf6\u6642\u9593", "MHT", "\u30de\u30fc\u30b7\u30e3\u30eb\u5cf6\u590f\u6642\u9593", "MHST", "\u30DE\u30FC\u30B7\u30E3\u30EB\u8AF8\u5CF6\u6642\u9593", "MHT"}; + String MMT[] = new String[] {"\u30df\u30e3\u30f3\u30de\u30fc\u6642\u9593", "MMT", + "\u30df\u30e3\u30f3\u30de\u30fc\u590f\u6642\u9593", "MMST", + "\u30DF\u30E3\u30F3\u30DE\u30FC\u6642\u9593", "MMT"}; String MSK[] = new String[] {"\u30e2\u30b9\u30af\u30ef\u6a19\u6e96\u6642", "MSK", "\u30e2\u30b9\u30af\u30ef\u590f\u6642\u9593", "MSD", "\u30E2\u30B9\u30AF\u30EF\u6642\u9593", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"\u30ad\u30b8\u30eb\u30aa\u30eb\u30c0\u6642\u9593", "QYZT", "\u30ad\u30b8\u30eb\u30aa\u30eb\u30c0\u590f\u6642\u9593", "QYZST", "\u30AF\u30BA\u30ED\u30EB\u30C0\u6642\u9593", "QYZT"}}, - {"Asia/Rangoon", new String[] {"\u30df\u30e3\u30f3\u30de\u30fc\u6642\u9593", "MMT", - "\u30df\u30e3\u30f3\u30de\u30fc\u590f\u6642\u9593", "MMST", - "\u30DF\u30E3\u30F3\u30DE\u30FC\u6642\u9593", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"\u6a3a\u592a\u6642\u9593", "SAKT", @@ -719,6 +720,7 @@ "\u30a6\u30e9\u30b8\u30aa\u30b9\u30c8\u30af\u590f\u6642\u9593", "VLAST", "\u30A6\u30E9\u30B8\u30AA\u30B9\u30C8\u30AF\u6642\u9593", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"\u30a8\u30ab\u30c6\u30ea\u30f3\u30d6\u30eb\u30b0\u6642\u9593", "YEKT", "\u30a8\u30ab\u30c6\u30ea\u30f3\u30d6\u30eb\u30b0\u590f\u6642\u9593", "YEKST", "\u30A8\u30AB\u30C6\u30EA\u30F3\u30D6\u30EB\u30AF\u6642\u9593", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ko.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ko.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_ko.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"\ub9c8\uc15c\uc81c\ub3c4 \uc2dc\uac04", "MHT", "\ub9c8\uc15c\uc81c\ub3c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MHST", "\uB9C8\uC15C \uC81C\uB3C4 \uD45C\uC900\uC2DC", "MHT"}; + String MMT[] = new String[] {"\ubbf8\uc580\ub9c8 \uc2dc\uac04", "MMT", + "\ubbf8\uc580\ub9c8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MMST", + "\uBBF8\uC580\uB9C8 \uD45C\uC900\uC2DC", "MMT"}; String MSK[] = new String[] {"\ubaa8\uc2a4\ud06c\ubc14 \ud45c\uc900\uc2dc", "MSK", "\ubaa8\uc2a4\ud06c\ubc14 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MSD", "\uBAA8\uC2A4\uD06C\uBC14 \uD45C\uC900\uC2DC", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda \ud45c\uc900\uc2dc", "QYZT", "Qyzylorda \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "QYZST", "\uD0A4\uC9C8\uB85C\uB974\uB2E4 \uD45C\uC900\uC2DC", "QYZT"}}, - {"Asia/Rangoon", new String[] {"\ubbf8\uc580\ub9c8 \uc2dc\uac04", "MMT", - "\ubbf8\uc580\ub9c8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MMST", - "\uBBF8\uC580\uB9C8 \uD45C\uC900\uC2DC", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"\uc0ac\ud560\ub9b0 \uc2dc\uac04", "SAKT", @@ -719,6 +720,7 @@ "\ube14\ub77c\ub514\ubcf4\uc2a4\ud1a1 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "VLAST", "\uBE14\uB77C\uB514\uBCF4\uC2A4\uD1A1 \uD45C\uC900\uC2DC", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"\uc608\uce74\ud14c\ub9b0\ubc84\uadf8 \uc2dc\uac04", "YEKT", "\uc608\uce74\ud14c\ub9b0\ubc84\uadf8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "YEKST", "\uC608\uCE74\uD14C\uB9B0\uBD80\uB974\uD06C \uD45C\uC900\uC2DC", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_pt_BR.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_pt_BR.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_pt_BR.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MSK[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o de Moscou", "MSK", "Hor\u00e1rio de luz natural de Moscou", "MSD", "Hor\u00E1rio de Moscou", "MT"}; + String MMT[] = new String[] {"Fuso hor\u00e1rio de Mianmar", "MMT", + "Fuso hor\u00e1rio de ver\u00e3o de Mianmar", "MMST", + "Hor\u00E1rio de Mianmar", "MMT"}; String MST[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o das montanhas", "MST", "Hor\u00e1rio de luz natural das montanhas", "MDT", "Hor\u00E1rio das Montanhas Rochosas", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Fuso hor\u00e1rio de Kizil-Orda", "QYZT", "Fuso hor\u00e1rio de ver\u00e3o de Kizil-Orda", "QYZST", "Hor\u00E1rio de Qyzylorda", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Fuso hor\u00e1rio de Mianmar", "MMT", - "Fuso hor\u00e1rio de ver\u00e3o de Mianmar", "MMST", - "Hor\u00E1rio de Mianmar", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Fuso hor\u00e1rio de Sakhalina", "SAKT", @@ -719,6 +720,7 @@ "Fuso hor\u00e1rio de ver\u00e3o de Vladivostok", "VLAST", "Hor\u00E1rio de Vladivostok", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Fuso hor\u00e1rio de Yekaterinburgo", "YEKT", "Fuso hor\u00e1rio de ver\u00e3o de Yekaterinburgo", "YEKST", "Hor\u00E1rio de Yekaterinburg", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_sv.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_sv.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_sv.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"Marshall\u00f6arna, normaltid", "MHT", "Marshall\u00f6arna, sommartid", "MHST", "Marshall\u00F6arna-tid", "MHT"}; + String MMT[] = new String[] {"Myanmar, normaltid", "MMT", + "Myanmar, sommartid", "MMST", + "Myanmar-tid", "MMT"}; String MSK[] = new String[] {"Moskva, normaltid", "MSK", "Moskva, sommartid", "MSD", "Moskvas tid", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda, normaltid", "QYZT", "Qyzylorda, sommartid", "QYZST", "Qyzylorda-tid", "QYZT"}}, - {"Asia/Rangoon", new String[] {"Myanmar, normaltid", "MMT", - "Myanmar, sommartid", "MMST", - "Myanmar-tid", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"Sakhalin, normaltid", "SAKT", @@ -719,6 +720,7 @@ "Vladivostok, sommartid", "VLAST", "Vladivostok-tid", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Jekaterinburg, normaltid", "YEKT", "Jekaterinburg, sommartid", "YEKST", "Jekaterinburg-tid", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_CN.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_CN.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_CN.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"\u9a6c\u7ecd\u5c14\u7fa4\u5c9b\u65f6\u95f4", "MHT", "\u9a6c\u7ecd\u5c14\u7fa4\u5c9b\u590f\u4ee4\u65f6", "MHST", "\u9A6C\u7ECD\u5C14\u7FA4\u5C9B\u65F6\u95F4", "MHT"}; + String MMT[] = new String[] {"\u7f05\u7538\u65f6\u95f4", "MMT", + "\u7f05\u7538\u590f\u4ee4\u65f6", "MMST", + "\u7F05\u7538\u65F6\u95F4", "MMT"}; String MSK[] = new String[] {"\u83ab\u65af\u79d1\u6807\u51c6\u65f6\u95f4", "MSK", "\u83ab\u65af\u79d1\u590f\u4ee4\u65f6", "MSD", "\u83AB\u65AF\u79D1\u65F6\u95F4", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda \u65f6\u95f4", "QYZT", "Qyzylorda \u590f\u4ee4\u65f6", "QYZST", "Qyzylorda \u65F6\u95F4", "QYZT"}}, - {"Asia/Rangoon", new String[] {"\u7f05\u7538\u65f6\u95f4", "MMT", - "\u7f05\u7538\u590f\u4ee4\u65f6", "MMST", - "\u7F05\u7538\u65F6\u95F4", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"\u5e93\u9875\u5c9b\u65f6\u95f4", "SAKT", @@ -719,6 +720,7 @@ "\u6d77\u53c2\u5d34\u590f\u4ee4\u65f6", "VLAST", "\u6D77\u53C2\u5D34\u65F6\u95F4", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Yekaterinburg \u65f6\u95f4", "YEKT", "Yekaterinburg \u590f\u4ee4\u65f6", "YEKST", "Yekaterinburg \u65F6\u95F4", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_TW.java --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_TW.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_zh_TW.java Mon Oct 10 13:31:48 2016 -0700 @@ -189,6 +189,9 @@ String MHT[] = new String[] {"\u99ac\u7d39\u723e\u7fa4\u5cf6\u6642\u9593", "MHT", "\u99ac\u7d39\u723e\u7fa4\u5cf6\u590f\u4ee4\u6642\u9593", "MHST", "\u99AC\u7D39\u723E\u7FA4\u5CF6\u6642\u9593", "MHT"}; + String MMT[] = new String[] {"\u7dec\u7538\u6642\u9593", "MMT", + "\u7dec\u7538\u590f\u4ee4\u6642\u9593", "MMST", + "\u7DEC\u7538\u6642\u9593", "MMT"}; String MSK[] = new String[] {"\u83ab\u65af\u79d1\u6a19\u6e96\u6642\u9593", "MSK", "\u83ab\u65af\u79d1\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "MSD", "\u83AB\u65AF\u79D1\u6642\u9593", "MT"}; @@ -684,9 +687,7 @@ {"Asia/Qyzylorda", new String[] {"Qyzylorda \u6642\u9593", "QYZT", "Qyzylorda \u590f\u4ee4\u6642\u9593", "QYZST", "\u514B\u5B5C\u6D1B\u723E\u9054\u6642\u9593", "QYZT"}}, - {"Asia/Rangoon", new String[] {"\u7dec\u7538\u6642\u9593", "MMT", - "\u7dec\u7538\u590f\u4ee4\u6642\u9593", "MMST", - "\u7DEC\u7538\u6642\u9593", "MMT"}}, + {"Asia/Rangoon", MMT}, {"Asia/Riyadh", ARAST}, {"Asia/Saigon", ICT}, {"Asia/Sakhalin", new String[] {"\u5eab\u9801\u5cf6\u6642\u9593", "SAKT", @@ -721,6 +722,7 @@ "\u6d77\u53c3\u5d34\u590f\u4ee4\u6642\u9593", "VLAST", "\u6D77\u53C3\u5D34\u6642\u9593", "VLAT"}}, {"Asia/Yakutsk", YAKT}, + {"Asia/Yangon", MMT}, {"Asia/Yekaterinburg", new String[] {"Yekaterinburg \u6642\u9593", "YEKT", "Yekaterinburg \u590f\u4ee4\u6642\u9593", "YEKST", "\u8449\u5361\u6377\u7433\u5821\u6642\u9593", "YEKT"}}, diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java --- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java Mon Oct 10 13:31:48 2016 -0700 @@ -26,8 +26,6 @@ package com.sun.security.jgss; import org.ietf.jgss.*; -import sun.security.jgss.GSSContextImpl; -import sun.security.krb5.internal.AuthorizationData; /** * The extended GSSContext interface for supporting additional @@ -36,40 +34,6 @@ */ public interface ExtendedGSSContext extends GSSContext { - // The impl is almost identical to GSSContextImpl with only 2 differences: - // 1. It implements the extended interface - // 2. It translates result to data types here in inquireSecContext - static class ExtendedGSSContextImpl extends GSSContextImpl - implements ExtendedGSSContext { - - public ExtendedGSSContextImpl(GSSContextImpl old) { - super(old); - } - - @Override - public Object inquireSecContext(InquireType type) throws GSSException { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission( - new InquireSecContextPermission(type.toString())); - } - Object output = super.inquireSecContext(type.name()); - if (output != null) { - if (type == InquireType.KRB5_GET_AUTHZ_DATA) { - AuthorizationData ad = (AuthorizationData) output; - AuthorizationDataEntry[] authzData = - new AuthorizationDataEntry[ad.count()]; - for (int i = 0; i < ad.count(); i++) { - authzData[i] = new AuthorizationDataEntry( - ad.item(i).adType, ad.item(i).adData); - } - output = authzData; - } - } - return output; - } - } - /** * Return the mechanism-specific attribute associated with {@code type}. *

diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContextImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContextImpl.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,64 @@ +/* + * 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 com.sun.security.jgss; + +import org.ietf.jgss.*; +import sun.security.jgss.GSSContextImpl; +import sun.security.krb5.internal.AuthorizationData; + +// The impl is almost identical to GSSContextImpl with only 2 differences: +// 1. It implements the extended interface +// 2. It translates result to data types here in inquireSecContext +class ExtendedGSSContextImpl extends GSSContextImpl + implements ExtendedGSSContext { + + public ExtendedGSSContextImpl(GSSContextImpl old) { + super(old); + } + + @Override + public Object inquireSecContext(InquireType type) throws GSSException { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission( + new InquireSecContextPermission(type.toString())); + } + Object output = super.inquireSecContext(type.name()); + if (output != null) { + if (type == InquireType.KRB5_GET_AUTHZ_DATA) { + AuthorizationData ad = (AuthorizationData) output; + AuthorizationDataEntry[] authzData = + new AuthorizationDataEntry[ad.count()]; + for (int i = 0; i < ad.count(); i++) { + authzData[i] = new AuthorizationDataEntry( + ad.item(i).adType, ad.item(i).adData); + } + output = authzData; + } + } + return output; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java --- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java Mon Oct 10 13:31:48 2016 -0700 @@ -26,7 +26,6 @@ package com.sun.security.jgss; import org.ietf.jgss.*; -import sun.security.jgss.GSSCredentialImpl; /** * The extended GSSCredential interface for supporting additional @@ -35,14 +34,6 @@ */ public interface ExtendedGSSCredential extends GSSCredential { - static class ExtendedGSSCredentialImpl extends GSSCredentialImpl - implements ExtendedGSSCredential { - - public ExtendedGSSCredentialImpl(GSSCredentialImpl old) { - super(old); - } - } - /** * Impersonates a principal. In Kerberos, this can be implemented * using the Microsoft S4U2self extension. diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredentialImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredentialImpl.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.jgss; + +import sun.security.jgss.GSSCredentialImpl; + +class ExtendedGSSCredentialImpl extends GSSCredentialImpl + implements ExtendedGSSCredential { + + public ExtendedGSSCredentialImpl(GSSCredentialImpl old) { + super(old); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java --- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java Mon Oct 10 13:31:48 2016 -0700 @@ -39,18 +39,18 @@ } public GSSCredential wrap(GSSCredential cred) { - if (cred instanceof ExtendedGSSCredential.ExtendedGSSCredentialImpl) { + if (cred instanceof ExtendedGSSCredentialImpl) { return cred; } else { - return new ExtendedGSSCredential.ExtendedGSSCredentialImpl((GSSCredentialImpl)cred); + return new ExtendedGSSCredentialImpl((GSSCredentialImpl)cred); } } public GSSContext wrap(GSSContext ctxt) { - if (ctxt instanceof ExtendedGSSContext.ExtendedGSSContextImpl) { + if (ctxt instanceof ExtendedGSSContextImpl) { return ctxt; } else { - return new ExtendedGSSContext.ExtendedGSSContextImpl((GSSContextImpl)ctxt); + return new ExtendedGSSContextImpl((GSSContextImpl)ctxt); } } } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/ProblemList.txt Mon Oct 10 13:31:48 2016 -0700 @@ -134,8 +134,6 @@ java/lang/instrument/BootClassPath/BootClassPathTest.sh 8072130 macosx-all -java/lang/instrument/DaemonThread/TestDaemonThread.java 8161225 generic-all - java/lang/instrument/DaemonThread/TestDaemonThread.java 8167001 generic-all java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java Mon Oct 10 13:31:48 2016 -0700 @@ -36,7 +36,6 @@ * @author Yun Ke * @author Bill Situ * @author Yu-Ching (Valerie) PENG - * @run main TestCipherKeyWrapperPBEKey */ public class TestCipherPBECons { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/com/sun/jdi/InterfaceMethodsTest.java --- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Mon Oct 10 13:31:48 2016 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -197,14 +197,18 @@ // invoke interface static method A testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A)); - // try to invoke static method A on the instance - testInvokePos(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A)); + // invoking static method A on the instance fails because static method A is + // not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), + "Invalid MethodID"); // invoke interface static method B testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); - // try to invoke static method B on the instance - testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); + // invoking static method B on the instance fails because static method B is + // not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A), + "Invalid MethodID"); // try to invoke a virtual method testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_A), true); @@ -239,21 +243,25 @@ testInvokeNeg(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), "Static interface methods are not inheritable"); - // however it is possible to call "staticMethodA" on the actual instance + // "staticMethodA" is not inherited by InterfaceB even from an actual instance testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), "Static interface methods are not inheritable"); - // "staticMethodB" is overridden in InterfaceB + // "staticMethodB" is re-defined in InterfaceB testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B)); - // the instance invokes the overriden form of "staticMethodB" from InterfaceB - testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B)); + // the instance fails to invoke the re-defined form of "staticMethodB" from + // InterfaceB because staticMethodB is not inherited by TargetClass + testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B), + "Invalid MethodID"); // "staticMethodC" is present only in InterfaceB testInvokePos(ifaceClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B)); - // "staticMethodC" should be reachable from the instance too - testInvokePos(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B)); + // "staticMethodC" is not reachable from the instance because staticMethodC + // is not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B), + "Invalid MethodID"); } private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/Correctness.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/Correctness.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,182 @@ +/* + * 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 8164705 + * @summary Remove pathname canonicalization from FilePermission + */ + +import java.io.FilePermission; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class Correctness { + + static boolean err = false; + static Method containsMethod; + static boolean isWindows = + System.getProperty("os.name").contains("Windows"); + public static void main(String args[]) throws Exception { + check("/", "/"); + checkNo("/", "/x"); + checkNo("/", "/../x"); + + checkNo("/", "x"); + + check("/-", "/*"); + checkNo("/*", "/-"); + + check("/*", "/x"); + check("/-", "/x"); + check("/-", "/x/*"); + check("/-", "/x/-"); + check("/-", "/x/y"); + checkNo("/*", "/x/y"); + check("/x/*", "/x/x"); + checkNo("/x/-", "/x"); + checkNo("/x/*", "/x"); + check("/x/-", "/x/x"); + check("/x/-", "/x/x/y"); + checkNo("/x/*", "/x/x/y"); + checkNo("/x/*", "/x"); + + check("*", "x"); + checkNo("", "x"); + check("-", "x"); + check("-", "*"); + check("-", "a/-"); + check("-", "a/*"); + checkNo("*", "a/b"); + check("a/*", "a/b"); + check("a/-", "a/*"); + check("a/-", "a/b/c"); + checkNo("a/*", "a/b/c"); + + check("../", "../"); + check("../-", "../*"); + check("../../*", "../../a"); + + // If we allow .. and abs/rel checks + check("../-", "a"); + check("../../-", "-"); + checkNo("../../*", "a"); + //check("/-", "a"); + //checkNo("/*", "a"); + //check("/-", "-"); + + try { + // containsPath is broken on Windows. + containsMethod = FilePermission.class.getDeclaredMethod( + "containsPath", Path.class, Path.class); + containsMethod.setAccessible(true); + System.out.println(); + + contains("x", "x", 0); + contains("x", "x/y", 1); + contains("x", "x/y/z", 2); + contains("x", "y", -1); + contains("x", "", -1); + contains("", "", 0); + contains("", "x", 1); + contains("", "x/y", 2); + contains("/", "/", 0); + contains("/", "/x", 1); + contains("/", "/x/y", 2); + contains("/x", "/x/y", 1); + contains("/x", "/y", -1); + //contains("/", "..", Integer.MAX_VALUE); + //contains("/", "x", Integer.MAX_VALUE); + //contains("/", "x/y", Integer.MAX_VALUE); + //contains("/", "../x", Integer.MAX_VALUE); + contains("/x", "y", -1); + contains("x", "/y", -1); + + contains("", "..", -1); + contains("", "../x", -1); + contains("..", "", 1); + contains("..", "x", 2); + contains("..", "x/y", 3); + contains("../x", "x", -1); + contains("../x", "y", -1); + contains("../x", "../x/y", 1); + contains("../../x", "../../x/y", 1); + contains("../../../x", "../../../x/y", 1); + contains("../x", "../y", -1); + } catch (NoSuchMethodException e) { + // Ignored + } + if (err) throw new Exception("Failed."); + } + + // Checks if s2 is inside s1 and depth is expected. + static void contains(String s1, String s2, int expected) throws Exception { + contains0(s1, s2, expected); + if (isWindows) { + contains0("C:" + s1, s2, -1); + contains0(s1, "C:" + s2, -1); + contains0("C:" + s1, "D:" + s2, -1); + contains0("C:" + s1, "C:" + s2, expected); + } + } + + static void contains0(String s1, String s2, int expected) throws Exception { + Path p1 = Paths.get(s1); + Path p2 = Paths.get(s2); + int d = (int)containsMethod.invoke(null, p1, p2); + Path p; + try { + p = p2.relativize(p1); + } catch (Exception e) { + p = null; + } + System.out.printf("%-20s -> %-20s: %20s %5d %5d %s\n", s1, s2, p, + d, expected, d==expected?"":" WRONG"); + if (d != expected) { + err = true; + } + } + + static void check(String s1, String s2, boolean expected) { + FilePermission fp1 = new FilePermission(s1, "read"); + FilePermission fp2 = new FilePermission(s2, "read"); + boolean b = fp1.implies(fp2); + System.out.printf("%-30s -> %-30s: %5b %s\n", + s1, s2, b, b==expected?"":" WRONG"); + if (b != expected) { + err = true; + System.out.println(fp1); + System.out.println(fp2); + } + } + + static void check(String s1, String s2) { + check(s1, s2, true); + } + + static void checkNo(String s1, String s2) { + check(s1, s2, false); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/FilePermissionCollection.java --- a/jdk/test/java/io/FilePermission/FilePermissionCollection.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/io/FilePermission/FilePermissionCollection.java Mon Oct 10 13:31:48 2016 -0700 @@ -47,14 +47,14 @@ ("test 1: add throws IllegalArgExc for wrong perm type"); try { perms.add(new SecurityPermission("createAccessControlContext")); - System.err.println("Expected IllegalArgumentException"); + System.out.println("Expected IllegalArgumentException"); testFail++; } catch (IllegalArgumentException iae) {} // test 2 System.out.println("test 2: implies returns false for wrong perm type"); if (perms.implies(new SecurityPermission("getPolicy"))) { - System.err.println("Expected false, returned true"); + System.out.println("Expected false, returned true"); testFail++; } @@ -63,7 +63,7 @@ "name and action"); perms.add(new FilePermission("/tmp/foo", "read")); if (!perms.implies(new FilePermission("/tmp/foo", "read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } @@ -71,7 +71,7 @@ System.out.println("test 4: implies returns false for match on " + "name but not action"); if (perms.implies(new FilePermission("/tmp/foo", "write"))) { - System.err.println("Expected false, returned true"); + System.out.println("Expected false, returned true"); testFail++; } @@ -80,7 +80,7 @@ "name and subset of actions"); perms.add(new FilePermission("/tmp/bar", "read, write")); if (!perms.implies(new FilePermission("/tmp/bar", "write"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } @@ -90,11 +90,11 @@ perms.add(new FilePermission("/tmp/baz", "read")); perms.add(new FilePermission("/tmp/baz", "write")); if (!perms.implies(new FilePermission("/tmp/baz", "read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } if (!perms.implies(new FilePermission("/tmp/baz", "write,read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } @@ -103,7 +103,7 @@ "and match on action"); perms.add(new FilePermission("/usr/tmp/*", "read")); if (!perms.implies(new FilePermission("/usr/tmp/foo", "read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } @@ -111,7 +111,7 @@ System.out.println ("test 8: implies returns false for non-match on wildcard"); if (perms.implies(new FilePermission("/usr/tmp/bar/foo", "read"))) { - System.err.println("Expected false, returned true"); + System.out.println("Expected false, returned true"); testFail++; } @@ -120,25 +120,25 @@ ("test 9: implies returns true for deep wildcard match"); perms.add(new FilePermission("/usr/tmp/-", "read")); if (!perms.implies(new FilePermission("/usr/tmp/bar/foo", "read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } // test 10 - System.out.println("test 10: implies returns true for relative match"); + //System.out.println("test 10: implies returns true for relative match"); perms.add(new FilePermission(".", "read")); - if (!perms.implies(new FilePermission(System.getProperty("user.dir"), - "read"))) { - System.err.println("Expected true, returned false"); - testFail++; - } + //if (!perms.implies(new FilePermission(System.getProperty("user.dir"), + // "read"))) { + // System.out.println("Expected true, returned false"); + // testFail++; + //} // test 11 System.out.println("test 11: implies returns true for all " + "wildcard and match on action"); perms.add(new FilePermission("<>", "read")); if (!perms.implies(new FilePermission("/tmp/foobar", "read"))) { - System.err.println("Expected true, returned false"); + System.out.println("Expected true, returned false"); testFail++; } @@ -146,7 +146,7 @@ System.out.println("test 12: implies returns false for wildcard " + "and non-match on action"); if (perms.implies(new FilePermission("/tmp/foobar", "write"))) { - System.err.println("Expected false, returned true"); + System.out.println("Expected false, returned true"); testFail++; } @@ -160,7 +160,7 @@ } // the two "/tmp/baz" entries were combined into one if (numPerms != 7) { - System.err.println("Expected 7, got " + numPerms); + System.out.println("Expected 7, got " + numPerms); testFail++; } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/FilePermissionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/FilePermissionTest.java Mon Oct 10 13:31:48 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. + */ + +import java.io.File; +import java.io.FilePermission; +import java.util.Arrays; +import java.util.List; + +/* + * @test + * @bug 8156054 + * @summary Test some of FilePermission methods when canonicalization property + * set and un-set. + * @run main/othervm -Djdk.io.permissionsUseCanonicalPath=true + * FilePermissionTest truetruetruetruetruetrue + * @run main/othervm -Djdk.io.permissionsUseCanonicalPath=false + * FilePermissionTest falsefalsefalsefalsefalsefalse + * @run main FilePermissionTest falsefalsefalsefalsefalsefalse + */ +public class FilePermissionTest { + + public static void main(String[] args) throws Exception { + + final File realFile = new File("exist.file"); + try { + if (!realFile.createNewFile()) { + throw new RuntimeException("Unable to create a file."); + } + check(Arrays.asList(realFile.getName(), "notexist.file"), args[0]); + } finally { + if (realFile.exists()) { + realFile.delete(); + } + } + } + + private static void check(List files, String expected) { + + StringBuilder actual = new StringBuilder(); + files.forEach(f -> { + StringBuilder result = new StringBuilder(); + FilePermission fp1 = new FilePermission(f, "read"); + FilePermission fp2 = new FilePermission( + new File(f).getAbsolutePath(), "read"); + result.append(fp1.equals(fp2)); + result.append(fp1.implies(fp2)); + result.append(fp1.hashCode() == fp2.hashCode()); + System.out.println(fp1 + " Vs. " + fp2 + " : Result: " + result); + actual.append(result); + }); + if (!expected.equals(actual.toString())) { + throw new RuntimeException("Failed: " + expected + "/" + actual); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/ReadFileOnPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/ReadFileOnPath.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,82 @@ +/* + * 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 8164705 + * @library /lib/testlibrary /test/lib + * @modules java.base/jdk.internal.misc + * @run main ReadFileOnPath + * @summary Still able to read file on the same path + */ + +import jdk.test.lib.process.ProcessTools; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ReadFileOnPath { + + private static final Path SRC_DIR = Paths.get(System.getProperty("test.src")); + private static final Path HERE_DIR = Paths.get("."); + private static final Path MODS_DIR = Paths.get("modules"); + + public static void main(String args[]) throws Exception { + CompilerUtils.compile(SRC_DIR.resolve("m"), MODS_DIR.resolve("m")); + Files.write(MODS_DIR.resolve("m/base"), "base".getBytes()); + Files.write(MODS_DIR.resolve("m/p/child"), "child".getBytes()); + JarUtils.createJarFile(HERE_DIR.resolve("old.jar"), + MODS_DIR.resolve("m"), + "base", "p/App.class", "p/child"); + JarUtils.createJarFile(HERE_DIR.resolve("new.jar"), + MODS_DIR.resolve("m"), + "module-info.class", "base", "p/App.class", "p/child"); + + // exploded module + test("--module-path", "modules", "-m", "m/p.App", "SS+++++"); + + // module in jar + test("--module-path", "new.jar", "-m", "m/p.App", "SSSS++0"); + + // exploded classpath + test("-cp", "modules/m", "p.App", "SS+++++"); + + // classpath in jar + test("-cp", "old.jar", "p.App", "SSSS++0"); + } + + static void test(String... args) throws Exception { + List cmds = new ArrayList<>(); + cmds.add("-Djava.security.manager"); + cmds.addAll(Arrays.asList(args)); + cmds.addAll(List.of( + "x", "modules/m", "modules/m/base", "modules/m/p/child", + "-", "child", "/base", "../base")); + ProcessTools.executeTestJvm(cmds.toArray(new String[cmds.size()])) + .shouldHaveExitValue(0); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/m/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/m/module-info.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,3 @@ +module m { + exports p; +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/FilePermission/m/p/App.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/m/p/App.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,44 @@ +package p; +import java.io.InputStream; +import java.io.FileInputStream; +public class App { + public static void main(String[] args) throws Exception { + boolean f = true; + StringBuilder sb = new StringBuilder(); + String expected = null; + for (String s: args) { + if (expected == null) { + expected = s; + } else if (s.equals("-")) { + f = false; + } else if (f) { + try (InputStream is = new FileInputStream(s)) { + is.readAllBytes(); + sb.append('+'); + } catch (SecurityException se) { + System.out.println(se); + sb.append('S'); + } catch (Exception e) { + System.out.println(e); + sb.append('-'); + } + } else { + try (InputStream is = App.class.getResourceAsStream(s)) { + is.readAllBytes(); + sb.append('+'); + } catch (NullPointerException npe) { + System.out.println(npe); + sb.append('0'); + } catch (Exception e) { + System.out.println(e); + sb.append('-'); + } + } + } + if (!sb.toString().equals(expected)) { + throw new Exception("Expected " + expected + ", actually " + sb); + } else { + System.out.println("OK"); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/CheckInputOrderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/CheckInputOrderTest.java Mon Oct 10 13:31:48 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"); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java Mon Oct 10 13:31:48 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")); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/GlobalFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/GlobalFilterTest.java Mon Oct 10 13:31:48 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); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/MixedFiltersTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/MixedFiltersTest.java Mon Oct 10 13:31:48 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) { } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java Mon Oct 10 13:31:48 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 The pattern + * @param The test object + * @param 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> 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> 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 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(); + } + } + 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 deepHashSet(int depth) { + HashSet hashSet = new HashSet<>(); + HashSet s1 = hashSet; + HashSet s2 = new HashSet<>(); + for (int i = 0; i < depth; i++ ) { + HashSet t1 = new HashSet<>(); + HashSet 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; + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/java.security-extra1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/java.security-extra1 Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/security.policy Mon Oct 10 13:31:48 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 "<>", "read,write,delete"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.security.SecurityPermission "*"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; +}; + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/io/Serializable/serialFilter/security.policy.without.globalFilter --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/Serializable/serialFilter/security.policy.without.globalFilter Mon Oct 10 13:31:48 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 "<>", "read,write,delete"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; +}; + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/lang/ClassLoader/forNameLeak/ClassForName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/forNameLeak/ClassForName.java Mon Oct 10 13:31:48 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. + */ + +import java.net.URLClassLoader; + +/* + * This class is loaded by the custom URLClassLoader, and then calls + * Class.forName(); + */ +public class ClassForName implements Runnable { + static { + if (!(ClassForName.class.getClassLoader() instanceof URLClassLoader)) { + throw new RuntimeException("Supposed to be loaded by URLClassLoader"); + } + } + + public void run() { + try { + Class.forName(java.util.List.class.getName(), false, + ClassLoader.getSystemClassLoader()); + } catch (Throwable e) { + e.printStackTrace(); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/lang/ClassLoader/forNameLeak/ClassForNameLeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/forNameLeak/ClassForNameLeak.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8151486 + * @summary Call Class.forName() on the system classloader from a class loaded + * from a custom classloader. + * @library /lib/testlibrary + * @build jdk.testlibrary.Utils JarUtils + * @build ClassForName ClassForNameLeak + * @run main/othervm/policy=test.policy -Djava.security.manager ClassForNameLeak + */ + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.testlibrary.Utils; + +/* + * Create .jar, load ClassForName from .jar using a URLClassLoader + */ +public class ClassForNameLeak { + private static final long TIMEOUT = (long)(5000.0 * Utils.TIMEOUT_FACTOR); + private static final String TESTCLASSES = System.getProperty("test.classes", "."); + private static final String CLASSFILENAME = "ClassForName.class"; + private static final int THREADS = 10; + private static final ReferenceQueue rq = new ReferenceQueue<>(); + + // Use a new classloader to load the ClassForName class, then run its + // Runnable. + public static PhantomReference loadAndRun(Path jarFilePath) + throws Exception { + ClassLoader classLoader = new URLClassLoader( + new URL[]{jarFilePath.toUri().toURL()}) { + @Override public String toString() { return "LeakedClassLoader"; } + }; + + Class loadClass = Class.forName("ClassForName", true, classLoader); + ((Runnable) loadClass.newInstance()).run(); + + PhantomReference ref = new PhantomReference<>(classLoader, rq); + System.out.println("returning phantom ref: " + ref + " to " + classLoader); + return ref; + } + + public static void main(final String[] args) throws Exception { + // Create a temporary .jar file containing ClassForName.class + Path testClassesDir = Paths.get(TESTCLASSES); + Path jarFilePath = Files.createTempFile("cfn", ".jar"); + JarUtils.createJarFile(jarFilePath, testClassesDir, CLASSFILENAME); + jarFilePath.toFile().deleteOnExit(); + + // Remove the ClassForName.class file that jtreg built, to make sure + // we're loading from the tmp .jar + Path classFile = FileSystems.getDefault().getPath(TESTCLASSES, + CLASSFILENAME); + Files.delete(classFile); + + // Make simultaneous calls to the test method, to stress things a bit + ExecutorService es = Executors.newFixedThreadPool(THREADS); + + List>> callables = + Stream.generate(() -> { + Callable> cprcl = () -> { + return loadAndRun(jarFilePath); + }; + return cprcl; + }).limit(THREADS).collect(Collectors.toList()); + + List>> refs = es.invokeAll(callables); + + // Give the GC a chance to enqueue the PhantomReferences + for (int i = 0; i < 10; i++) { + System.gc(); + } + // Make sure all PhantomReferences to the leaked classloader are enqueued + for (int j = 0; j < THREADS; j++) { + Reference rmRef = rq.remove(TIMEOUT); + if (rmRef == null) { + throw new RuntimeException("ClassLoader was never enqueued!"); + } else { + System.out.println("Enqueued " + rmRef); + } + } + System.out.println("All Classloaders successfully enqued"); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/lang/ClassLoader/forNameLeak/test.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/forNameLeak/test.policy Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,6 @@ +grant { + permission java.io.FilePermission "<>", "read, write, delete"; + permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "getClassLoader"; + permission java.util.PropertyPermission "*", "read"; /* for Utils */ +}; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/lang/Math/FusedMultiplyAddTests.java --- a/jdk/test/java/lang/Math/FusedMultiplyAddTests.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/lang/Math/FusedMultiplyAddTests.java Mon Oct 10 13:31:48 2016 -0700 @@ -221,6 +221,9 @@ {Double.MIN_VALUE, -0.0, +0.0, +0.0}, + + {1.0+Math.ulp(1.0), 1.0+Math.ulp(1.0), -1.0-2.0*Math.ulp(1.0), + Math.ulp(1.0)*Math.ulp(1.0)}, }; for (double[] testCase: testCases) @@ -344,6 +347,9 @@ {Float.MAX_VALUE, 2.0f, 1.0f, InfinityF}, + + {1.0f+Math.ulp(1.0f), 1.0f+Math.ulp(1.0f), -1.0f-2.0f*Math.ulp(1.0f), + Math.ulp(1.0f)*Math.ulp(1.0f)}, }; for (float[] testCase: testCases) diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java --- a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java Mon Oct 10 13:31:48 2016 -0700 @@ -1,6 +1,6 @@ /* * Copyright 2014 Goldman Sachs. - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-javaagent:DummyAgent.jar", "TestDaemonThread", "."); OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); analyzer.shouldNotContain("ASSERTION FAILED"); + analyzer.shouldHaveExitValue(0); } } } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/DatagramSocket/ReuseAddressTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/DatagramSocket/ReuseAddressTest.java Mon Oct 10 13:31:48 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, + *
on: false. + *
Expected results: 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, + *
on: true. + *
Expected results: 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, + *
on: false. + *
Expected results: 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, + *
on: true. + *
Expected results: 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, + *
on: false. + *
Expected results: 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, + *
on: true. + *
Expected results: 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"); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/URLClassLoader/getresourceasstream/Test.java --- a/jdk/test/java/net/URLClassLoader/getresourceasstream/Test.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/URLClassLoader/getresourceasstream/Test.java Mon Oct 10 13:31:48 2016 -0700 @@ -26,12 +26,12 @@ public class Test { public static void main (String[] args) throws Exception { - test1(); + test1(args[0]); } - public static void test1 () throws Exception { + public static void test1 (String s) throws Exception { URLClassLoader cl = new URLClassLoader (new URL[] { - new URL ("file:./test.jar") + new URL ("file:" + s) }); Class clazz = Class.forName ("Test\u00a3", true, cl); InputStream is = clazz.getResourceAsStream ("Test\u00a3.class"); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh --- a/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh Mon Oct 10 13:31:48 2016 -0700 @@ -39,18 +39,33 @@ checkExit () { if [ $? != 0 ]; then - exit 1; + exit $1; fi } ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Test.java cp ${TESTSRC}/test.jar . -${TESTJAVA}/bin/java ${TESTVMOPTS} Test -checkExit +${TESTJAVA}/bin/java ${TESTVMOPTS} Test ./test.jar +checkExit 1 # try with security manager -${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.security.policy=file:./policy -Djava.security.manager Test -checkExit +${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.security.policy=file:./policy \ + -Djava.security.manager Test ./test.jar +checkExit 2 + +mkdir tmp +cd tmp +${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.security.policy=file:../policy \ + -cp .. -Djava.security.manager Test ../test.jar +checkExit 3 + +cd .. +THISDIR=$(basename $(pwd)) +cd .. +${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.security.policy=file:$THISDIR/policy \ + -cp $THISDIR -Djava.security.manager Test $THISDIR/test.jar +checkExit 4 + exit 0 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/httpclient/http2/ErrorTest.java --- a/jdk/test/java/net/httpclient/http2/ErrorTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/httpclient/http2/ErrorTest.java Mon Oct 10 13:31:48 2016 -0700 @@ -28,6 +28,7 @@ * @library /lib/testlibrary * @build jdk.testlibrary.SimpleSSLContext * @modules java.httpclient + * java.security.jgss * @compile/module=java.httpclient java/net/http/BodyOutputStream.java * @compile/module=java.httpclient java/net/http/BodyInputStream.java * @compile/module=java.httpclient java/net/http/EchoHandler.java @@ -41,18 +42,21 @@ * @summary check exception thrown when bad TLS parameters selected */ -import java.io.*; -import java.net.*; -import java.net.http.*; -import static java.net.http.HttpClient.Version.HTTP_2; -import javax.net.ssl.*; -import java.nio.file.*; -import java.util.concurrent.*; +import java.io.IOException; +import java.net.URI; +import java.net.http.EchoHandler; +import java.net.http.HttpClient; +import java.net.http.Http2TestServer; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.ExecutorService; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import jdk.testlibrary.SimpleSSLContext; +import org.testng.annotations.Test; -import org.testng.annotations.Test; -import org.testng.annotations.Parameters; +import static java.net.http.HttpClient.Version.HTTP_2; /** * When selecting an unacceptable cipher suite the TLS handshake will fail. diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/httpclient/http2/HpackDriver.java --- a/jdk/test/java/net/httpclient/http2/HpackDriver.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/httpclient/http2/HpackDriver.java Mon Oct 10 13:31:48 2016 -0700 @@ -33,7 +33,6 @@ * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.CircularBufferTest * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.DecoderTest * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.EncoderTest - * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.HeaderTableTest * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.HuffmanTest * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.TestHelper */ diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/httpclient/http2/HpackDriverHeaderTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/httpclient/http2/HpackDriverHeaderTable.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,35 @@ +/* + * 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 8153353 + * @modules java.httpclient/sun.net.httpclient.hpack + * jdk.localedata + * @key randomness + * @compile/module=java.httpclient sun/net/httpclient/hpack/SpecHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/TestHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/BuffersTestingKit.java + * @run testng/othervm java.httpclient/sun.net.httpclient.hpack.HeaderTableTest + */ +public class HpackDriverHeaderTable { } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/httpclient/security/Driver.java --- a/jdk/test/java/net/httpclient/security/Driver.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/httpclient/security/Driver.java Mon Oct 10 13:31:48 2016 -0700 @@ -23,10 +23,12 @@ * questions. */ -/** +/* * @test * @bug 8087112 * @library /lib/testlibrary/ + * @modules java.httpclient + * jdk.httpserver * @build jdk.testlibrary.SimpleSSLContext jdk.testlibrary.Utils * @compile ../../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../../com/sun/net/httpserver/FileServerHandler.java @@ -43,11 +45,14 @@ * The tests are in Security.java and port number supplied in -Dport.number * and -Dport.number1 for tests that require a second free port */ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import java.io.*; -import java.net.*; import jdk.testlibrary.OutputAnalyzer; import jdk.testlibrary.Utils; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/net/spi/URLStreamHandlerProvider/Basic.java --- a/jdk/test/java/net/spi/URLStreamHandlerProvider/Basic.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/net/spi/URLStreamHandlerProvider/Basic.java Mon Oct 10 13:31:48 2016 -0700 @@ -21,11 +21,19 @@ * questions. */ -import java.io.*; +import java.io.File; +import java.io.FileWriter; +import java.io.Reader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.SequenceInputStream; +import java.io.StringWriter; +import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -46,6 +54,7 @@ * @test * @bug 8064924 * @modules java.compiler + * jdk.compiler * @summary Basic test for URLStreamHandlerProvider * @library /lib/testlibrary * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/security/AccessController/DoPrivAccompliceTest.java --- a/jdk/test/java/security/AccessController/DoPrivAccompliceTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/security/AccessController/DoPrivAccompliceTest.java Mon Oct 10 13:31:48 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 */ diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/security/Security/ClassLoader/DeprivilegedModuleLoaderTest.java --- a/jdk/test/java/security/Security/ClassLoader/DeprivilegedModuleLoaderTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/security/Security/ClassLoader/DeprivilegedModuleLoaderTest.java Mon Oct 10 13:31:48 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) { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/security/Signature/SignatureLength.java --- a/jdk/test/java/security/Signature/SignatureLength.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/security/Signature/SignatureLength.java Mon Oct 10 13:31:48 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 { diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/security/testlibrary/Proc.java --- a/jdk/test/java/security/testlibrary/Proc.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/security/testlibrary/Proc.java Mon Oct 10 13:31:48 2016 -0700 @@ -29,6 +29,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.Permission; +import java.security.Principal; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -37,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -49,7 +51,8 @@ * .args("x") // with args * .env("env", "value") // and an environment variable * .prop("key","value") // and a system property - * .perm(perm) // with granted permissions + * .grant(file) // grant codes in this codebase + * .perm(perm) // with the permission * .start(); // and start * * create/start must be called, args/env/prop/perm can be called zero or @@ -57,7 +60,7 @@ * * The controller can call inheritIO to share its I/O to the process. * Otherwise, it can send data into a proc's stdin with write/println, and - * read its stdout with readLine. stderr is always redirected to DFILE + * read its stdout with readLine. stderr is always redirected to a file * unless nodump() is called. A protocol is designed to make * data exchange among the controller and the processes super easy, in which * useful data are always printed with a special prefix ("PROCISFUN:"). @@ -84,10 +87,10 @@ * * As the Proc objects are hidden so deeply, two static methods, d(String) and * d(Throwable) are provided to output info into stderr, where they will - * normally be appended messages to DFILE (unless nodump() is called). + * normally be appended messages to a debug file (unless nodump() is called). * Developers can view the messages in real time by calling * - * tail -f proc.debug + * {@code tail -f stderr.} * * TODO: * @@ -104,19 +107,24 @@ private BufferedReader br; // the stdout of a process private String launcher; // Optional: the java program - private List perms = new ArrayList<>(); private List args = new ArrayList<>(); private Map env = new HashMap<>(); private Map prop = new HashMap(); private boolean inheritIO = false; private boolean noDump = false; + private List cp; // user-provided classpath private String clazz; // Class to launch private String debug; // debug flag, controller will show data - // transfer between procs + // transfer between procs. If debug is set, + // it MUST be different between Procs. final private static String PREFIX = "PROCISFUN:"; - final private static String DFILE = "proc.debug"; + + // policy file + final private StringBuilder perms = new StringBuilder(); + // temporary saving the grant line in a policy file + final private StringBuilder grant = new StringBuilder(); // The following methods are called by controllers @@ -168,10 +176,68 @@ prop.put(a, b); return this; } - // Adds a perm to policy. Can be called multiple times. In order to make it - // effective, please also call prop("java.security.manager", ""). + // Sets classpath. If not called, Proc will choose a classpath. If called + // with no arg, no classpath will be used. Can be called multiple times. + public Proc cp(String... s) { + if (cp == null) { + cp = new ArrayList<>(); + } + cp.addAll(Arrays.asList(s)); + return this; + } + // Adds a permission to policy. Can be called multiple times. + // All perm() calls after a series of grant() calls are grouped into + // a single grant block. perm() calls before any grant() call are grouped + // into a grant block with no restriction. + // Please note that in order to make permissions effective, also call + // prop("java.security.manager", ""). public Proc perm(Permission p) { - perms.add(p); + if (grant.length() != 0) { // Right after grant(s) + if (perms.length() != 0) { // Not first block + perms.append("};\n"); + } + perms.append("grant ").append(grant).append(" {\n"); + grant.setLength(0); + } else { + if (perms.length() == 0) { // First block w/o restriction + perms.append("grant {\n"); + } + } + if (p.getActions().isEmpty()) { + String s = String.format("%s \"%s\"", + p.getClass().getCanonicalName(), + p.getName() + .replace("\\", "\\\\").replace("\"", "\\\"")); + perms.append(" permission ").append(s).append(";\n"); + } else { + String s = String.format("%s \"%s\", \"%s\"", + p.getClass().getCanonicalName(), + p.getName() + .replace("\\", "\\\\").replace("\"", "\\\""), + p.getActions()); + perms.append(" permission ").append(s).append(";\n"); + } + return this; + } + + // Adds a grant option to policy. If called in a row, a single grant block + // with all options will be created. If there are perm() call(s) between + // grant() calls, they belong to different grant blocks + + // grant on a principal + public Proc grant(Principal p) { + grant.append("principal ").append(p.getClass().getName()) + .append(" \"").append(p.getName()).append("\", "); + return this; + } + // grant on a codebase + public Proc grant(File f) { + grant.append("codebase \"").append(f.toURI()).append("\", "); + return this; + } + // arbitrary grant + public Proc grant(String v) { + grant.append(v).append(", "); return this; } // Starts the proc @@ -191,30 +257,22 @@ Collections.addAll(cmd, splitProperty("test.vm.opts")); Collections.addAll(cmd, splitProperty("test.java.opts")); - cmd.add("-cp"); - cmd.add(System.getProperty("test.class.path") + File.pathSeparator + - System.getProperty("test.src.path")); + if (cp == null) { + cmd.add("-cp"); + cmd.add(System.getProperty("test.class.path") + File.pathSeparator + + System.getProperty("test.src.path")); + } else if (!cp.isEmpty()) { + cmd.add("-cp"); + cmd.add(cp.stream().collect(Collectors.joining(File.pathSeparator))); + } for (Entry e: prop.entrySet()) { cmd.add("-D" + e.getKey() + "=" + e.getValue()); } - if (!perms.isEmpty()) { - Path p = Files.createTempFile( - Paths.get(".").toAbsolutePath(), "policy", null); - StringBuilder sb = new StringBuilder(); - sb.append("grant {\n"); - for (Permission perm: perms) { - // Sometimes a permission has no name or actions. - // but it's safe to use an empty string. - String s = String.format("%s \"%s\", \"%s\"", - perm.getClass().getCanonicalName(), - perm.getName() - .replace("\\", "\\\\").replace("\"", "\\\""), - perm.getActions()); - sb.append(" permission ").append(s).append(";\n"); - } - sb.append("};\n"); - Files.write(p, sb.toString().getBytes()); + if (perms.length() > 0) { + Path p = Paths.get(getId("policy")).toAbsolutePath(); + perms.append("};\n"); + Files.write(p, perms.toString().getBytes()); cmd.add("-Djava.security.policy=" + p.toString()); } cmd.add(clazz); @@ -223,6 +281,15 @@ } if (debug != null) { System.out.println("PROC: " + debug + " cmdline: " + cmd); + for (String c : cmd) { + if (c.indexOf('\\') >= 0 || c.indexOf(' ') > 0) { + System.out.print('\'' + c + '\''); + } else { + System.out.print(c); + } + System.out.print(' '); + } + System.out.println(); } ProcessBuilder pb = new ProcessBuilder(cmd); for (Entry e: env.entrySet()) { @@ -233,12 +300,17 @@ } else if (noDump) { pb.redirectError(ProcessBuilder.Redirect.INHERIT); } else { - pb.redirectError(ProcessBuilder.Redirect.appendTo(new File(DFILE))); + pb.redirectError(ProcessBuilder.Redirect + .appendTo(new File(getId("stderr")))); } p = pb.start(); br = new BufferedReader(new InputStreamReader(p.getInputStream())); return this; } + String getId(String prefix) { + if (debug != null) return prefix + "." + debug; + else return prefix + "." + System.identityHashCode(this); + } // Reads a line from stdout of proc public String readLine() throws IOException { String s = br.readLine(); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/text/Format/DecimalFormat/Bug8165466.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/text/Format/DecimalFormat/Bug8165466.java Mon Oct 10 13:31:48 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 + + "]"); + } + } + +} + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java --- a/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java Mon Oct 10 13:31:48 2016 -0700 @@ -49,7 +49,7 @@ /* * @test - * @bug 8081022 8151876 + * @bug 8081022 8151876 8166875 * @key randomness */ diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/time/test/java/time/format/ZoneName.java --- a/jdk/test/java/time/test/java/time/format/ZoneName.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/time/test/java/time/format/ZoneName.java Mon Oct 10 13:31:48 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 @@ -378,6 +378,7 @@ "Europe/Helsinki", "Europe_Eastern", "Europe/Bucharest", "America/Nome", "Alaska", "America/Juneau", "Asia/Yakutsk", "Yakutsk", "Asia/Yakutsk", + "Asia/Yangon", "Myanmar", "Asia/Rangoon", "Africa/Conakry", "GMT", "Atlantic/Reykjavik", "Asia/Seoul", "Korea", "Asia/Seoul", "America/Antigua", "Atlantic", "America/Halifax", @@ -747,6 +748,7 @@ "NZ", "Pacific/Auckland", "Asia/Tel_Aviv", "Asia/Jerusalem", "Hongkong", "Asia/Hong_Kong", + "Asia/Rangoon", "Asia/Yangon", }; private static final Map zidToMzone = new HashMap<>(); diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/util/TimeZone/TimeZoneTest.java --- a/jdk/test/java/util/TimeZone/TimeZoneTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/java/util/TimeZone/TimeZoneTest.java Mon Oct 10 13:31:48 2016 -0700 @@ -24,7 +24,7 @@ /* * @test * @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483 - * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 + * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 * @modules java.base/sun.util.resources * @library /java/text/testlib * @summary test TimeZone diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/java/util/spi/ToolProviderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/spi/ToolProviderTest.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,105 @@ +/* + * 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 8159855 + * @summary test ToolProvider SPI + * @run main/othervm ToolProviderTest + */ + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.spi.ToolProvider; + +public class ToolProviderTest { + public static void main(String... args) throws Exception { + ToolProviderTest t = new ToolProviderTest(); + t.run(); + } + + void run() throws Exception { + initServices(); + + System.out.println("test without security manager present:"); + test(); + + System.setSecurityManager(new SecurityManager()); + + System.out.println("test with security manager present:"); + test(); + } + + private void test() throws Exception { + ToolProvider testProvider = ToolProvider.findFirst("test").get(); + int rc = testProvider.run(System.out, System.err, "hello test"); + if (rc != 0) { + throw new Exception("unexpected exit code: " + rc); + } + } + + private void initServices() throws IOException { + Path testClasses = Paths.get(System.getProperty("test.classes")); + Path services = testClasses.resolve(Paths.get("META-INF", "services")); + Files.createDirectories(services); + Files.write(services.resolve(ToolProvider.class.getName()), + Arrays.asList(TestProvider.class.getName())); + } + + public static class TestProvider implements ToolProvider { + public TestProvider() { + checkPrivileges(); + } + + public String name() { + return "test"; + } + + public int run(PrintWriter out, PrintWriter err, String... args) { + out.println("Test: " + Arrays.toString(args)); + return 0; + } + + private void checkPrivileges() { + boolean haveSecurityManager = (System.getSecurityManager() != null); + try { + // validate appropriate privileges by checking access to a + // system property + System.getProperty("java.home"); + if (haveSecurityManager) { + throw new Error("exception exception not thrown"); + } + } catch (SecurityException e) { + if (!haveSecurityManager) { + throw new Error("unexpected exception: " + e); + } + } + } + } +} + diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java --- a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java Mon Oct 10 13:31:48 2016 -0700 @@ -22,7 +22,6 @@ */ import jdk.internal.misc.Unsafe; -import java.lang.reflect.Field; /* * @test @@ -40,7 +39,6 @@ */ private void testPositive() { testSmallCopy(false); - testLargeCopy(false); } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,58 @@ +/* + * 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.internal.misc.Unsafe; + +/* + * @test + * @summary Test Unsafe.copyMemory + * @modules java.base/jdk.internal.misc + * @requires os.maxMemory > 8G + */ +public class CopyMemoryLarge extends CopyCommon { + private CopyMemoryLarge() { + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testLargeCopy(false); + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + } + + public static void main(String[] args) { + CopyMemoryLarge cs = new CopyMemoryLarge(); + cs.test(); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/jdk/internal/misc/Unsafe/CopySwap.java --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java Mon Oct 10 13:31:48 2016 -0700 @@ -22,7 +22,6 @@ */ import jdk.internal.misc.Unsafe; -import java.lang.reflect.Field; /* * @test @@ -40,7 +39,6 @@ */ private void testPositive() { testSmallCopy(true); - testLargeCopy(true); } /** diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,58 @@ +/* + * 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.internal.misc.Unsafe; + +/* + * @test + * @summary Test Unsafe.copySwapMemory + * @modules java.base/jdk.internal.misc + * @requires os.maxMemory > 8G + */ +public class CopySwapLarge extends CopyCommon { + private CopySwapLarge() { + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testLargeCopy(true); + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + } + + public static void main(String[] args) { + CopySwapLarge cs = new CopySwapLarge(); + cs.test(); + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java --- a/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java Mon Oct 10 13:31:48 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.*; diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java --- a/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java Mon Oct 10 13:31:48 2016 -0700 @@ -27,6 +27,7 @@ * @summary Test that URL connections to multi-release jars can be runtime versioned * @library /lib/testlibrary/java/util/jar * @modules java.compiler + * jdk.compiler * jdk.httpserver * jdk.jartool * @build Compiler JarBuilder CreateMultiReleaseTestJars SimpleHttpServer diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/security/provider/PolicyFile/CanonPath.java --- a/jdk/test/sun/security/provider/PolicyFile/CanonPath.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/security/provider/PolicyFile/CanonPath.java Mon Oct 10 13:31:48 2016 -0700 @@ -150,9 +150,9 @@ // // on unix, /- implies everything - if (w.implies(u) || !u.implies(w)) { - throw new Exception("SLASH/- test failed"); - } + //if (w.implies(u) || !u.implies(w)) { + // throw new Exception("SLASH/- test failed"); + //} } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/security/util/FilePermCompat/CompatImpact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/util/FilePermCompat/CompatImpact.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2013, 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 8164705 + * @summary check compatibility after FilePermission change + * @library /java/security/testlibrary/ + * @modules java.base/jdk.internal.misc + * @run main CompatImpact prepare + * @run main CompatImpact builtin + * @run main CompatImpact mine + * @run main CompatImpact dopriv + */ + +import java.io.File; +import java.io.FilePermission; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.security.SecurityPermission; + +public class CompatImpact { + + public static void main(String[] args) throws Exception { + switch (args[0]) { + // copy class files to future classpath + case "prepare": + // cp in . + String cp = System.getProperty("test.classes"); + Files.copy(Paths.get(cp, "CompatImpact.class"), + Paths.get("CompatImpact.class")); + Files.copy(Paths.get(cp, "CompatImpact$MP.class"), + Paths.get("CompatImpact$MP.class")); + Files.write(Paths.get("f"), new byte[10]); + // cp in ./sub + Files.createDirectory(Paths.get("sub")); + Files.copy(Paths.get(cp, "CompatImpact.class"), + Paths.get("sub", "CompatImpact.class")); + Files.copy(Paths.get(cp, "CompatImpact$MP.class"), + Paths.get("sub", "CompatImpact$MP.class")); + Files.write(Paths.get("sub", "f"), new byte[10]); + // cp in ./inner + Files.createDirectory(Paths.get("inner")); + Files.copy(Paths.get(cp, "CompatImpact$DoPrivInner.class"), + Paths.get("inner", "CompatImpact$DoPrivInner.class")); + break; + // run tests with different policy impls + case "builtin": + case "mine": + cp = System.getProperty("test.classes"); + Proc p; + String failed = ""; + String testcase = ""; + String cwd = System.getProperty("user.dir"); + + // Granting a FilePermission on an absolute path + testcase = "PonA"; + p = p(args[0], cwd + "/f") + .args("f", cwd + "/f") + .debug(testcase) + .start(); + if (p.waitFor() != 0) { + Files.copy(Paths.get("stderr." + testcase), System.out); + failed += testcase + " "; + } + + // Granting a FilePermission on a relative path + testcase = "PonR"; + p = p(args[0], "f") + .args("f", cwd + "/f") + .debug(testcase) + .start(); + if (p.waitFor() != 0) { + Files.copy(Paths.get("stderr." + testcase), System.out); + failed += testcase + " "; + } + + // Reading file on classpath, not cwd + testcase = "cp"; + String cprel = Paths.get(cwd).relativize(Paths.get(cp)) + .normalize().toString(); + p = p(args[0], "x") + .args(cp + "/f", cprel + "/f") + .debug(testcase) + .start(); + if (p.waitFor() != 0) { + Files.copy(Paths.get("stderr." + testcase), System.out); + failed += testcase + " "; + } + + // Reading file on classpath, cwd + testcase = "cpHere"; + p = p(args[0], "x") + .args(cwd + "/f", "f", "RES") + .cp(".") // Must! cancel the old CLASSPATH. + .debug(testcase) + .start(); + if (p.waitFor() != 0) { + Files.copy(Paths.get("stderr." + testcase), System.out); + failed += testcase + " "; + } + + // Reading file on classpath, cwd + testcase = "cpSub"; + p = p(args[0], "x") + .args(cwd + "/sub/f", "sub/f", "RES") + .cp("sub") // Must! There's CLASSPATH. + .debug(testcase) + .start(); + if (p.waitFor() != 0) { + Files.copy(Paths.get("stderr." + testcase), System.out); + failed += testcase + " "; + } + + if (!failed.isEmpty()) { + throw new Exception(failed + "failed"); + } + break; + // test + case "test": + if (args[1].equals("mine")) { + Policy.setPolicy(new MP(args[2])); + } + Exception e = null; + for (int i = 3; i < args.length; i++) { + try { + System.out.println(args[i]); + if (args[i].equals("RES")) { + CompatImpact.class.getResourceAsStream("f") + .close(); + } else { + new File(args[i]).exists(); + } + } catch (Exception e2) { + e = e2; + e2.printStackTrace(System.out); + } + } + if (e != null) { + System.err.println("===================="); + throw e; + } + break; + // doPrivWithPerm test launcher + case "dopriv": + cwd = System.getProperty("user.dir"); + // caller (CompatImpact doprivouter, no permission) in sub, + // executor (DoPrivInner, AllPermission) in inner. + p = Proc.create("CompatImpact") + .args("doprivouter") + .prop("java.security.manager", "") + .grant(new File("inner")) + .perm(new AllPermission()) + .cp("sub", "inner") + .debug("doPriv") + .args(cwd) + .start(); + if (p.waitFor() != 0) { + throw new Exception("dopriv test fails"); + } + break; + // doprivouter + case "doprivouter": + DoPrivInner.main(args); + break; + default: + throw new Exception("unknown " + args[0]); + } + } + + // Call by CompatImpact doprivouter, with AllPermission + public static class DoPrivInner { + public static void main(String[] args) throws Exception { + AccessController.doPrivileged((PrivilegedAction) + () -> new File("x").exists(), + null, + new FilePermission(args[1] + "/x", "read")); + AccessController.doPrivileged((PrivilegedAction) + () -> new File(args[1] + "/x").exists(), + null, + new FilePermission("x", "read")); + try { + AccessController.doPrivileged((PrivilegedAction) + () -> new File("x").exists(), + null, + new FilePermission("y", "read")); + throw new Exception("Should not read"); + } catch (SecurityException se) { + // Expected + } + } + } + + // Return a Proc object for different policy types + private static Proc p(String type, String f) throws Exception { + Proc p = Proc.create("CompatImpact") + .prop("java.security.manager", ""); + p.args("test", type); + switch (type) { + case "builtin": + // For builtin policy, reading access to f can be + // granted as a permission + p.perm(new FilePermission(f, "read")); + p.args("-"); + break; + case "mine": + // For my policy, f is passed into test and new MP(f) + // will be set as new policy + p.perm(new SecurityPermission("setPolicy")); + p.args(f); + break; + default: + throw new Exception("unknown " + type); + } + return p; + } + + // My own Policy impl, with only one granted permission, also not smart + // enough to know whether ProtectionDomain grants any permission + static class MP extends Policy { + final PermissionCollection pc; + MP(String f) { + FilePermission p = new FilePermission(f, "read"); + pc = p.newPermissionCollection(); + pc.add(p); + } + @Override + public PermissionCollection getPermissions(CodeSource codesource) { + return pc; + } + + @Override + public PermissionCollection getPermissions(ProtectionDomain domain) { + return pc; + } + + @Override + public boolean implies(ProtectionDomain domain, Permission permission) { + return pc.implies(permission); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/security/util/FilePermCompat/Flag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/util/FilePermCompat/Flag.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, 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 8164705 + * @summary check jdk.filepermission.canonicalize + * @library /java/security/testlibrary/ + * @modules java.base/jdk.internal.misc + * @run main/othervm -Djdk.io.permissionsUseCanonicalPath=true Flag truetrue + * @run main/othervm -Djdk.io.permissionsUseCanonicalPath=false Flag falsetrue + * @run main/othervm Flag falsetrue + */ + +import java.io.File; +import java.io.FilePermission; +import java.lang.*; +import java.security.Permission; +import java.security.Policy; +import java.security.ProtectionDomain; + +public class Flag { + public static void main(String[] args) throws Exception { + + boolean test1; + boolean test2; + + String here = System.getProperty("user.dir"); + File abs = new File(here, "x"); + FilePermission fp1 = new FilePermission("x", "read"); + FilePermission fp2 = new FilePermission(abs.toString(), "read"); + test1 = fp1.equals(fp2); + + Policy pol = new Policy() { + @java.lang.Override + public boolean implies(ProtectionDomain domain, Permission permission) { + return fp1.implies(permission); + } + }; + + Policy.setPolicy(pol); + System.setSecurityManager(new SecurityManager()); + try { + System.getSecurityManager().checkPermission(fp2); + test2 = true; + } catch (SecurityException se) { + test2 = false; + } + + if (!args[0].equals(test1 + "" + test2)) { + throw new Exception("Test failed: " + test1 + test2); + } + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/VERSION --- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION Mon Oct 10 13:31:48 2016 -0700 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016f +tzdata2016g diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/africa --- a/jdk/test/sun/util/calendar/zi/tzdata/africa Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/africa Mon Oct 10 13:31:48 2016 -0700 @@ -487,7 +487,7 @@ # http://www.libyaherald.com/2013/10/24/correction-no-time-change-tomorrow/ # # From Paul Eggert (2013-10-25): -# For now, assume they're reverting to the pre-2012 rules of permanent UTC+2. +# For now, assume they're reverting to the pre-2012 rules of permanent UT +02. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Libya 1951 only - Oct 14 2:00 1:00 S diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/antarctica --- a/jdk/test/sun/util/calendar/zi/tzdata/antarctica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/antarctica Mon Oct 10 13:31:48 2016 -0700 @@ -33,9 +33,7 @@ # http://www.spri.cam.ac.uk/bob/periant.htm # for information. # Unless otherwise specified, we have no time zone information. -# -# Except for the French entries, -# I made up all time zone abbreviations mentioned here; corrections welcome! + # FORMAT is '-00' and GMTOFF is 0 for locations while uninhabited. # Argentina - year-round bases @@ -52,7 +50,7 @@ # previously sealers and scientific personnel wintered # Margaret Turner reports # http://web.archive.org/web/20021204222245/http://www.dstc.qut.edu.au/DST/marg/daylight.html -# (1999-09-30) that they're UTC+5, with no DST; +# (1999-09-30) that they're UT +05, with no DST; # presumably this is when they have visitors. # # year-round bases @@ -91,23 +89,22 @@ # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 - 8:00 - AWST 2009 Oct 18 2:00 - # Australian Western Std Time - 11:00 - CAST 2010 Mar 5 2:00 # Casey Time - 8:00 - AWST 2011 Oct 28 2:00 - 11:00 - CAST 2012 Feb 21 17:00u - 8:00 - AWST + 8:00 - +08 2009 Oct 18 2:00 + 11:00 - +11 2010 Mar 5 2:00 + 8:00 - +08 2011 Oct 28 2:00 + 11:00 - +11 2012 Feb 21 17:00u + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 - 7:00 - DAVT 1964 Nov # Davis Time + 7:00 - +07 1964 Nov 0 - -00 1969 Feb - 7:00 - DAVT 2009 Oct 18 2:00 - 5:00 - DAVT 2010 Mar 10 20:00u - 7:00 - DAVT 2011 Oct 28 2:00 - 5:00 - DAVT 2012 Feb 21 20:00u - 7:00 - DAVT + 7:00 - +07 2009 Oct 18 2:00 + 5:00 - +05 2010 Mar 10 20:00u + 7:00 - +07 2011 Oct 28 2:00 + 5:00 - +05 2012 Feb 21 20:00u + 7:00 - +07 Zone Antarctica/Mawson 0 - -00 1954 Feb 13 - 6:00 - MAWT 2009 Oct 18 2:00 # Mawson Time - 5:00 - MAWT + 6:00 - +06 2009 Oct 18 2:00 + 5:00 - +05 # References: # Casey Weather (1998-02-26) # http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html @@ -161,7 +158,7 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français - 5:00 - TFT # ISO code TF Time + 5:00 - +05 # # year-round base in the main continent # Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11 @@ -172,9 +169,9 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/DumontDUrville 0 - -00 1947 - 10:00 - PMT 1952 Jan 14 # Port-Martin Time + 10:00 - +10 1952 Jan 14 0 - -00 1956 Nov - 10:00 - DDUT # Dumont-d'Urville Time + 10:00 - +10 # France & Italy - year-round base # Concordia, -750600+1232000, since 2005 @@ -200,7 +197,7 @@ # station of Japan, it's appropriate for the principal location. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Syowa 0 - -00 1957 Jan 29 - 3:00 - SYOT # Syowa Time + 3:00 - +03 # See: # NIPR Antarctic Research Activities (1999-08-17) # http://www.nipr.ac.jp/english/ara01.html @@ -237,17 +234,17 @@ # correct, but they should be quite close to the actual dates. # # From Paul Eggert (2014-03-21): -# The CET-switching Troll rules require zic from tzcode 2014b or later, so as +# The CET-switching Troll rules require zic from tz 2014b or later, so as # suggested by Bengt-Inge Larsson comment them out for now, and approximate # with only UTC and CEST. Uncomment them when 2014b is more prevalent. # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -#Rule Troll 2005 max - Mar 1 1:00u 1:00 CET -Rule Troll 2005 max - Mar lastSun 1:00u 2:00 CEST -#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 CET -#Rule Troll 2004 max - Nov 7 1:00u 0:00 UTC +#Rule Troll 2005 max - Mar 1 1:00u 1:00 +01 +Rule Troll 2005 max - Mar lastSun 1:00u 2:00 +02 +#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 +01 +#Rule Troll 2004 max - Nov 7 1:00u 0:00 +00 # Remove the following line when uncommenting the above '#Rule' lines. -Rule Troll 2004 max - Oct lastSun 1:00u 0:00 UTC +Rule Troll 2004 max - Oct lastSun 1:00u 0:00 +00 # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Troll 0 - -00 2005 Feb 12 0:00 Troll %s @@ -288,10 +285,10 @@ # changes during the year and does not necessarily correspond to mean # solar noon. So the Vostok time might have been whatever the clocks # happened to be during their visit. So we still don't really know what time -# it is at Vostok. But we'll guess UTC+6. +# it is at Vostok. But we'll guess +06. # Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 6:00 - VOST # Vostok time + 6:00 - +06 # S Africa - year-round bases # Marion Island, -4653+03752 @@ -324,7 +321,7 @@ # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Rothera 0 - -00 1976 Dec 1 - -3:00 - ROTT # Rothera time + -3:00 - -03 # Uruguay - year round base # Artigas, King George Island, -621104-0585107 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/asia --- a/jdk/test/sun/util/calendar/zi/tzdata/asia Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia Mon Oct 10 13:31:48 2016 -0700 @@ -139,13 +139,11 @@ # http://www.worldtimezone.com/dst_news/dst_news_armenia03.html # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2 - 3:00 - YERT 1957 Mar # Yerevan Time - 4:00 RussiaAsia YER%sT 1991 Mar 31 2:00s - 3:00 1:00 YERST 1991 Sep 23 # independence - 3:00 RussiaAsia AM%sT 1995 Sep 24 2:00s - 4:00 - AMT 1997 - 4:00 RussiaAsia AM%sT 2012 Feb 9 - 4:00 - AMT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s + 4:00 - +04 1997 + 4:00 RussiaAsia +04/+05 # Azerbaijan @@ -166,13 +164,12 @@ Rule Azer 1997 2015 - Oct lastSun 5:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Baku 3:19:24 - LMT 1924 May 2 - 3:00 - BAKT 1957 Mar # Baku Time - 4:00 RussiaAsia BAK%sT 1991 Mar 31 2:00s - 3:00 1:00 BAKST 1991 Aug 30 # independence - 3:00 RussiaAsia AZ%sT 1992 Sep lastSun 2:00s - 4:00 - AZT 1996 # Azerbaijan Time - 4:00 EUAsia AZ%sT 1997 - 4:00 Azer AZ%sT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s + 4:00 - +04 1996 + 4:00 EUAsia +04/+05 1997 + 4:00 Azer +04/+05 # Bahrain # See Asia/Qatar. @@ -291,7 +288,7 @@ # Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon. # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Asia/Rangoon 6:24:40 - LMT 1880 # or Yangon +Zone Asia/Yangon 6:24:40 - LMT 1880 # or Rangoon 6:24:40 - RMT 1920 # Rangoon Mean Time? 6:30 - BURT 1942 May # Burma Time 9:00 - JST 1945 May 3 @@ -406,7 +403,7 @@ # Lewiston (ME) Daily Sun (1939-05-29), p 17, said "Even the time is # different - the occupied districts going by Tokyo time, an hour # ahead of that prevailing in the rest of Shanghai." Guess that the -# Xujiahui Observatory was under French control and stuck with UT+8. +# Xujiahui Observatory was under French control and stuck with UT +08. # # In earlier versions of this file, China had many separate Zone entries, but # this was based on what were apparently incorrect data in Shanks & Pottenger. @@ -415,26 +412,26 @@ # Proposed in 1918 and theoretically in effect until 1949 (although in practice # mainly observed in coastal areas), the five zones were: # -# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT+8.5 +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT +08:30 # Asia/Harbin (currently a link to Asia/Shanghai) # Heilongjiang (except Mohe county), Jilin # -# Zhongyuan Time ("Central plain Time") UT+8 +# Zhongyuan Time ("Central plain Time") UT +08 # Asia/Shanghai # most of China # This currently represents most other zones as well, # as apparently these regions have been the same since 1970. # Milne gives 8:05:43.2 for Xujiahui Observatory time; round to nearest. -# Guo says Shanghai switched to UT+8 "from the end of the 19th century". +# Guo says Shanghai switched to UT +08 "from the end of the 19th century". # -# Long-shu Time (probably due to Long and Shu being two names of that area) UT+7 +# Long-shu Time (probably due to Long and Shu being two names of the area) UT +07 # Asia/Chongqing (currently a link to Asia/Shanghai) # Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan; # most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong # counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing, # Yangchun, Yangjiang, Yu'nan, and Yunfu. # -# Xin-zang Time ("Xinjiang-Tibet Time") UT+6 +# Xin-zang Time ("Xinjiang-Tibet Time") UT +06 # Asia/Urumqi # This currently represents Kunlun Time as well, # as apparently the two regions have been the same since 1970. @@ -447,7 +444,7 @@ # Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami, # Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan. # -# Kunlun Time UT+5.5 +# Kunlun Time UT +05:30 # Asia/Kashgar (currently a link to Asia/Urumqi) # West Tibet, including Pulan, Aheqi, Shufu, Shule; # West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke, @@ -463,7 +460,7 @@ # # On the other hand, ethnic Uyghurs, who make up about half the # population of Xinjiang, typically use "Xinjiang time" which is two -# hours behind Beijing time, or UTC +0600. The government of the Xinjiang +# hours behind Beijing time, or UT +06. The government of the Xinjiang # Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as # local governments such as the Ürümqi city government use both times in # publications, referring to what is popularly called Xinjiang time as @@ -519,8 +516,8 @@ # having the same time as Beijing. # From Paul Eggert (2014-06-30): -# In the early days of the PRC, Tibet was given its own time zone (UT+6) but -# this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, +# In the early days of the PRC, Tibet was given its own time zone (UT +06) +# but this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, # Memories of life in Lhasa under Chinese Rule, Columbia U Press, ISBN # 978-0231142861 (2008), translator's introduction by Matthew Akester, p x. # As this is before our 1970 cutoff, Tibet doesn't need a separate zone. @@ -534,12 +531,12 @@ # Republics, the Soviet Union, the Kuomintang, and the People's Republic of # China, and tracking down all these organizations' timekeeping rules would be # quite a trick. Approximate this lost history by a transition from LMT to -# XJT at the start of 1928, the year of accession of the warlord Jin Shuren, +# UT +06 at the start of 1928, the year of accession of the warlord Jin Shuren, # which happens to be the date given by Shanks & Pottenger (no doubt as a -# guess) as the transition from LMT. Ignore the usage of UT+8 before -# 1986-02-01 under the theory that the transition date to UT+8 is unknown and +# guess) as the transition from LMT. Ignore the usage of +08 before +# 1986-02-01 under the theory that the transition date to +08 is unknown and # that the sort of users who prefer Asia/Urumqi now typically ignored the -# UT+8 mandate back then. +# +08 mandate back then. # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Beijing time, used throughout China; represented by Shanghai. @@ -744,7 +741,7 @@ # be found from historical government announcement database. # From Paul Eggert (2014-07-03): -# As per Yu-Cheng Chuang, say that Taiwan was at UT+9 from 1937-10-01 +# As per Yu-Cheng Chuang, say that Taiwan was at UT +09 from 1937-10-01 # until 1945-09-21 at 01:00, overriding Shanks & Pottenger. # Likewise, use Yu-Cheng Chuang's data for DST in Taiwan. @@ -858,16 +855,15 @@ # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Tbilisi 2:59:11 - LMT 1880 2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time - 3:00 - TBIT 1957 Mar # Tbilisi Time - 4:00 RussiaAsia TBI%sT 1991 Mar 31 2:00s - 3:00 1:00 TBIST 1991 Apr 9 # independence - 3:00 RussiaAsia GE%sT 1992 # Georgia Time - 3:00 E-EurAsia GE%sT 1994 Sep lastSun - 4:00 E-EurAsia GE%sT 1996 Oct lastSun - 4:00 1:00 GEST 1997 Mar lastSun - 4:00 E-EurAsia GE%sT 2004 Jun 27 - 3:00 RussiaAsia GE%sT 2005 Mar lastSun 2:00 - 4:00 - GET + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 + 3:00 E-EurAsia +03/+04 1994 Sep lastSun + 4:00 E-EurAsia +04/+05 1996 Oct lastSun + 4:00 1:00 +05 1997 Mar lastSun + 4:00 E-EurAsia +04/+05 2004 Jun 27 + 3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00 + 4:00 - +04 # East Timor @@ -944,7 +940,7 @@ # These would be the earliest possible times for a change. # Régimes horaires pour le monde entier, by Henri Le Corre, (Éditions # Traditionnelles, 1987, Paris) says that Java and Madura switched -# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura +# from UT +09 to +07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura # (Hollandia). For now, assume all Indonesian locations other than Jayapura # switched on 1945-09-23. # @@ -955,11 +951,11 @@ # summary published by the Time and Frequency Laboratory of the # Research Center for Calibration, Instrumentation and Metrology, # Indonesia, (2006-09-29). -# The abbreviations are: +# The time zone abbreviations and UT offsets are: # -# WIB - UTC+7 - Waktu Indonesia Barat (Indonesia western time) -# WITA - UTC+8 - Waktu Indonesia Tengah (Indonesia central time) -# WIT - UTC+9 - Waktu Indonesia Timur (Indonesia eastern time) +# WIB - +07 - Waktu Indonesia Barat (Indonesia western time) +# WITA - +08 - Waktu Indonesia Tengah (Indonesia central time) +# WIT - +09 - Waktu Indonesia Timur (Indonesia eastern time) # # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Java, Sumatra @@ -1848,11 +1844,11 @@ Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2 - 5:00 - FRUT 1930 Jun 21 # Frunze Time - 6:00 RussiaAsia FRU%sT 1991 Mar 31 2:00s - 5:00 1:00 FRUST 1991 Aug 31 2:00 # independence - 5:00 Kyrgyz KG%sT 2005 Aug 12 # Kyrgyzstan Time - 6:00 - KGT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 RussiaAsia +05/+06 1991 Aug 31 2:00 + 5:00 Kyrgyz +05/+06 2005 Aug 12 + 6:00 - +06 ############################################################################### @@ -1891,25 +1887,24 @@ Rule ROK 1987 1988 - May Sun>=8 2:00 1:00 D Rule ROK 1987 1988 - Oct Sun>=8 3:00 0 S -# From Paul Eggert (2014-10-30): +# From Paul Eggert (2016-08-23): # The Korean Wikipedia entry gives the following sources for UT offsets: # -# 1908: Official Journal Article No. 3994 (Edict No. 5) +# 1908: Official Journal Article No. 3994 (decree No. 5) # 1912: Governor-General of Korea Official Gazette Issue No. 367 # (Announcement No. 338) # 1954: Presidential Decree No. 876 (1954-03-17) # 1961: Law No. 676 (1961-08-07) -# 1987: Law No. 3919 (1986-12-31) # -# The Wikipedia entry also has confusing information about a change -# to UT+9 in April 1910, but then what would be the point of the later change -# to UT+9 on 1912-01-01? Omit the 1910 change for now. +# (Another source "1987: Law No. 3919 (1986-12-31)" was in the 2014-10-30 +# edition of the Korean Wikipedia entry.) # # I guessed that time zone abbreviations through 1945 followed the same # rules as discussed under Taiwan, with nominal switches from JST to KST # when the respective cities were taken over by the Allies after WWII. # -# For Pyongyang we have no information; guess no changes since World War II. +# For Pyongyang, guess no changes from World War II until 2015, as we +# have no information otherwise. # From Steffen Thorsen (2015-08-07): # According to many news sources, North Korea is going to change to @@ -2069,7 +2064,7 @@ # Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says # there is only one time zone and that DST is observed, citing Microsoft # Windows XP as the source. Risto Nykänen (2005-05-16) reports that -# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST. +# travelmongolia.org says there are two time zones (UT +07, +08) with no DST. # Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in # Washington, DC says there are two time zones, with DST observed. # He also found @@ -2705,7 +2700,7 @@ # earlier date. # # Shanks & Pottenger also state that until 1968-05-01 Saudi Arabia had two -# time zones; the other zone, at UTC+4, was in the far eastern part of +# time zones; the other zone, at UT +04, was in the far eastern part of # the country. Ignore this, as it's before our 1970 cutoff. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2974,10 +2969,10 @@ # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 - 5:00 - DUST 1930 Jun 21 # Dushanbe Time - 6:00 RussiaAsia DUS%sT 1991 Mar 31 2:00s - 5:00 1:00 DUSST 1991 Sep 9 2:00s - 5:00 - TJT # Tajikistan Time + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 1:00 +05/+06 1991 Sep 9 2:00s + 5:00 - +05 # Thailand # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2991,11 +2986,10 @@ # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad - 4:00 - ASHT 1930 Jun 21 # Ashkhabad Time - 5:00 RussiaAsia ASH%sT 1991 Mar 31 2:00 - 4:00 RussiaAsia ASH%sT 1991 Oct 27 # independence - 4:00 RussiaAsia TM%sT 1992 Jan 19 2:00 - 5:00 - TMT + 4:00 - +04 1930 Jun 21 + 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00 + 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 + 5:00 - +05 # United Arab Emirates # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -3007,20 +3001,18 @@ # Byalokoz 1919 says Uzbekistan was 4:27:53. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2 - 4:00 - SAMT 1930 Jun 21 # Samarkand Time - 5:00 - SAMT 1981 Apr 1 - 5:00 1:00 SAMST 1981 Oct 1 - 6:00 - TAST 1982 Apr 1 # Tashkent Time - 5:00 RussiaAsia SAM%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 4:00 - +04 1930 Jun 21 + 5:00 - +05 1981 Apr 1 + 5:00 1:00 +06 1981 Oct 1 + 6:00 - +06 1982 Apr 1 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Milne says Tashkent was 4:37:10.8; round to nearest. Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 - 5:00 - TAST 1930 Jun 21 # Tashkent Time - 6:00 RussiaAsia TAS%sT 1991 Mar 31 2:00 - 5:00 RussiaAsia TAS%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Vietnam diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/australasia --- a/jdk/test/sun/util/calendar/zi/tzdata/australasia Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia Mon Oct 10 13:31:48 2016 -0700 @@ -568,7 +568,7 @@ # Base the Bougainville entry on the Arawa-Kieta region, which appears to have # the most people even though it was devastated in the Bougainville Civil War. # -# Although Shanks gives 1942-03-15 / 1943-11-01 for JST, these dates +# Although Shanks gives 1942-03-15 / 1943-11-01 for UT +09, these dates # are apparently rough guesswork from the starts of military campaigns. # The World War II entries below are instead based on Arawa-Kieta. # The Japanese occupied Kieta in July 1942, @@ -576,8 +576,8 @@ # http://pwencycl.kgbudge.com/B/o/Bougainville.htm # and seem to have controlled it until their 1945-08-21 surrender. # -# The Autonomous Region of Bougainville plans to switch from UTC+10 to UTC+11 -# on 2014-12-28 at 02:00. They call UTC+11 "Bougainville Standard Time"; +# The Autonomous Region of Bougainville switched from UT +10 to +11 +# on 2014-12-28 at 02:00. They call +11 "Bougainville Standard Time"; # abbreviate this as BST. See: # http://www.bougainville24.com/bougainville-issues/bougainville-gets-own-timezone/ # @@ -643,7 +643,7 @@ # From Paul Eggert (2014-06-27): # The International Date Line Act 2011 # http://www.parliament.gov.ws/images/ACTS/International_Date_Line_Act__2011_-_Eng.pdf -# changed Samoa from UTC-11 to UTC+13, effective "12 o'clock midnight, on +# changed Samoa from UT -11 to +13, effective "12 o'clock midnight, on # Thursday 29th December 2011". The International Date Line was adjusted # accordingly. @@ -738,7 +738,7 @@ # 1886-1891; Baker was similar but exact dates are not known. # Inhabited by civilians 1935-1942; U.S. military bases 1943-1944; # uninhabited thereafter. -# Howland observed Hawaii Standard Time (UT-10:30) in 1937; +# Howland observed Hawaii Standard Time (UT -10:30) in 1937; # see page 206 of Elgen M. Long and Marie K. Long, # Amelia Earhart: the Mystery Solved, Simon & Schuster (2000). # So most likely Howland and Baker observed Hawaii Time from 1935 @@ -1496,7 +1496,7 @@ # Zealand time. I understand that is the time they keep locally, anyhow." # For now, assume this practice goes back to the introduction of standard time # in New Zealand, as this would make Chatham Islands time almost exactly match -# LMT back when New Zealand was at UTC+11:30; also, assume Chatham Islands did +# LMT back when New Zealand was at UT +11:30; also, assume Chatham Islands did # not observe New Zealand's prewar DST. ############################################################################### @@ -1552,7 +1552,7 @@ # For now, we assume the Ladrones switched at the same time as the Philippines; # see Asia/Manila. -# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time, +# US Public Law 106-564 (2000-12-23) made UT +10 the official standard time, # under the name "Chamorro Standard Time". There is no official abbreviation, # but Congressman Robert A. Underwood, author of the bill that became law, # wrote in a press release (2000-12-27) that he will seek the use of "ChST". @@ -1564,15 +1564,15 @@ # "I am certain, having lived there for the past decade, that 'Truk' # (now properly known as Chuuk) ... is in the time zone GMT+10." # -# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11 +# Shanks & Pottenger write that Truk switched from UT +10 to +11 # on 1978-10-01; ignore this for now. # From Paul Eggert (1999-10-29): # The Federated States of Micronesia Visitors Board writes in # The Federated States of Micronesia - Visitor Information (1999-01-26) # http://www.fsmgov.org/info/clocks.html -# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11. -# We don't know when Kosrae switched from UTC+12; assume January 1 for now. +# that Truk and Yap are UT +10, and Ponape and Kosrae are +11. +# We don't know when Kosrae switched from +12; assume January 1 for now. # Midway @@ -1638,11 +1638,11 @@ # ordaining - by a masterpiece of diplomatic flattery - that # the Fourth of July should be celebrated twice in that year." -# Although Shanks & Pottenger says they both switched to UTC-11:30 -# in 1911, and to UTC-11 in 1950. many earlier sources give UTC-11 +# Although Shanks & Pottenger says they both switched to UT -11:30 +# in 1911, and to -11 in 1950. many earlier sources give -11 # for American Samoa, e.g., the US National Bureau of Standards # circular "Standard Time Throughout the World", 1932. -# Assume American Samoa switched to UTC-11 in 1911, not 1950, +# Assume American Samoa switched to -11 in 1911, not 1950, # and that after 1950 they agreed until (western) Samoa skipped a # day in 2011. Assume also that the Samoas follow the US and New # Zealand's "ST"/"DT" style of daylight-saving abbreviations. diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/backward --- a/jdk/test/sun/util/calendar/zi/tzdata/backward Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/backward Mon Oct 10 13:31:48 2016 -0700 @@ -59,6 +59,7 @@ Link Asia/Urumqi Asia/Kashgar Link Asia/Kathmandu Asia/Katmandu Link Asia/Macau Asia/Macao +Link Asia/Yangon Asia/Rangoon Link Asia/Ho_Chi_Minh Asia/Saigon Link Asia/Jerusalem Asia/Tel_Aviv Link Asia/Thimphu Asia/Thimbu diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/etcetera --- a/jdk/test/sun/util/calendar/zi/tzdata/etcetera Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/etcetera Mon Oct 10 13:31:48 2016 -0700 @@ -31,6 +31,13 @@ # need now for the entries that are not on UTC are for ships at sea # that cannot use POSIX TZ settings. +# Starting with POSIX 1003.1-2001, the entries below are all +# unnecessary as settings for the TZ environment variable. E.g., +# instead of TZ='Etc/GMT+4' one can use the POSIX setting TZ='<-04>+4'. +# +# Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours +# behind GMT but uses the completely misleading abbreviation "GMT". + Zone Etc/GMT 0 - GMT Zone Etc/UTC 0 - UTC Zone Etc/UCT 0 - UCT @@ -49,23 +56,13 @@ Link Etc/GMT Etc/GMT+0 Link Etc/GMT Etc/GMT0 -# We use POSIX-style signs in the Zone names and the output abbreviations, +# Be consistent with POSIX TZ settings in the Zone names, # even though this is the opposite of what many people expect. # POSIX has positive signs west of Greenwich, but many people expect # positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses -# the abbreviation "GMT+4" and corresponds to 4 hours behind UT +# the abbreviation "-04" and corresponds to 4 hours behind UT # (i.e. west of Greenwich) even though many people would expect it to # mean 4 hours ahead of UT (i.e. east of Greenwich). -# -# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for -# TZ='+4'; if you want time zone abbreviations conforming to -# ISO 8601 you can use TZ='<-0400>+4'. Thus the commonly-expected -# offset is kept within the angle bracket (and is used for display) -# while the POSIX sign is kept outside the angle bracket (and is used -# for calculation). -# -# Do not use a TZ setting like TZ='GMT+4', which is four hours behind -# GMT but uses the completely misleading abbreviation "GMT". # Earlier incarnations of this package were not POSIX-compliant, # and had lines such as @@ -74,30 +71,31 @@ # way does a # zic -l GMT-12 # so we moved the names into the Etc subdirectory. +# Also, the time zone abbreviations are now compatible with %z. -Zone Etc/GMT-14 14 - GMT-14 # 14 hours ahead of GMT -Zone Etc/GMT-13 13 - GMT-13 -Zone Etc/GMT-12 12 - GMT-12 -Zone Etc/GMT-11 11 - GMT-11 -Zone Etc/GMT-10 10 - GMT-10 -Zone Etc/GMT-9 9 - GMT-9 -Zone Etc/GMT-8 8 - GMT-8 -Zone Etc/GMT-7 7 - GMT-7 -Zone Etc/GMT-6 6 - GMT-6 -Zone Etc/GMT-5 5 - GMT-5 -Zone Etc/GMT-4 4 - GMT-4 -Zone Etc/GMT-3 3 - GMT-3 -Zone Etc/GMT-2 2 - GMT-2 -Zone Etc/GMT-1 1 - GMT-1 -Zone Etc/GMT+1 -1 - GMT+1 -Zone Etc/GMT+2 -2 - GMT+2 -Zone Etc/GMT+3 -3 - GMT+3 -Zone Etc/GMT+4 -4 - GMT+4 -Zone Etc/GMT+5 -5 - GMT+5 -Zone Etc/GMT+6 -6 - GMT+6 -Zone Etc/GMT+7 -7 - GMT+7 -Zone Etc/GMT+8 -8 - GMT+8 -Zone Etc/GMT+9 -9 - GMT+9 -Zone Etc/GMT+10 -10 - GMT+10 -Zone Etc/GMT+11 -11 - GMT+11 -Zone Etc/GMT+12 -12 - GMT+12 +Zone Etc/GMT-14 14 - +14 +Zone Etc/GMT-13 13 - +13 +Zone Etc/GMT-12 12 - +12 +Zone Etc/GMT-11 11 - +11 +Zone Etc/GMT-10 10 - +10 +Zone Etc/GMT-9 9 - +09 +Zone Etc/GMT-8 8 - +08 +Zone Etc/GMT-7 7 - +07 +Zone Etc/GMT-6 6 - +06 +Zone Etc/GMT-5 5 - +05 +Zone Etc/GMT-4 4 - +04 +Zone Etc/GMT-3 3 - +03 +Zone Etc/GMT-2 2 - +02 +Zone Etc/GMT-1 1 - +01 +Zone Etc/GMT+1 -1 - -01 +Zone Etc/GMT+2 -2 - -02 +Zone Etc/GMT+3 -3 - -03 +Zone Etc/GMT+4 -4 - -04 +Zone Etc/GMT+5 -5 - -05 +Zone Etc/GMT+6 -6 - -06 +Zone Etc/GMT+7 -7 - -07 +Zone Etc/GMT+8 -8 - -08 +Zone Etc/GMT+9 -9 - -09 +Zone Etc/GMT+10 -10 - -10 +Zone Etc/GMT+11 -11 - -11 +Zone Etc/GMT+12 -12 - -12 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/europe --- a/jdk/test/sun/util/calendar/zi/tzdata/europe Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe Mon Oct 10 13:31:48 2016 -0700 @@ -98,8 +98,7 @@ # 1:00 CET CEST CEMT Central Europe # 1:00:14 SET Swedish (1879-1899)* # 2:00 EET EEST Eastern Europe -# 3:00 FET Further-eastern Europe (2011-2014)* -# 3:00 MSK MSD MSM* Minsk, Moscow +# 3:00 MSK MSD Moscow # From Peter Ilieve (1994-12-04), # The original six [EU members]: Belgium, France, (West) Germany, Italy, @@ -606,16 +605,33 @@ Rule E-Eur 1981 max - Mar lastSun 0:00 1:00 S Rule E-Eur 1996 max - Oct lastSun 0:00 0 - + +# Daylight saving time for Russia and the Soviet Union +# +# The 1917-1921 decree URLs are from Alexander Belopolsky (2016-08-23). + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Russia 1917 only - Jul 1 23:00 1:00 MST # Moscow Summer Time +# +# Decree No. 142 (1917-12-22) http://istmat.info/node/28137 Rule Russia 1917 only - Dec 28 0:00 0 MMT # Moscow Mean Time +# +# Decree No. 497 (1918-05-30) http://istmat.info/node/30001 Rule Russia 1918 only - May 31 22:00 2:00 MDST # Moscow Double Summer Time Rule Russia 1918 only - Sep 16 1:00 1:00 MST +# +# Decree No. 258 (1919-05-29) http://istmat.info/node/37949 Rule Russia 1919 only - May 31 23:00 2:00 MDST -Rule Russia 1919 only - Jul 1 2:00 1:00 MSD +# +Rule Russia 1919 only - Jul 1 0:00u 1:00 MSD Rule Russia 1919 only - Aug 16 0:00 0 MSK +# +# Decree No. 63 (1921-02-03) http://istmat.info/node/45840 Rule Russia 1921 only - Feb 14 23:00 1:00 MSD -Rule Russia 1921 only - Mar 20 23:00 2:00 MSM # Midsummer +# +# Decree No. 121 (1921-03-07) http://istmat.info/node/45949 +Rule Russia 1921 only - Mar 20 23:00 2:00 +05 +# Rule Russia 1921 only - Sep 1 0:00 1:00 MSD Rule Russia 1921 only - Oct 1 0:00 0 - # Act No. 925 of the Council of Ministers of the USSR (1980-10-24): @@ -798,8 +814,6 @@ # From Alexander Bokovoy (2014-10-09): # Belarussian government decided against changing to winter time.... # http://eng.belta.by/all_news/society/Belarus-decides-against-adjusting-time-in-Russias-wake_i_76335.html -# From Paul Eggert (2014-10-08): -# Hence Belarus can share time zone abbreviations with Moscow again. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Minsk 1:50:16 - LMT 1880 @@ -810,8 +824,7 @@ 3:00 Russia MSK/MSD 1990 3:00 - MSK 1991 Mar 31 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 1:00s - 3:00 - MSK + 3:00 - +03 # Belgium # @@ -1319,7 +1332,7 @@ # http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf # says that Bersarin issued an order to use Moscow time on May 20. # However, Moscow did not observe daylight saving in 1945, so -# this was equivalent to CEMT (GMT+3), not GMT+4. +# this was equivalent to UT +03, not +04. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S @@ -2283,7 +2296,6 @@ # http://www.worldtimezone.com/dst_news/dst_news_russia-map-2014-07.html # From Paul Eggert (2006-03-22): -# Except for Moscow after 1919-07-01, I invented the time zone abbreviations. # Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991, # are from Andrey A. Chernov. The rest is from Shanks & Pottenger, # except we follow Chernov's report that 1992 DST transitions were Sat @@ -2359,7 +2371,7 @@ 2:00 Poland CE%sT 1946 3:00 Russia MSK/MSD 1989 Mar 26 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 2:00s + 3:00 - +03 2014 Oct 26 2:00s 2:00 - EET @@ -2412,6 +2424,16 @@ # 78 RU-SPE Saint Petersburg # 83 RU-NEN Nenets Autonomous Okrug +# From Paul Eggert (2016-08-23): +# The Soviets switched to UT-based time in 1919. Decree No. 59 +# (1919-02-08) http://istmat.info/node/35567 established UT-based time +# zones, and Decree No. 147 (1919-03-29) http://istmat.info/node/35854 +# specified a transition date of 1919-07-01, apparently at 00:00 UT. +# No doubt only the Soviet-controlled regions switched on that date; +# later transitions to UT-based time in other parts of Russia are +# taken from what appear to be guesses by Shanks. +# (Thanks to Alexander Belopolsky for pointers to the decrees.) + # From Stepan Golosunov (2016-03-07): # 11. Regions-violators, 1981-1982. # Wikipedia refers to @@ -2453,7 +2475,7 @@ # attributes the 1982 changes to the Act of the Council of Ministers # of the USSR No. 126 from 18.02.1982. 1980-925.txt also adds # Udmurtia to the list of affected territories and lists Khatangsky -# district separately from Taymyr Autonomous Okurg. Probably erroneously. +# district separately from Taymyr Autonomous Okrug. Probably erroneously. # # The affected territories are currently listed under Europe/Moscow, # Asia/Yekaterinburg and Asia/Krasnoyarsk. @@ -2513,7 +2535,7 @@ Zone Europe/Moscow 2:30:17 - LMT 1880 2:30:17 - MMT 1916 Jul 3 # Moscow Mean Time - 2:31:19 Russia %s 1919 Jul 1 2:00 + 2:31:19 Russia %s 1919 Jul 1 0:00u 3:00 Russia %s 1921 Oct 3:00 Russia MSK/MSD 1922 Oct 2:00 - EET 1930 Jun 21 @@ -2596,22 +2618,21 @@ # The 1988 transition is from USSR act No. 5 (1988-01-04). Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 - 3:00 - TSAT 1925 Apr 6 # Tsaritsyn Time - 3:00 - STAT 1930 Jun 21 # Stalingrad Time - 4:00 - STAT 1961 Nov 11 - 4:00 Russia VOL%sT 1988 Mar 27 2:00s # Volgograd T - 3:00 Russia VOL%sT 1991 Mar 31 2:00s - 4:00 - VOLT 1992 Mar 29 2:00s - 3:00 Russia MSK/MSD 2011 Mar 27 2:00s - 4:00 - MSK 2014 Oct 26 2:00s - 3:00 - MSK + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1961 Nov 11 + 4:00 Russia +04/+05 1988 Mar 27 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 4:00 - +04 1992 Mar 29 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 2014 Oct 26 2:00s + 3:00 - +03 # From Paul Eggert (2016-03-18): # Europe/Kirov covers: # 43 RU-KIR Kirov Oblast # The 1989 transition is from USSR act No. 227 (1989-03-14). # -Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 2:00 +Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2629,16 +2650,16 @@ # Byalokoz 1919 says Samara was 3:20:20. # The 1989 transition is from USSR act No. 227 (1989-03-14). -Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 2:00 - 3:00 - SAMT 1930 Jun 21 # Samara Time - 4:00 - SAMT 1935 Jan 27 - 4:00 Russia KUY%sT 1989 Mar 26 2:00s # Kuybyshev - 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 2:00 Russia EE%sT 1991 Sep 29 2:00s - 3:00 - SAMT 1991 Oct 20 3:00 - 4:00 Russia SAM%sT 2010 Mar 28 2:00s - 3:00 Russia SAM%sT 2011 Mar 27 2:00s - 4:00 - SAMT +Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1935 Jan 27 + 4:00 Russia +04/+05 1989 Mar 26 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 2:00 Russia +02/+03 1991 Sep 29 2:00s + 3:00 - +03 1991 Oct 20 3:00 + 4:00 Russia +04/+05 2010 Mar 28 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 # From Paul Eggert (2016-03-18): # Europe/Ulyanovsk covers: @@ -2653,7 +2674,7 @@ # From Matt Johnson (2016-03-09): # http://publication.pravo.gov.ru/Document/View/0001201603090051 -Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 2:00 +Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2685,12 +2706,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 3:45:05 - PMT 1919 Jul 15 4:00 - 4:00 - SVET 1930 Jun 21 # Sverdlovsk Time - 5:00 Russia SVE%sT 1991 Mar 31 2:00s - 4:00 Russia SVE%sT 1992 Jan 19 2:00s - 5:00 Russia YEK%sT 2011 Mar 27 2:00s - 6:00 - YEKT 2014 Oct 26 2:00s - 5:00 - YEKT + 4:00 - +04 1930 Jun 21 + 5:00 Russia +05/+06 1991 Mar 31 2:00s + 4:00 Russia +04/+05 1992 Jan 19 2:00s + 5:00 Russia +05/+06 2011 Mar 27 2:00s + 6:00 - +06 2014 Oct 26 2:00s + 5:00 - +05 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2700,12 +2721,12 @@ # Byalokoz 1919 says Omsk was 4:53:30. Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 - 5:00 - OMST 1930 Jun 21 # Omsk Time - 6:00 Russia OMS%sT 1991 Mar 31 2:00s - 5:00 Russia OMS%sT 1992 Jan 19 2:00s - 6:00 Russia OMS%sT 2011 Mar 27 2:00s - 7:00 - OMST 2014 Oct 26 2:00s - 6:00 - OMST + 5:00 - +05 1930 Jun 21 + 6:00 Russia +06/+07 1991 Mar 31 2:00s + 5:00 Russia +05/+06 1992 Jan 19 2:00s + 6:00 Russia +06/+07 2011 Mar 27 2:00s + 7:00 - +07 2014 Oct 26 2:00s + 6:00 - +06 # From Paul Eggert (2016-02-22): # Asia/Barnaul covers: @@ -2785,7 +2806,7 @@ # Note that time belts (numbered from 2 (Moscow) to 12 according to their # GMT/UTC offset and having too many exceptions like regions formally # belonging to one belt but using time from another) were replaced -# with time zones in 2011 with different numberings (there was a +# with time zones in 2011 with different numbering (there was a # 2-hour gap between second and third zones in 2011-2014). # From Stepan Golosunov (2016-04-12): @@ -2868,12 +2889,12 @@ # Byalokoz 1919 says Krasnoyarsk was 6:11:26. Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 - 6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time - 7:00 Russia KRA%sT 1991 Mar 31 2:00s - 6:00 Russia KRA%sT 1992 Jan 19 2:00s - 7:00 Russia KRA%sT 2011 Mar 27 2:00s - 8:00 - KRAT 2014 Oct 26 2:00s - 7:00 - KRAT + 6:00 - +06 1930 Jun 21 + 7:00 Russia +07/+08 1991 Mar 31 2:00s + 6:00 Russia +06/+07 1992 Jan 19 2:00s + 7:00 Russia +07/+08 2011 Mar 27 2:00s + 8:00 - +08 2014 Oct 26 2:00s + 7:00 - +07 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2890,12 +2911,12 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880 6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time - 7:00 - IRKT 1930 Jun 21 # Irkutsk Time - 8:00 Russia IRK%sT 1991 Mar 31 2:00s - 7:00 Russia IRK%sT 1992 Jan 19 2:00s - 8:00 Russia IRK%sT 2011 Mar 27 2:00s - 9:00 - IRKT 2014 Oct 26 2:00s - 8:00 - IRKT + 7:00 - +07 1930 Jun 21 + 8:00 Russia +08/+09 1991 Mar 31 2:00s + 7:00 Russia +07/+08 1992 Jan 19 2:00s + 8:00 Russia +08/+09 2011 Mar 27 2:00s + 9:00 - +09 2014 Oct 26 2:00s + 8:00 - +08 # From Tim Parenti (2014-07-06): @@ -2912,13 +2933,13 @@ # http://publication.pravo.gov.ru/Document/View/0001201512300107 Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 8:00 - IRKT 2016 Mar 27 2:00 - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 8:00 - +08 2016 Mar 27 2:00 + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2958,12 +2979,12 @@ # Byalokoz 1919 says Yakutsk was 8:38:58. Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2981,12 +3002,12 @@ # Go with Byalokoz. Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 - 9:00 - VLAT 1930 Jun 21 # Vladivostok Time - 10:00 Russia VLA%sT 1991 Mar 31 2:00s - 9:00 Russia VLA%sT 1992 Jan 19 2:00s - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 9:00 - +09 1930 Jun 21 + 10:00 Russia +10/+11 1991 Mar 31 2:00s + 9:00 Russia +09/+10 1992 Jan 19 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03): @@ -3004,14 +3025,14 @@ # This transition is no doubt wrong, but we have no better info. Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2004 - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2011 Sep 13 0:00s # Decree 725? - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2004 + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2011 Sep 13 0:00s # Decree 725? + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03): @@ -3027,15 +3048,14 @@ # The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long. Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 - 9:00 - JCST 1937 Oct 1 - 9:00 - JST 1945 Aug 25 - 11:00 Russia SAK%sT 1991 Mar 31 2:00s # Sakhalin T - 10:00 Russia SAK%sT 1992 Jan 19 2:00s - 11:00 Russia SAK%sT 1997 Mar lastSun 2:00s - 10:00 Russia SAK%sT 2011 Mar 27 2:00s - 11:00 - SAKT 2014 Oct 26 2:00s - 10:00 - SAKT 2016 Mar 27 2:00s - 11:00 - SAKT + 9:00 - +09 1945 Aug 25 + 11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 1997 Mar lastSun 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 2016 Mar 27 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3058,13 +3078,13 @@ # http://publication.pravo.gov.ru/Document/View/0001201604050038 Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 10:00 - MAGT 2016 Apr 24 2:00s - 11:00 - MAGT + 10:00 - +10 1930 Jun 21 # Magadan Time + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 10:00 - +10 2016 Apr 24 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-06): @@ -3107,17 +3127,14 @@ # in Russian.) In addition, Srednekolymsk appears to be a much older # settlement and the population of Zyryanka seems to be declining. # Go with Srednekolymsk. -# -# Since Magadan Oblast moves to UTC+10 on 2014-10-26, we cannot keep using MAGT -# as the abbreviation. Use SRET instead. Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 11:00 - SRET # Srednekolymsk Time + 10:00 - +10 1930 Jun 21 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03): @@ -3135,14 +3152,14 @@ # UTC+12 since at least then, too. Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAKT 1981 Apr 1 - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2011 Sep 13 0:00s # Decree 725? - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1981 Apr 1 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2011 Sep 13 0:00s # Decree 725? + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3155,12 +3172,12 @@ # The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps # Asia/Petropavlovsk-Kamchatsky, but these are too long. Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 - 11:00 - PETT 1930 Jun 21 # P-K Time - 12:00 Russia PET%sT 1991 Mar 31 2:00s - 11:00 Russia PET%sT 1992 Jan 19 2:00s - 12:00 Russia PET%sT 2010 Mar 28 2:00s - 11:00 Russia PET%sT 2011 Mar 27 2:00s - 12:00 - PETT + 11:00 - +11 1930 Jun 21 + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # From Tim Parenti (2014-07-03): @@ -3168,13 +3185,13 @@ # 87 RU-CHU Chukotka Autonomous Okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 - 12:00 - ANAT 1930 Jun 21 # Anadyr Time - 13:00 Russia ANA%sT 1982 Apr 1 0:00s - 12:00 Russia ANA%sT 1991 Mar 31 2:00s - 11:00 Russia ANA%sT 1992 Jan 19 2:00s - 12:00 Russia ANA%sT 2010 Mar 28 2:00s - 11:00 Russia ANA%sT 2011 Mar 27 2:00s - 12:00 - ANAT + 12:00 - +12 1930 Jun 21 + 13:00 Russia +13/+14 1982 Apr 1 0:00s + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # San Marino @@ -3495,6 +3512,14 @@ # Engineered Standard Time," said Twitter user @aysekarahasan. # http://www.bbc.com/news/world-europe-34631326 +# From Burak AYDIN (2016-09-08): +# Turkey will stay in Daylight Saving Time even in winter.... +# http://www.resmigazete.gov.tr/eskiler/2016/09/20160908-2.pdf +# +# From Paul Eggert (2016-09-07): +# The change is permanent, so this is the new standard time in Turkey. +# It takes effect today, which is not much notice. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Turkey 1916 only - May 1 0:00 1:00 S Rule Turkey 1916 only - Oct 1 0:00 0 - @@ -3558,7 +3583,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 1:56:56 - IMT 1910 Oct # Istanbul Mean Time? 2:00 Turkey EE%sT 1978 Oct 15 - 3:00 Turkey TR%sT 1985 Apr 20 # Turkey Time + 3:00 Turkey +03/+04 1985 Apr 20 2:00 Turkey EE%sT 2007 2:00 EU EE%sT 2011 Mar 27 1:00u 2:00 - EET 2011 Mar 28 1:00u @@ -3566,7 +3591,8 @@ 2:00 - EET 2014 Mar 31 1:00u 2:00 EU EE%sT 2015 Oct 25 1:00u 2:00 1:00 EEST 2015 Nov 8 1:00u - 2:00 EU EE%sT + 2:00 EU EE%sT 2016 Sep 7 + 3:00 - +03 Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. # Ukraine diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/factory --- a/jdk/test/sun/util/calendar/zi/tzdata/factory Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/factory Mon Oct 10 13:31:48 2016 -0700 @@ -24,9 +24,10 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -# For companies who don't want to put time zone specification in -# their installation procedures. When users run date, they'll get the message. -# Also useful for the "comp.sources" version. +# For distributors who don't want to put time zone specification in +# their installation procedures. Users that run 'date' will get the +# time zone abbreviation "-00", indicating that the actual time zone +# is unknown. # Zone NAME GMTOFF RULES FORMAT -Zone Factory 0 - "Local time zone must be set--see zic manual page" +Zone Factory 0 - -00 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/leapseconds --- a/jdk/test/sun/util/calendar/zi/tzdata/leapseconds Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds Mon Oct 10 13:31:48 2016 -0700 @@ -79,6 +79,7 @@ Leap 2008 Dec 31 23:59:60 + S Leap 2012 Jun 30 23:59:60 + S Leap 2015 Jun 30 23:59:60 + S +Leap 2016 Dec 31 23:59:60 + S -# Updated through IERS Bulletin C51 -# File expires on: 28 December 2016 +# Updated through IERS Bulletin C52 +# File expires on: 28 June 2017 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/northamerica --- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica Mon Oct 10 13:31:48 2016 -0700 @@ -436,11 +436,42 @@ # north of the Salmon River, and the towns of Burgdorf and Warren), # Nevada (except West Wendover), Oregon (except the northern 3/4 of # Malheur county), and Washington + +# From Paul Eggert (2016-08-20): +# In early February 1948, in response to California's electricity shortage, +# PG&E changed power frequency from 60 to 59.5 Hz during daylight hours, +# causing electric clocks to lose six minutes per day. (This did not change +# legal time, and is not part of the data here.) See: +# Ross SA. An energy crisis from the past: Northern California in 1948. +# Working Paper No. 8, Institute of Governmental Studies, UC Berkeley, +# 1973-11. http://escholarship.org/uc/item/8x22k30c +# +# In another measure to save electricity, DST was instituted from 1948-03-14 +# at 02:01 to 1949-01-16 at 02:00, with the governor having the option to move +# the fallback transition earlier. See pages 3-4 of: +# http://clerk.assembly.ca.gov/sites/clerk.assembly.ca.gov/files/archive/Statutes/1948/48Vol1_Chapters.pdf +# +# In response: +# +# Governor Warren received a torrent of objecting mail, and it is not too much +# to speculate that the objections to Daylight Saving Time were one important +# factor in the defeat of the Dewey-Warren Presidential ticket in California. +# -- Ross, p 25 +# +# On December 8 the governor exercised the option, setting the date to January 1 +# (LA Times 1948-12-09). The transition time was 02:00 (LA Times 1949-01-01). +# +# Despite the controversy, in 1949 California voters approved Proposition 12, +# which established DST from April's last Sunday at 01:00 until September's +# last Sunday at 02:00. This was amended by 1962's Proposition 6, which changed +# the fall-back date to October's last Sunday. See: +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1501&context=ca_ballot_props +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1636&context=ca_ballot_props # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER -Rule CA 1948 only - Mar 14 2:00 1:00 D +Rule CA 1948 only - Mar 14 2:01 1:00 D Rule CA 1949 only - Jan 1 2:00 0 S -Rule CA 1950 1966 - Apr lastSun 2:00 1:00 D +Rule CA 1950 1966 - Apr lastSun 1:00 1:00 D Rule CA 1950 1961 - Sep lastSun 2:00 0 S Rule CA 1962 1966 - Oct lastSun 2:00 0 S # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -3304,7 +3335,7 @@ # indicating that the normal ET rules are followed. # # From Paul Eggert (2014-08-19): -# The 2014-08-13 Cabinet meeting decided to stay on UTC-4 year-round. See: +# The 2014-08-13 Cabinet meeting decided to stay on UT -04 year-round. See: # http://tcweeklynews.com/daylight-savings-time-to-be-maintained-p5353-127.htm # Model this as a switch from EST/EDT to AST ... # From Chris Walton (2014-11-04): diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/southamerica --- a/jdk/test/sun/util/calendar/zi/tzdata/southamerica Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica Mon Oct 10 13:31:48 2016 -0700 @@ -433,9 +433,9 @@ # stuck on Summer daylight savings time even though the summer is over. # From Paul Eggert (2013-09-05): -# Perhaps San Luis operates on the legal fiction that it is at UTC-4 +# Perhaps San Luis operates on the legal fiction that it is at -04 # with perpetual summer time, but ordinary usage typically seems to -# just say it's at UTC-3; see, for example, +# just say it's at -03; see, for example, # http://es.wikipedia.org/wiki/Hora_oficial_argentina # We've documented similar situations as being plain changes to # standard time, so let's do that here too. This does not change UTC diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/sun/util/calendar/zi/tzdata/zone.tab --- a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab Mon Oct 10 13:31:48 2016 -0700 @@ -284,7 +284,7 @@ MH +0905+16720 Pacific/Kwajalein Kwajalein MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako -MM +1647+09610 Asia/Rangoon +MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jjs/addmodulesrepeat.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jjs/addmodulesrepeat.js Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,17 @@ +/* + * This is the test JavaScript program used in jjs-modulepathTest.sh + */ + +print("--module-path passed: " + $OPTIONS._module_path); +print("--add-modules passed: " + $OPTIONS._add_modules); + +if ($OPTIONS._add_modules != "java.base,com.greetings") { + throw new Error("--add-modules values are not merged!"); +} + +var Hello = com.greetings.Hello; + +var moduleName = Hello.class.module.name; +if (moduleName != "com.greetings") { + throw new Error("Expected module name to be com.greetings"); +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jjs/com.greetings/com/greetings/Hello.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jjs/com.greetings/com/greetings/Hello.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,30 @@ +/* + * 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 com.greetings; + +public class Hello { + public static String greet() { + return "Hello World!"; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jjs/com.greetings/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jjs/com.greetings/module-info.java Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module com.greetings { + exports com.greetings; +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jjs/jjs-modulepathTest.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jjs/jjs-modulepathTest.sh Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,68 @@ +#!/bin/sh + +# +# 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 8167018 +# @summary Nashorn and jjs should support --module-path and --add-modules options +# @run shell jjs-modulepathTest.sh +# Tests --module-path option to set the module path for jjs + +. ${TESTSRC-.}/common.sh + +setup + +mkdir -p ${TESTCLASSES}/com.greetings +rm -rf ${TESTCLASSES}/com.greetings + +${JAVAC} ${TESTSRC}/com.greetings/module-info.java \ + ${TESTSRC}/com.greetings/com/greetings/*.java \ + -d ${TESTCLASSES}/com.greetings + +# no --add-modules passed. This should result in error. +${JJS} -scripting --module-path ${TESTCLASSES} ${TESTSRC}/modulepath.js + +if [ $? -ne 0 ]; then + echo "Error thrown as expected when --add-modules is missing!" +else + echo "Should have thrown error for missing --add-modules!" + exit 1 +fi + +# proper usage of --module-path with --add-modules +${JJS} -scripting --module-path ${TESTCLASSES} --add-modules com.greetings ${TESTSRC}/modulepath.js +if [ $? -ne 0 ]; then + exit 1 +fi + +# check that repeated --add-modules values are combined +${JJS} -scripting --module-path ${TESTCLASSES} --add-modules java.base --add-modules com.greetings ${TESTSRC}/addmodulesrepeat.js +if [ $? -ne 0 ]; then + exit 1 +fi + +rm -rf ${TESTCLASSES}/com.greetings +echo "Passed" +exit 0 diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jjs/modulepath.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jjs/modulepath.js Mon Oct 10 13:31:48 2016 -0700 @@ -0,0 +1,21 @@ +/* + * This is the test JavaScript program used in jjs-modulepathTest.sh + */ + +print("--module-path passed: " + $OPTIONS._module_path); +print("--add-modules passed: " + $OPTIONS._add_modules); + +var Hello = com.greetings.Hello; +var moduleName = Hello.class.module.name; +if (moduleName != "com.greetings") { + throw new Error("Expected module name to be com.greetings"); +} else { + print("Module name is " + moduleName); +} + +var msg = Hello.greet(); +if (msg != "Hello World!") { + throw new Error("Expected 'Hello World!'"); +} else { + print(msg); +} diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jlink/JLinkNegativeTest.java --- a/jdk/test/tools/jlink/JLinkNegativeTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java Mon Oct 10 13:31:48 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); } diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jlink/JLinkTest.java --- a/jdk/test/tools/jlink/JLinkTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/tools/jlink/JLinkTest.java Mon Oct 10 13:31:48 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() diff -r ef26c8e40f1e -r 31882abda8b5 jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java --- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Mon Oct 03 14:10:40 2016 -0700 +++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Mon Oct 10 13:31:48 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", diff -r ef26c8e40f1e -r 31882abda8b5 langtools/.hgtags --- a/langtools/.hgtags Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/.hgtags Mon Oct 10 13:31:48 2016 -0700 @@ -380,3 +380,4 @@ af5eb8f3ffd21288305a54ea177ffad75021a741 jdk-9+135 c8f02f0ecbd7cd6700f47416e4b7e9d5ec20ad77 jdk-9+136 dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137 +90dd93e668a521642382561c47abe96ee2e065b7 jdk-9+138 diff -r ef26c8e40f1e -r 31882abda8b5 langtools/make/gendata/Gendata-jdk.compiler.gmk --- a/langtools/make/gendata/Gendata-jdk.compiler.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/make/gendata/Gendata-jdk.compiler.gmk Mon Oct 10 13:31:48 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 \ diff -r ef26c8e40f1e -r 31882abda8b5 langtools/make/gensrc/GensrcCommon.gmk --- a/langtools/make/gensrc/GensrcCommon.gmk Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/make/gensrc/GensrcCommon.gmk Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java Mon Oct 10 13:31:48 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); + } + } diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Mon Oct 10 13:31:48 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); } diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Mon Oct 10 13:31:48 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); } diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Mon Oct 10 13:31:48 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 allModules = allModules(); for (ModuleSymbol m : allModules) { diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Mon Oct 10 13:31:48 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) { diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Mon Oct 10 13:31:48 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; diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ModuleNameReader.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ModuleNameReader.java Mon Oct 03 14:10:40 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. - * - *

- * 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. - */ -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; - } -} diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Mon Oct 10 13:31:48 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. + * + *

+ * 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. + */ +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; + } +} diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Oct 10 13:31:48 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.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.nil()); - } finally { - log.useSource(prev); - } + tree = parseImplicitFile(c.classfile); } + readSourceFile(tree, c, cut -> c); + } + + private ClassSymbol readSourceFile(JCCompilationUnit tree, + ClassSymbol expectedSymbol, + Function 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. */ diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Mon Oct 10 13:31:48 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, diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Oct 10 13:31:48 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); diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Oct 10 13:31:48 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 diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java Mon Oct 10 13:31:48 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; } diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java Mon Oct 10 13:31:48 2016 -0700 @@ -595,8 +595,9 @@ @Override public Set getSupportedOptions() { + Resources resources = getResources(); Doclet.Option[] options = { - new Option(this, "-bottom", 1) { + new Option(resources, "-bottom", 1) { @Override public boolean process(String opt, ListIterator 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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()); diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Mon Oct 10 13:31:48 2016 -0700 @@ -191,144 +191,196 @@ doclet.Same_package_name_used=Package name format used twice: {0} # option specifiers -doclet.usage.d.parameters= -doclet.usage.d.description=Destination directory for output files +doclet.usage.d.parameters=\ + +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= -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=\ + +doclet.usage.overview.description=\ + Read overview documentation from HTML file -doclet.usage.windowtitle.parameters= -doclet.usage.windowtitle.description=Browser window title for the documentation - -doclet.usage.doctitle.parameters= -doclet.usage.doctitle.description=Include title for the overview page +doclet.usage.windowtitle.parameters=\ + +doclet.usage.windowtitle.description=\ + Browser window title for the documentation -doclet.usage.header.parameters= -doclet.usage.header.description=Include header text for each page - -doclet.usage.html4.description=Generate HTML 4.01 output +doclet.usage.doctitle.parameters=\ + +doclet.usage.doctitle.description=\ + Include title for the overview page -doclet.usage.html5.description=Generate HTML 5 output +doclet.usage.header.parameters=\ + +doclet.usage.header.description=\ + Include header text for each page -doclet.usage.footer.parameters= -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= -doclet.usage.top.description=Include top text for each page +doclet.usage.footer.parameters=\ + +doclet.usage.footer.description=\ + Include footer text for each page -doclet.usage.bottom.parameters= -doclet.usage.bottom.description=Include bottom text for each page - -doclet.usage.link.parameters= -doclet.usage.link.description=Create links to javadoc output at +doclet.usage.top.parameters=\ + +doclet.usage.top.description=\ + Include top text for each page -doclet.usage.linkoffline.parameters= -doclet.usage.linkoffline.description=Link to docs at using package list\n\ -\ at +doclet.usage.bottom.parameters=\ + +doclet.usage.bottom.description=\ + Include bottom text for each page -doclet.usage.excludedocfilessubdir.parameters=:.. -doclet.usage.excludedocfilessubdir.description=\n\ -\ Exclude any doc-files subdirectories with\n\ -\ given name +doclet.usage.link.parameters=\ + +doclet.usage.link.description=\ + Create links to javadoc output at -doclet.usage.group.parameters= :.. -doclet.usage.group.description=Group specified packages together\n\ -\ in overview page +doclet.usage.linkoffline.parameters=\ + +doclet.usage.linkoffline.description=\ + Link to docs at using package list at -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=\ + :.. +doclet.usage.excludedocfilessubdir.description=\ + Exclude any doc-files subdirectories with given name -doclet.usage.noqualifier.parameters=::.. -doclet.usage.noqualifier.description=Exclude the list of qualifiers from the output +doclet.usage.group.parameters=\ + :.. +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=\ + ::.. +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=::

-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=\ + ::
+doclet.usage.tag.description=\ + Specify single argument custom tags -doclet.usage.charset.parameters= -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= -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=\ + +doclet.usage.charset.description=\ + Charset for cross-platform viewing of generated documentation -doclet.usage.sourcetab.parameters= -doclet.usage.sourcetab.description=Specify the number of spaces each tab\n\ -\ takes up in the source +doclet.usage.helpfile.parameters=\ + +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= -doclet.usage.stylesheetfile.description=File to change style of the generated\n\ -\ documentation +doclet.usage.sourcetab.parameters=\ + +doclet.usage.sourcetab.description=\ + Specify the number of spaces each tab takes up in the source -doclet.usage.docencoding.parameters= -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=\ + +doclet.usage.stylesheetfile.description=\ + File to change style of the generated documentation -doclet.xusage.xdocrootparent.parameters= -doclet.xusage.xdocrootparent.description=Replaces all @docRoot followed by /..\n\ -\ in doc comments with +doclet.usage.docencoding.parameters=\ + +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|[-]) -# 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\ -\ is one of accessibility, html,\n\ -\ missing, reference, or syntax.\n +doclet.usage.xdocrootparent.parameters=\ + +doclet.usage.xdocrootparent.description=\ + Replaces all @docRoot followed by /.. in doc comments with\n\ + + +doclet.usage.xdoclint.description=\ + Enable recommended checks for problems in javadoc comments -doclet.xusage.xdoclint-package.parameters=([-]) -doclet.xusage.xdoclint-package.description=\n\ -\ Enable or disable checks in specific\n\ -\ 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|[-]) +# 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 is one of accessibility, html,\n\ + missing, reference, or syntax. + +doclet.usage.xdoclint-package.parameters=\ + ([-]) +doclet.usage.xdoclint-package.description=\ + Enable or disable checks in specific 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. diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java Mon Oct 10 13:31:48 2016 -0700 @@ -404,8 +404,9 @@ } public Set getSupportedOptions() { + Resources resources = getResources(); Doclet.Option[] options = { - new Option(this, "-author") { + new Option(resources, "-author") { @Override public boolean process(String opt, ListIterator 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 = ""; this.parameters = ""; } 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 diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java Mon Oct 10 13:31:48 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(); } diff -r ef26c8e40f1e -r 31882abda8b5 langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Mon Oct 03 14:10:40 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Mon Oct 10 13:31:48 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