diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 8aba430d599..0f468dba94d 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -272,3 +272,4 @@ d3ec8d048e6c3c46b6e0ee011cc551ad386dfba5 jdk9-b26 ba5645f2735b41ed085d07ba20fa7b322afff318 jdk9-b27 ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28 9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29 +36e9bc875325813ac9c44ac0c617a463091fa9f5 jdk9-b30 diff --git a/Makefile b/Makefile index 6827fd615f3..d385e0f3299 100644 --- a/Makefile +++ b/Makefile @@ -108,12 +108,23 @@ else $(shell $(MKDIR) -p $(SJAVAC_SERVER_DIR) && $(RM) -rf $(SJAVAC_SERVER_DIR)/*) endif + # Split out the targets requiring sequential execution. Run these targets separately + # from the rest so that the rest may still enjoy full parallel execution. + SEQUENTIAL_TARGETS := $(filter dist-clean clean% reconfigure, $(MAIN_TARGETS)) + PARALLEL_TARGETS := $(filter-out $(SEQUENTIAL_TARGETS), $(MAIN_TARGETS)) + main-wrapper: - @$(if $(findstring clean, $(MAIN_TARGETS)), , $(call AtMakeStart)) - (cd $(root_dir)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ - $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(MAIN_TARGETS) \ - $(if $(filter true, $(OUTPUT_SYNC_SUPPORTED)), -O$(OUTPUT_SYNC))) - @$(if $(findstring clean, $(MAIN_TARGETS)), , $(call AtMakeEnd)) + ifneq ($(SEQUENTIAL_TARGETS), ) + (cd $(root_dir)/make && $(MAKE) -f Main.gmk SPEC=$(SPEC) -j 1 \ + $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(SEQUENTIAL_TARGETS)) + endif + ifneq ($(PARALLEL_TARGETS), ) + @$(call AtMakeStart) + (cd $(root_dir)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ + $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(PARALLEL_TARGETS) \ + $(if $(filter true, $(OUTPUT_SYNC_SUPPORTED)), -O$(OUTPUT_SYNC))) + @$(call AtMakeEnd) + endif .PHONY: main-wrapper @@ -138,10 +149,9 @@ help: $(info . make profiles # Create complete j2re compact profile images) $(info . make bootcycle-images # Build images twice, second time with newly built JDK) $(info . make install # Install the generated images locally) + $(info . make reconfigure # Rerun configure with the same arguments as last time) $(info . make clean # Remove all files generated by make, but not those) - $(info . # generated by configure. Do not run clean and other) - $(info . # targets together as that might behave in an) - $(info . # unexpected way.) + $(info . # generated by configure) $(info . make dist-clean # Remove all files, including configuration) $(info . make help # Give some help on using make) $(info . make test # Run tests, default is all tests (see TEST below)) diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index ca373c859f1..481d328a1c4 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -54,6 +54,7 @@ m4_include([toolchain_windows.m4]) AC_DEFUN_ONCE([CUSTOM_EARLY_HOOK]) AC_DEFUN_ONCE([CUSTOM_LATE_HOOK]) +AC_DEFUN_ONCE([CUSTOM_SUMMARY_AND_WARNINGS_HOOK]) # This line needs to be here, verbatim, after all includes and the dummy hook # definitions. It is replaced with custom functionality when building @@ -273,3 +274,4 @@ $CHMOD +x $OUTPUT_ROOT/compare.sh # Finally output some useful information to the user HELP_PRINT_SUMMARY_AND_WARNINGS +CUSTOM_SUMMARY_AND_WARNINGS_HOOK diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index d24edd39c20..8ceccb58d54 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -753,6 +753,7 @@ MCS GNM NM STRIP +MSBUILD DUMPBIN RC MT @@ -1088,6 +1089,7 @@ with_cups_include with_freetype with_freetype_include with_freetype_lib +with_freetype_src enable_freetype_bundling with_alsa with_alsa_include @@ -1942,6 +1944,9 @@ Optional Packages: headers under PATH/include) --with-freetype-include specify directory for the freetype include files --with-freetype-lib specify directory for the freetype library + --with-freetype-src specify directory with freetype sources to + automatically build the library (experimental, + Windows-only) --with-alsa specify prefix directory for the alsa package (expecting the libraries under PATH/lib and the headers under PATH/include) @@ -3882,20 +3887,18 @@ cygwin_help() { HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." ;; freetype) - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - HELP_MSG="To install freetype, run: -wget \"http://gnuwin32.sourceforge.net/downlinks/freetype.php\" -O /tmp/freetype-setup.exe -chmod +x /tmp/freetype-setup.exe -/tmp/freetype-setup.exe -Follow GUI prompts, and install to default directory \"C:\Program Files (x86)\GnuWin32\". -After installation, locate lib/libfreetype.dll.a and make a copy with the name freetype.dll." - else - HELP_MSG="You need to build a 64-bit version of freetype. -This is not readily available. -You can find source code and build instructions on -http://www.freetype.org/ -If you put the resulting build in \"C:\Program Files\GnuWin32\", it will be found automatically." - fi + HELP_MSG=" +The freetype library can now be build during the configure process. +Download the freetype sources and unpack them into an arbitrary directory: + +wget http://download.savannah.gnu.org/releases/freetype/freetype-2.5.3.tar.gz +tar -xzf freetype-2.5.3.tar.gz + +Then run configure with '--with-freetype-src='. This will +automatically build the freetype library into '/lib64' for 64-bit +builds or into '/lib32' for 32-bit builds. +Afterwards you can always use '--with-freetype-include=/include' +and '--with-freetype-lib=/lib32|64' for other builds." ;; esac } @@ -4060,6 +4063,8 @@ pkgadd_help() { + + # # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. @@ -4315,13 +4320,14 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" + # This line needs to be here, verbatim, after all includes and the dummy hook # definitions. It is replaced with custom functionality when building # custom sources. #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1409311712 +DATE_WHEN_GENERATED=1410377275 ############################################################################### # @@ -26881,6 +26887,10 @@ $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} @@ -26922,6 +26932,10 @@ $as_echo "$as_me: Please point to the VC/bin directory within the Visual Studio { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} @@ -26952,6 +26966,10 @@ $as_echo "$as_me: Warning: $VCVARSFILE is missing, this is probably Visual Studi { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} @@ -26981,6 +26999,10 @@ $as_echo "$as_me: Warning: $VCVARSFILE is missing, this is probably Visual Studi { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} @@ -27009,6 +27031,10 @@ $as_echo "$as_me: Warning: $VCVARSFILE is missing, this is probably Visual Studi { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Visual Studio installation at $VS100BASE using $METHOD" >&5 $as_echo "$as_me: Found Visual Studio installation at $VS100BASE using $METHOD" >&6;} @@ -27051,6 +27077,10 @@ $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&5 $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&6;} @@ -27093,6 +27123,10 @@ $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&5 $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&6;} @@ -27135,6 +27169,10 @@ $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&5 $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&6;} @@ -27176,6 +27214,10 @@ $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&5 $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&6;} @@ -27216,6 +27258,10 @@ $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else { $as_echo "$as_me:${as_lineno-$LINENO}: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&5 $as_echo "$as_me: Found Windows SDK installation at $WIN_SDK_BASE using $METHOD" >&6;} @@ -35112,6 +35158,50 @@ $as_echo "$as_me: This might be caused by spaces in the path, which is not allow $as_echo "$as_me: Rewriting DUMPBIN to \"$new_complete\"" >&6;} fi + # We need to check for 'msbuild.exe' because at the place where we expect to + # find 'msbuild.exe' there's also a directory called 'msbuild' and configure + # won't find the 'msbuild.exe' executable in that case (and the + # 'ac_executable_extensions' is unusable due to performance reasons). + # Notice that we intentionally don't fix up the path to MSBUILD because we + # will call it in a DOS shell during freetype detection on Windows (see + # 'LIB_SETUP_FREETYPE' in "libraries.m4" + # Extract the first word of "msbuild.exe", so it can be a program name with args. +set dummy msbuild.exe; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MSBUILD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MSBUILD"; then + ac_cv_prog_MSBUILD="$MSBUILD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MSBUILD="msbuild.exe" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MSBUILD=$ac_cv_prog_MSBUILD +if test -n "$MSBUILD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSBUILD" >&5 +$as_echo "$MSBUILD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then @@ -44318,6 +44408,12 @@ if test "${with_freetype_lib+set}" = set; then : withval=$with_freetype_lib; fi + +# Check whether --with-freetype-src was given. +if test "${with_freetype_src+set}" = set; then : + withval=$with_freetype_src; +fi + # Check whether --enable-freetype-bundling was given. if test "${enable_freetype_bundling+set}" = set; then : enableval=$enable_freetype_bundling; @@ -44329,7 +44425,7 @@ fi FREETYPE_BUNDLE_LIB_PATH= if test "x$FREETYPE_NOT_NEEDED" = xyes; then - if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x; then + if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x || test "x$with_freetype_src" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: freetype not used, so --with-freetype is ignored" >&5 $as_echo "$as_me: WARNING: freetype not used, so --with-freetype is ignored" >&2;} fi @@ -44342,6 +44438,429 @@ $as_echo "$as_me: WARNING: freetype not used, so --enable-freetype-bundling is i BUNDLE_FREETYPE="$enable_freetype_bundling" + if test "x$with_freetype_src" != x; then + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # Try to build freetype if --with-freetype-src was given on Windows + + FREETYPE_SRC_PATH="$with_freetype_src" + BUILD_FREETYPE=yes + + # Check if the freetype sources are acessible.. + if ! test -d $FREETYPE_SRC_PATH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-freetype-src specified, but can't find path \"$FREETYPE_SRC_PATH\" - ignoring --with-freetype-src" >&5 +$as_echo "$as_me: WARNING: --with-freetype-src specified, but can't find path \"$FREETYPE_SRC_PATH\" - ignoring --with-freetype-src" >&2;} + BUILD_FREETYPE=no + fi + # ..and contain a vc2010 project file + vcxproj_path="$FREETYPE_SRC_PATH/builds/windows/vc2010/freetype.vcxproj" + if test "x$BUILD_FREETYPE" = xyes && ! test -s $vcxproj_path; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find project file $vcxproj_path (you may try a newer freetype version) - ignoring --with-freetype-src" >&5 +$as_echo "$as_me: WARNING: Can't find project file $vcxproj_path (you may try a newer freetype version) - ignoring --with-freetype-src" >&2;} + BUILD_FREETYPE=no + fi + # Now check if configure found a version of 'msbuild.exe' + if test "x$BUILD_FREETYPE" = xyes && test "x$MSBUILD" == x ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find an msbuild.exe executable (you may try to install .NET 4.0) - ignoring --with-freetype-src" >&5 +$as_echo "$as_me: WARNING: Can't find an msbuild.exe executable (you may try to install .NET 4.0) - ignoring --with-freetype-src" >&2;} + BUILD_FREETYPE=no + fi + + # Ready to go.. + if test "x$BUILD_FREETYPE" = xyes; then + + # msbuild requires trailing slashes for output directories + freetype_lib_path="$FREETYPE_SRC_PATH/lib$OPENJDK_TARGET_CPU_BITS/" + freetype_lib_path_unix="$freetype_lib_path" + freetype_obj_path="$FREETYPE_SRC_PATH/obj$OPENJDK_TARGET_CPU_BITS/" + + unix_path="$vcxproj_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + vcxproj_path="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + vcxproj_path="$windows_path" + fi + + + unix_path="$freetype_lib_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + freetype_lib_path="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + freetype_lib_path="$windows_path" + fi + + + unix_path="$freetype_obj_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + freetype_obj_path="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + freetype_obj_path="$windows_path" + fi + + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + freetype_platform=x64 + else + freetype_platform=win32 + fi + + # The original freetype project file is for VS 2010 (i.e. 'v100'), + # so we have to adapt the toolset if building with any other toolsed (i.e. SDK). + # Currently 'PLATFORM_TOOLSET' is set in 'TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT'/ + # 'TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT' in toolchain_windows.m4 + { $as_echo "$as_me:${as_lineno-$LINENO}: Trying to compile freetype sources with PlatformToolset=$PLATFORM_TOOLSET to $freetype_lib_path_unix ..." >&5 +$as_echo "$as_me: Trying to compile freetype sources with PlatformToolset=$PLATFORM_TOOLSET to $freetype_lib_path_unix ..." >&6;} + + # First we try to build the freetype.dll + $ECHO -e "@echo off\n"\ + "$MSBUILD $vcxproj_path "\ + "/p:PlatformToolset=$PLATFORM_TOOLSET "\ + "/p:Configuration=\"Release Multithreaded\" "\ + "/p:Platform=$freetype_platform "\ + "/p:ConfigurationType=DynamicLibrary "\ + "/p:TargetName=freetype "\ + "/p:OutDir=\"$freetype_lib_path\" "\ + "/p:IntDir=\"$freetype_obj_path\" > freetype.log" > freetype.bat + cmd /c freetype.bat + + if test -s "$freetype_lib_path_unix/freetype.dll"; then + # If that succeeds we also build freetype.lib + $ECHO -e "@echo off\n"\ + "$MSBUILD $vcxproj_path "\ + "/p:PlatformToolset=$PLATFORM_TOOLSET "\ + "/p:Configuration=\"Release Multithreaded\" "\ + "/p:Platform=$freetype_platform "\ + "/p:ConfigurationType=StaticLibrary "\ + "/p:TargetName=freetype "\ + "/p:OutDir=\"$freetype_lib_path\" "\ + "/p:IntDir=\"$freetype_obj_path\" >> freetype.log" > freetype.bat + cmd /c freetype.bat + + if test -s "$freetype_lib_path_unix/freetype.lib"; then + # Once we build both, lib and dll, set freetype lib and include path appropriately + POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_SRC_PATH/include" + POTENTIAL_FREETYPE_LIB_PATH="$freetype_lib_path_unix" + { $as_echo "$as_me:${as_lineno-$LINENO}: Compiling freetype sources succeeded! (see freetype.log for build results)" >&5 +$as_echo "$as_me: Compiling freetype sources succeeded! (see freetype.log for build results)" >&6;} + else + BUILD_FREETYPE=no + fi + else + BUILD_FREETYPE=no + fi + fi + + if test "x$BUILD_FREETYPE" = xyes; then + # Okay, we built it. Check that it works. + + POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH" + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH" + METHOD="--with-freetype-src" + + # First check if the files exists. + if test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then + # We found an arbitrary include file. That's a good sign. + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5 +$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;} + FOUND_FREETYPE=yes + + FREETYPE_LIB_NAME="${LIBRARY_PREFIX}freetype${SHARED_LIBRARY_SUFFIX}" + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;} + FOUND_FREETYPE=no + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # On Windows, we will need both .lib and .dll file. + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/freetype.lib"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&6;} + FOUND_FREETYPE=no + fi + elif test "x$OPENJDK_TARGET_OS" = xsolaris \ + && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then + # Found lib in isa dir, use that instead. + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR" + fi + fi + fi + + if test "x$FOUND_FREETYPE" = xyes; then + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_LIB_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5 +$as_echo_n "checking for freetype includes... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5 +$as_echo "$FREETYPE_INCLUDE_PATH" >&6; } + FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5 +$as_echo_n "checking for freetype libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5 +$as_echo "$FREETYPE_LIB_PATH" >&6; } + fi + + if test "x$FOUND_FREETYPE" != xyes; then + as_fn_error $? "Can not use the built freetype at location given by --with-freetype-src" "$LINENO" 5 + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: User specified --with-freetype-src but building freetype failed. (see freetype.log for build results)" >&5 +$as_echo "$as_me: User specified --with-freetype-src but building freetype failed. (see freetype.log for build results)" >&6;} + as_fn_error $? "Consider building freetype manually and using --with-freetype instead." "$LINENO" 5 + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-freetype-src is currently only supported on Windows - ignoring" >&5 +$as_echo "$as_me: WARNING: --with-freetype-src is currently only supported on Windows - ignoring" >&2;} + fi + fi + if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x; then # User has specified settings @@ -51828,3 +52347,4 @@ $CHMOD +x $OUTPUT_ROOT/compare.sh printf "\n" fi + diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index 9ae7874fd6b..e1e792c3aa1 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -75,20 +75,18 @@ cygwin_help() { HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." ;; freetype) - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - HELP_MSG="To install freetype, run: -wget \"http://gnuwin32.sourceforge.net/downlinks/freetype.php\" -O /tmp/freetype-setup.exe -chmod +x /tmp/freetype-setup.exe -/tmp/freetype-setup.exe -Follow GUI prompts, and install to default directory \"C:\Program Files (x86)\GnuWin32\". -After installation, locate lib/libfreetype.dll.a and make a copy with the name freetype.dll." - else - HELP_MSG="You need to build a 64-bit version of freetype. -This is not readily available. -You can find source code and build instructions on -http://www.freetype.org/ -If you put the resulting build in \"C:\Program Files\GnuWin32\", it will be found automatically." - fi + HELP_MSG=" +The freetype library can now be build during the configure process. +Download the freetype sources and unpack them into an arbitrary directory: + +wget http://download.savannah.gnu.org/releases/freetype/freetype-2.5.3.tar.gz +tar -xzf freetype-2.5.3.tar.gz + +Then run configure with '--with-freetype-src='. This will +automatically build the freetype library into '/lib64' for 64-bit +builds or into '/lib32' for 32-bit builds. +Afterwards you can always use '--with-freetype-include=/include' +and '--with-freetype-lib=/lib[32|64]' for other builds." ;; esac } diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 3a689ef62ee..5f9eabf250b 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -247,12 +247,95 @@ AC_DEFUN_ONCE([LIB_SETUP_CUPS], ]) +AC_DEFUN([LIB_BUILD_FREETYPE], +[ + FREETYPE_SRC_PATH="$1" + BUILD_FREETYPE=yes + + # Check if the freetype sources are acessible.. + if ! test -d $FREETYPE_SRC_PATH; then + AC_MSG_WARN([--with-freetype-src specified, but can't find path "$FREETYPE_SRC_PATH" - ignoring --with-freetype-src]) + BUILD_FREETYPE=no + fi + # ..and contain a vc2010 project file + vcxproj_path="$FREETYPE_SRC_PATH/builds/windows/vc2010/freetype.vcxproj" + if test "x$BUILD_FREETYPE" = xyes && ! test -s $vcxproj_path; then + AC_MSG_WARN([Can't find project file $vcxproj_path (you may try a newer freetype version) - ignoring --with-freetype-src]) + BUILD_FREETYPE=no + fi + # Now check if configure found a version of 'msbuild.exe' + if test "x$BUILD_FREETYPE" = xyes && test "x$MSBUILD" == x ; then + AC_MSG_WARN([Can't find an msbuild.exe executable (you may try to install .NET 4.0) - ignoring --with-freetype-src]) + BUILD_FREETYPE=no + fi + + # Ready to go.. + if test "x$BUILD_FREETYPE" = xyes; then + + # msbuild requires trailing slashes for output directories + freetype_lib_path="$FREETYPE_SRC_PATH/lib$OPENJDK_TARGET_CPU_BITS/" + freetype_lib_path_unix="$freetype_lib_path" + freetype_obj_path="$FREETYPE_SRC_PATH/obj$OPENJDK_TARGET_CPU_BITS/" + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(vcxproj_path) + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(freetype_lib_path) + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(freetype_obj_path) + if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + freetype_platform=x64 + else + freetype_platform=win32 + fi + + # The original freetype project file is for VS 2010 (i.e. 'v100'), + # so we have to adapt the toolset if building with any other toolsed (i.e. SDK). + # Currently 'PLATFORM_TOOLSET' is set in 'TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT'/ + # 'TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT' in toolchain_windows.m4 + AC_MSG_NOTICE([Trying to compile freetype sources with PlatformToolset=$PLATFORM_TOOLSET to $freetype_lib_path_unix ...]) + + # First we try to build the freetype.dll + $ECHO -e "@echo off\n"\ + "$MSBUILD $vcxproj_path "\ + "/p:PlatformToolset=$PLATFORM_TOOLSET "\ + "/p:Configuration=\"Release Multithreaded\" "\ + "/p:Platform=$freetype_platform "\ + "/p:ConfigurationType=DynamicLibrary "\ + "/p:TargetName=freetype "\ + "/p:OutDir=\"$freetype_lib_path\" "\ + "/p:IntDir=\"$freetype_obj_path\" > freetype.log" > freetype.bat + cmd /c freetype.bat + + if test -s "$freetype_lib_path_unix/freetype.dll"; then + # If that succeeds we also build freetype.lib + $ECHO -e "@echo off\n"\ + "$MSBUILD $vcxproj_path "\ + "/p:PlatformToolset=$PLATFORM_TOOLSET "\ + "/p:Configuration=\"Release Multithreaded\" "\ + "/p:Platform=$freetype_platform "\ + "/p:ConfigurationType=StaticLibrary "\ + "/p:TargetName=freetype "\ + "/p:OutDir=\"$freetype_lib_path\" "\ + "/p:IntDir=\"$freetype_obj_path\" >> freetype.log" > freetype.bat + cmd /c freetype.bat + + if test -s "$freetype_lib_path_unix/freetype.lib"; then + # Once we build both, lib and dll, set freetype lib and include path appropriately + POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_SRC_PATH/include" + POTENTIAL_FREETYPE_LIB_PATH="$freetype_lib_path_unix" + AC_MSG_NOTICE([Compiling freetype sources succeeded! (see freetype.log for build results)]) + else + BUILD_FREETYPE=no + fi + else + BUILD_FREETYPE=no + fi + fi +]) + AC_DEFUN([LIB_CHECK_POTENTIAL_FREETYPE], [ POTENTIAL_FREETYPE_INCLUDE_PATH="$1" POTENTIAL_FREETYPE_LIB_PATH="$2" METHOD="$3" - + # First check if the files exists. if test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then # We found an arbitrary include file. That's a good sign. @@ -305,6 +388,8 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], [specify directory for the freetype include files])]) AC_ARG_WITH(freetype-lib, [AS_HELP_STRING([--with-freetype-lib], [specify directory for the freetype library])]) + AC_ARG_WITH(freetype-src, [AS_HELP_STRING([--with-freetype-src], + [specify directory with freetype sources to automatically build the library (experimental, Windows-only)])]) AC_ARG_ENABLE(freetype-bundling, [AS_HELP_STRING([--disable-freetype-bundling], [disable bundling of the freetype library with the build result @<:@enabled on Windows or when using --with-freetype, disabled otherwise@:>@])]) @@ -313,7 +398,7 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], FREETYPE_BUNDLE_LIB_PATH= if test "x$FREETYPE_NOT_NEEDED" = xyes; then - if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x; then + if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x || test "x$with_freetype_src" != x; then AC_MSG_WARN([freetype not used, so --with-freetype is ignored]) fi if test "x$enable_freetype_bundling" != x; then @@ -324,6 +409,25 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], BUNDLE_FREETYPE="$enable_freetype_bundling" + if test "x$with_freetype_src" != x; then + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # Try to build freetype if --with-freetype-src was given on Windows + LIB_BUILD_FREETYPE([$with_freetype_src]) + if test "x$BUILD_FREETYPE" = xyes; then + # Okay, we built it. Check that it works. + LIB_CHECK_POTENTIAL_FREETYPE($POTENTIAL_FREETYPE_INCLUDE_PATH, $POTENTIAL_FREETYPE_LIB_PATH, [--with-freetype-src]) + if test "x$FOUND_FREETYPE" != xyes; then + AC_MSG_ERROR([Can not use the built freetype at location given by --with-freetype-src]) + fi + else + AC_MSG_NOTICE([User specified --with-freetype-src but building freetype failed. (see freetype.log for build results)]) + AC_MSG_ERROR([Consider building freetype manually and using --with-freetype instead.]) + fi + else + AC_MSG_WARN([--with-freetype-src is currently only supported on Windows - ignoring]) + fi + fi + if test "x$with_freetype" != x || test "x$with_freetype_include" != x || test "x$with_freetype_lib" != x; then # User has specified settings @@ -331,12 +435,12 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], # If not specified, default is to bundle freetype BUNDLE_FREETYPE=yes fi - + if test "x$with_freetype" != x; then POTENTIAL_FREETYPE_INCLUDE_PATH="$with_freetype/include" POTENTIAL_FREETYPE_LIB_PATH="$with_freetype/lib" fi - + # Allow --with-freetype-lib and --with-freetype-include to override if test "x$with_freetype_include" != x; then POTENTIAL_FREETYPE_INCLUDE_PATH="$with_freetype_include" @@ -468,7 +572,7 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], FREETYPE_CFLAGS="-I$FREETYPE_INCLUDE_PATH" fi fi - + if test "x$FREETYPE_LIBS" = x; then BASIC_FIXUP_PATH(FREETYPE_LIB_PATH) if test "x$OPENJDK_TARGET_OS" = xwindows; then @@ -484,7 +588,7 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], PREV_CXXCFLAGS="$CXXFLAGS" PREV_LIBS="$LIBS" PREV_CXX="$CXX" - CXXFLAGS="$CXXFLAGS $FREETYPE_CFLAGS" + CXXFLAGS="$CXXFLAGS $FREETYPE_CFLAGS" LIBS="$LIBS $FREETYPE_LIBS" CXX="$FIXPATH $CXX" AC_LINK_IFELSE([AC_LANG_SOURCE([[ @@ -502,9 +606,9 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], AC_MSG_RESULT([no]) AC_MSG_NOTICE([Could not compile and link with freetype. This might be a 32/64-bit mismatch.]) AC_MSG_NOTICE([Using FREETYPE_CFLAGS=$FREETYPE_CFLAGS and FREETYPE_LIBS=$FREETYPE_LIBS]) - + HELP_MSG_MISSING_DEPENDENCY([freetype]) - + AC_MSG_ERROR([Can not continue without freetype. $HELP_MSG]) ] ) diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index f380bf446ad..db0a253a207 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -557,6 +557,14 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA], BASIC_FIXUP_EXECUTABLE(RC) AC_CHECK_PROG([DUMPBIN], [dumpbin], [dumpbin],,,) BASIC_FIXUP_EXECUTABLE(DUMPBIN) + # We need to check for 'msbuild.exe' because at the place where we expect to + # find 'msbuild.exe' there's also a directory called 'msbuild' and configure + # won't find the 'msbuild.exe' executable in that case (and the + # 'ac_executable_extensions' is unusable due to performance reasons). + # Notice that we intentionally don't fix up the path to MSBUILD because we + # will call it in a DOS shell during freetype detection on Windows (see + # 'LIB_SETUP_FREETYPE' in "libraries.m4" + AC_CHECK_PROG([MSBUILD], [msbuild.exe], [msbuild.exe],,,) fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index bdd110582c9..380f7dd4054 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -33,6 +33,10 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], if test -f "$VS100BASE/$VCVARSFILE"; then AC_MSG_NOTICE([Found Visual Studio installation at $VS100BASE using $METHOD]) VS_ENV_CMD="$VS100BASE/$VCVARSFILE" + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be one of 'v100', 'v110' or 'v120' for VS 2010, 2012 or VS2013 + # TODO: improve detection for other versions of VS + PLATFORM_TOOLSET="v100" else AC_MSG_NOTICE([Found Visual Studio installation at $VS100BASE using $METHOD]) AC_MSG_NOTICE([Warning: $VCVARSFILE is missing, this is probably Visual Studio Express. Ignoring]) @@ -61,6 +65,10 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT], else VS_ENV_ARGS="/x64" fi + # PLATFORM_TOOLSET is used during the compilation of the freetype sources (see + # 'LIB_BUILD_FREETYPE' in libraries.m4) and must be 'Windows7.1SDK' for Windows7.1SDK + # TODO: improve detection for other versions of SDK + PLATFORM_TOOLSET="Windows7.1SDK" else AC_MSG_NOTICE([Found Windows SDK installation at $WIN_SDK_BASE using $METHOD]) AC_MSG_NOTICE([Warning: Installation is broken, SetEnv.Cmd is missing. Ignoring]) diff --git a/corba/.hgignore b/corba/.hgignore index e05f09317c5..5e6b22f24ee 100644 --- a/corba/.hgignore +++ b/corba/.hgignore @@ -1,5 +1,6 @@ ^build/ ^dist/ +^webrev /nbproject/private/ ^.hgtip .DS_Store diff --git a/corba/.hgtags b/corba/.hgtags index b2e4f01ee41..210911039ff 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -272,3 +272,4 @@ da08cca6b97f41b7081a3e176dcb400af6e4bb26 jdk9-b25 7e06bf1dcb0907b80ddf59315426ce9ce775e56d jdk9-b27 a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28 163a9cd806fd09970baf1f5f42b92a3cfe7ee945 jdk9-b29 +98967ae6ae53ebf15615e07cd5a6b1ae04dfd84c jdk9-b30 diff --git a/hotspot/.hgignore b/hotspot/.hgignore index c652de177bf..e9ce602582b 100644 --- a/hotspot/.hgignore +++ b/hotspot/.hgignore @@ -1,5 +1,6 @@ ^build/ ^dist/ +^webrev /nbproject/private/ ^src/share/tools/hsdis/build/ ^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/ diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 518ab26c6a0..a7b7e9b5c01 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -432,3 +432,4 @@ dde2d03b0ea46a27650839e3a1d212c7c1f7b4c8 jdk9-b24 f95347244306affc32ce3056f27ceff7b2100810 jdk9-b27 657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28 deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29 +5c722dffbc0f34eb8d903dca7b261e52248fa17e jdk9-b30 diff --git a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c index 0d3960f7ae7..5df5f1f1359 100644 --- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c +++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c @@ -64,7 +64,10 @@ static jmethodID listAdd_ID = 0; #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;} void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { - (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); + jclass clazz; + clazz = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); + CHECK_EXCEPTION; + (*env)->ThrowNew(env, clazz, errMsg); } struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { @@ -149,11 +152,14 @@ static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_p const char* name; jobject loadObject; jobject loadObjectList; + jstring str; base = get_lib_base(ph, i); name = get_lib_name(ph, i); - loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, - (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); + + str = (*env)->NewStringUTF(env, name); + CHECK_EXCEPTION; + loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, str, (jlong)0, (jlong)base); CHECK_EXCEPTION; loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); CHECK_EXCEPTION; @@ -298,13 +304,18 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_l JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByAddress0 (JNIEnv *env, jobject this_obj, jlong addr) { uintptr_t offset; + jobject obj; + jstring str; const char* sym = NULL; struct ps_prochandle* ph = get_proc_handle(env, this_obj); sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); if (sym == NULL) return 0; - return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, - (*env)->NewStringUTF(env, sym), (jlong)offset); + str = (*env)->NewStringUTF(env, sym); + CHECK_EXCEPTION_(NULL); + obj = (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, str, (jlong)offset); + CHECK_EXCEPTION_(NULL); + return obj; } /* diff --git a/hotspot/agent/src/os/solaris/proc/saproc.cpp b/hotspot/agent/src/os/solaris/proc/saproc.cpp index 3f0e6b25814..d727740ee34 100644 --- a/hotspot/agent/src/os/solaris/proc/saproc.cpp +++ b/hotspot/agent/src/os/solaris/proc/saproc.cpp @@ -90,7 +90,9 @@ struct DebuggerWith2Objects : DebuggerWithObject { */ static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) { - env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg); + jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"); + CHECK_EXCEPTION; + env->ThrowNew(clazz, errMsg); } // JNI ids for some fields, methods @@ -962,6 +964,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLoca CHECK_EXCEPTION_(0); jboolean isCopy; jlong* ptr = env->GetLongArrayElements(res, &isCopy); + CHECK_EXCEPTION_(NULL); for (int i = 0; i < NPRGREG; i++) { ptr[i] = (jlong) (uintptr_t) gregs[i]; } @@ -1253,6 +1256,7 @@ JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_d (JNIEnv *env, jobject this_object, jstring name) { jboolean isCopy; const char* ptr = env->GetStringUTFChars(name, &isCopy); + CHECK_EXCEPTION_(NULL); char buf[2*SYMBOL_BUF_SIZE + 1]; jstring res = 0; if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) { @@ -1439,7 +1443,9 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_init "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); CHECK_EXCEPTION; - listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z"); + jclass list_clazz = env->FindClass("java/util/List"); + CHECK_EXCEPTION; + listAdd_ID = env->GetMethodID(list_clazz, "add", "(Ljava/lang/Object;)Z"); CHECK_EXCEPTION; // part of the class sharing workaround diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java index ba9422ca8ee..a411534ea3a 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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,7 +49,6 @@ public class ArrayKlass extends Klass { higherDimension = new MetadataField(type.getAddressField("_higher_dimension"), 0); lowerDimension = new MetadataField(type.getAddressField("_lower_dimension"), 0); vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0); - componentMirror = new OopField(type.getOopField("_component_mirror"), 0); javaLangCloneableName = null; javaLangObjectName = null; javaIoSerializableName = null; @@ -63,7 +62,6 @@ public class ArrayKlass extends Klass { private static MetadataField higherDimension; private static MetadataField lowerDimension; private static CIntField vtableLen; - private static OopField componentMirror; public Klass getJavaSuper() { SystemDictionary sysDict = VM.getVM().getSystemDictionary(); @@ -74,7 +72,6 @@ public class ArrayKlass extends Klass { public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); } public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); } public long getVtableLen() { return vtableLen.getValue(this); } - public Oop getComponentMirror() { return componentMirror.getValue(this); } // constant class names - javaLangCloneable, javaIoSerializable, javaLangObject // Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and SymbolTable @@ -144,6 +141,5 @@ public class ArrayKlass extends Klass { visitor.doMetadata(higherDimension, true); visitor.doMetadata(lowerDimension, true); visitor.doCInt(vtableLen, true); - visitor.doOop(componentMirror, true); } } diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index 8668884d763..4ef0e45a9ba 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -337,7 +337,7 @@ export_optimized: export_product_jdk:: $(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR) generic_export export_optimized_jdk:: - $(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR) generic_export + $(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR)/$(@:export_%_jdk=%) generic_export export_fastdebug_jdk:: $(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR)/$(@:export_%_jdk=%) generic_export export_debug_jdk:: diff --git a/hotspot/make/aix/makefiles/mapfile-vers-debug b/hotspot/make/aix/makefiles/mapfile-vers-debug index 0a9d3e981c9..613e26bd880 100644 --- a/hotspot/make/aix/makefiles/mapfile-vers-debug +++ b/hotspot/make/aix/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/aix/makefiles/mapfile-vers-product b/hotspot/make/aix/makefiles/mapfile-vers-product index f748a10c8e2..0b8a040c74a 100644 --- a/hotspot/make/aix/makefiles/mapfile-vers-product +++ b/hotspot/make/aix/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index b31b0cd17a1..1877245e435 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -325,6 +325,10 @@ ifeq ($(USE_CLANG), true) else ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 1), 1) OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 + # Clang 6.0 + else ifeq ($(shell expr $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) = 0), 1) + OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) + OPT_CFLAGS/unsafe.o += -O1 else $(error "Update compiler workarounds for Clang $(CC_VER_MAJOR).$(CC_VER_MINOR)") endif diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug index db8c276811a..7f7f00036fe 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,6 @@ _JVM_GetClassSignature _JVM_GetClassSigners _JVM_GetClassTypeAnnotations - _JVM_GetComponentType _JVM_GetDeclaredClasses _JVM_GetDeclaringClass _JVM_GetEnclosingMethodInfo diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product index db8c276811a..7f7f00036fe 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,6 @@ _JVM_GetClassSignature _JVM_GetClassSigners _JVM_GetClassTypeAnnotations - _JVM_GetComponentType _JVM_GetDeclaredClasses _JVM_GetDeclaringClass _JVM_GetEnclosingMethodInfo diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-debug b/hotspot/make/bsd/makefiles/mapfile-vers-debug index df433ad55ea..f7d88125ab5 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-product b/hotspot/make/bsd/makefiles/mapfile-vers-product index df433ad55ea..f7d88125ab5 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/linux/makefiles/mapfile-vers-debug b/hotspot/make/linux/makefiles/mapfile-vers-debug index df433ad55ea..f7d88125ab5 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-debug +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product index df433ad55ea..f7d88125ab5 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-product +++ b/hotspot/make/linux/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2014, 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 @@ -125,7 +125,6 @@ SUNWprivate_1.1 { JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetClassTypeAnnotations; - JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; diff --git a/hotspot/make/solaris/makefiles/mapfile-vers b/hotspot/make/solaris/makefiles/mapfile-vers index d2a3d5c6e2a..9bf34ff8305 100644 --- a/hotspot/make/solaris/makefiles/mapfile-vers +++ b/hotspot/make/solaris/makefiles/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2014, 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 @@ -124,7 +124,6 @@ SUNWprivate_1.1 { JVM_GetClassNameUTF; JVM_GetClassSignature; JVM_GetClassSigners; - JVM_GetComponentType; JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; diff --git a/hotspot/make/solaris/makefiles/sparcWorks.make b/hotspot/make/solaris/makefiles/sparcWorks.make index cff57a29682..30d0c2ec691 100644 --- a/hotspot/make/solaris/makefiles/sparcWorks.make +++ b/hotspot/make/solaris/makefiles/sparcWorks.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2014, 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 @@ -53,9 +53,9 @@ ifeq ($(JRE_RELEASE_VER),1.6.0) VALIDATED_COMPILER_REVS := 5.8 VALIDATED_CC_COMPILER_REVS := 5.8 else - # Validated compiler for JDK7 is SS12 update 1 + patches (5.10) - VALIDATED_COMPILER_REVS := 5.10 - VALIDATED_CC_COMPILER_REVS := 5.10 + # Validated compiler for JDK9 is SS12.3 (5.12) + VALIDATED_COMPILER_REVS := 5.12 + VALIDATED_CC_COMPILER_REVS := 5.12 endif # Warning messages about not using the above validated versions diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 34219277523..8098e889ba9 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -4937,6 +4937,26 @@ void Assembler::addq(Register dst, Register src) { emit_arith(0x03, 0xC0, dst, src); } +void Assembler::adcxq(Register dst, Register src) { + //assert(VM_Version::supports_adx(), "adx instructions not supported"); + emit_int8((unsigned char)0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8(0x38); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::adoxq(Register dst, Register src) { + //assert(VM_Version::supports_adx(), "adx instructions not supported"); + emit_int8((unsigned char)0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8(0x38); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::andq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); @@ -5444,6 +5464,26 @@ void Assembler::movzwq(Register dst, Register src) { emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::mulq(Address src) { + InstructionMark im(this); + prefixq(src); + emit_int8((unsigned char)0xF7); + emit_operand(rsp, src); +} + +void Assembler::mulq(Register src) { + int encode = prefixq_and_encode(src->encoding()); + emit_int8((unsigned char)0xF7); + emit_int8((unsigned char)(0xE0 | encode)); +} + +void Assembler::mulxq(Register dst1, Register dst2, Register src) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, true, false); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::negq(Register dst) { int encode = prefixq_and_encode(dst->encoding()); emit_int8((unsigned char)0xF7); @@ -5572,6 +5612,28 @@ void Assembler::rclq(Register dst, int imm8) { emit_int8(imm8); } } + +void Assembler::rorq(Register dst, int imm8) { + assert(isShiftCount(imm8 >> 1), "illegal shift count"); + int encode = prefixq_and_encode(dst->encoding()); + if (imm8 == 1) { + emit_int8((unsigned char)0xD1); + emit_int8((unsigned char)(0xC8 | encode)); + } else { + emit_int8((unsigned char)0xC1); + emit_int8((unsigned char)(0xc8 | encode)); + emit_int8(imm8); + } +} + +void Assembler::rorxq(Register dst, Register src, int imm8) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, true, false); + emit_int8((unsigned char)0xF0); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::sarq(Register dst, int imm8) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); int encode = prefixq_and_encode(dst->encoding()); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 8edf31cada8..2ac9df8c927 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -888,6 +888,14 @@ private: void addq(Register dst, Address src); void addq(Register dst, Register src); +#ifdef _LP64 + //Add Unsigned Integers with Carry Flag + void adcxq(Register dst, Register src); + + //Add Unsigned Integers with Overflow Flag + void adoxq(Register dst, Register src); +#endif + void addr_nop_4(); void addr_nop_5(); void addr_nop_7(); @@ -1204,19 +1212,20 @@ private: void idivl(Register src); void divl(Register src); // Unsigned division +#ifdef _LP64 void idivq(Register src); +#endif void imull(Register dst, Register src); void imull(Register dst, Register src, int value); void imull(Register dst, Address src); +#ifdef _LP64 void imulq(Register dst, Register src); void imulq(Register dst, Register src, int value); -#ifdef _LP64 void imulq(Register dst, Address src); #endif - // jcc is the generic conditional branch generator to run- // time routines, jcc is used for branches to labels. jcc // takes a branch opcode (cc) and a label (L) and generates @@ -1408,9 +1417,16 @@ private: void movzwq(Register dst, Register src); #endif + // Unsigned multiply with RAX destination register void mull(Address src); void mull(Register src); +#ifdef _LP64 + void mulq(Address src); + void mulq(Register src); + void mulxq(Register dst1, Register dst2, Register src); +#endif + // Multiply Scalar Double-Precision Floating-Point Values void mulsd(XMMRegister dst, Address src); void mulsd(XMMRegister dst, XMMRegister src); @@ -1541,6 +1557,11 @@ private: void ret(int imm16); +#ifdef _LP64 + void rorq(Register dst, int imm8); + void rorxq(Register dst, Register src, int imm8); +#endif + void sahf(); void sarl(Register dst, int imm8); diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 5b34293ea6a..1401997b3a1 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -176,6 +176,8 @@ define_pd_global(uintx, TypeProfileLevel, 111); "Use count trailing zeros instruction") \ \ product(bool, UseBMI1Instructions, false, \ - "Use BMI instructions") - + "Use BMI1 instructions") \ + \ + product(bool, UseBMI2Instructions, false, \ + "Use BMI2 instructions") #endif // CPU_X86_VM_GLOBALS_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 7216c198027..592b45c9fd0 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -7293,6 +7293,467 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, bind(L_done); } +#ifdef _LP64 +/** + * Helper for multiply_to_len(). + */ +void MacroAssembler::add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) { + addq(dest_lo, src1); + adcq(dest_hi, 0); + addq(dest_lo, src2); + adcq(dest_hi, 0); +} + +/** + * Multiply 64 bit by 64 bit first loop. + */ +void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) { + // + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // huge_128 product = y[idx] * x[xstart] + carry; + // z[kdx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // z[xstart] = carry; + // + + Label L_first_loop, L_first_loop_exit; + Label L_one_x, L_one_y, L_multiply; + + decrementl(xstart); + jcc(Assembler::negative, L_one_x); + + movq(x_xstart, Address(x, xstart, Address::times_4, 0)); + rorq(x_xstart, 32); // convert big-endian to little-endian + + bind(L_first_loop); + decrementl(idx); + jcc(Assembler::negative, L_first_loop_exit); + decrementl(idx); + jcc(Assembler::negative, L_one_y); + movq(y_idx, Address(y, idx, Address::times_4, 0)); + rorq(y_idx, 32); // convert big-endian to little-endian + bind(L_multiply); + movq(product, x_xstart); + mulq(y_idx); // product(rax) * y_idx -> rdx:rax + addq(product, carry); + adcq(rdx, 0); + subl(kdx, 2); + movl(Address(z, kdx, Address::times_4, 4), product); + shrq(product, 32); + movl(Address(z, kdx, Address::times_4, 0), product); + movq(carry, rdx); + jmp(L_first_loop); + + bind(L_one_y); + movl(y_idx, Address(y, 0)); + jmp(L_multiply); + + bind(L_one_x); + movl(x_xstart, Address(x, 0)); + jmp(L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 64 bit by 64 bit and add 128 bit. + */ +void MacroAssembler::multiply_add_128_x_128(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, + Register carry, Register product, int offset) { + // huge_128 product = (y[idx] * x_xstart) + z[kdx] + carry; + // z[kdx] = (jlong)product; + + movq(yz_idx, Address(y, idx, Address::times_4, offset)); + rorq(yz_idx, 32); // convert big-endian to little-endian + movq(product, x_xstart); + mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax) + movq(yz_idx, Address(z, idx, Address::times_4, offset)); + rorq(yz_idx, 32); // convert big-endian to little-endian + + add2_with_carry(rdx, product, carry, yz_idx); + + movl(Address(z, idx, Address::times_4, offset+4), product); + shrq(product, 32); + movl(Address(z, idx, Address::times_4, offset), product); + +} + +/** + * Multiply 128 bit by 128 bit. Unrolled inner loop. + */ +void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, Register jdx, + Register carry, Register product, + Register carry2) { + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 product = (y[idx+1] * x_xstart) + z[kdx+idx+1] + carry; + // z[kdx+idx+1] = (jlong)product; + // jlong carry2 = (jlong)(product >>> 64); + // product = (y[idx] * x_xstart) + z[kdx+idx] + carry2; + // z[kdx+idx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // idx += 2; + // if (idx > 0) { + // product = (y[idx] * x_xstart) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + movl(jdx, idx); + andl(jdx, 0xFFFFFFFC); + shrl(jdx, 2); + + bind(L_third_loop); + subl(jdx, 1); + jcc(Assembler::negative, L_third_loop_exit); + subl(idx, 4); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 8); + movq(carry2, rdx); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry2, product, 0); + movq(carry, rdx); + jmp(L_third_loop); + + bind (L_third_loop_exit); + + andl (idx, 0x3); + jcc(Assembler::zero, L_post_third_loop_done); + + Label L_check_1; + subl(idx, 2); + jcc(Assembler::negative, L_check_1); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 0); + movq(carry, rdx); + + bind (L_check_1); + addl (idx, 0x2); + andl (idx, 0x1); + subl(idx, 1); + jcc(Assembler::negative, L_post_third_loop_done); + + movl(yz_idx, Address(y, idx, Address::times_4, 0)); + movq(product, x_xstart); + mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax) + movl(yz_idx, Address(z, idx, Address::times_4, 0)); + + add2_with_carry(rdx, product, yz_idx, carry); + + movl(Address(z, idx, Address::times_4, 0), product); + shrq(product, 32); + + shlq(rdx, 32); + orq(product, rdx); + movq(carry, product); + + bind(L_post_third_loop_done); +} + +/** + * Multiply 128 bit by 128 bit using BMI2. Unrolled inner loop. + * + */ +void MacroAssembler::multiply_128_x_128_bmi2_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4) { + assert(UseBMI2Instructions, "should be used only when BMI2 is available"); + + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 tmp3 = (y[idx+1] * rdx) + z[kdx+idx+1] + carry; + // jlong carry2 = (jlong)(tmp3 >>> 64); + // huge_128 tmp4 = (y[idx] * rdx) + z[kdx+idx] + carry2; + // carry = (jlong)(tmp4 >>> 64); + // z[kdx+idx+1] = (jlong)tmp3; + // z[kdx+idx] = (jlong)tmp4; + // } + // idx += 2; + // if (idx > 0) { + // yz_idx1 = (y[idx] * rdx) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)yz_idx1; + // carry = (jlong)(yz_idx1 >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + movl(jdx, idx); + andl(jdx, 0xFFFFFFFC); + shrl(jdx, 2); + + bind(L_third_loop); + subl(jdx, 1); + jcc(Assembler::negative, L_third_loop_exit); + subl(idx, 4); + + movq(yz_idx1, Address(y, idx, Address::times_4, 8)); + rorxq(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian + movq(yz_idx2, Address(y, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3 + mulxq(carry2, tmp, yz_idx2); // yz_idx2 * rdx -> carry2:tmp + + movq(yz_idx1, Address(z, idx, Address::times_4, 8)); + rorxq(yz_idx1, yz_idx1, 32); + movq(yz_idx2, Address(z, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + if (VM_Version::supports_adx()) { + adcxq(tmp3, carry); + adoxq(tmp3, yz_idx1); + + adcxq(tmp4, tmp); + adoxq(tmp4, yz_idx2); + + movl(carry, 0); // does not affect flags + adcxq(carry2, carry); + adoxq(carry2, carry); + } else { + add2_with_carry(tmp4, tmp3, carry, yz_idx1); + add2_with_carry(carry2, tmp4, tmp, yz_idx2); + } + movq(carry, carry2); + + movl(Address(z, idx, Address::times_4, 12), tmp3); + shrq(tmp3, 32); + movl(Address(z, idx, Address::times_4, 8), tmp3); + + movl(Address(z, idx, Address::times_4, 4), tmp4); + shrq(tmp4, 32); + movl(Address(z, idx, Address::times_4, 0), tmp4); + + jmp(L_third_loop); + + bind (L_third_loop_exit); + + andl (idx, 0x3); + jcc(Assembler::zero, L_post_third_loop_done); + + Label L_check_1; + subl(idx, 2); + jcc(Assembler::negative, L_check_1); + + movq(yz_idx1, Address(y, idx, Address::times_4, 0)); + rorxq(yz_idx1, yz_idx1, 32); + mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3 + movq(yz_idx2, Address(z, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + add2_with_carry(tmp4, tmp3, carry, yz_idx2); + + movl(Address(z, idx, Address::times_4, 4), tmp3); + shrq(tmp3, 32); + movl(Address(z, idx, Address::times_4, 0), tmp3); + movq(carry, tmp4); + + bind (L_check_1); + addl (idx, 0x2); + andl (idx, 0x1); + subl(idx, 1); + jcc(Assembler::negative, L_post_third_loop_done); + movl(tmp4, Address(y, idx, Address::times_4, 0)); + mulxq(carry2, tmp3, tmp4); // tmp4 * rdx -> carry2:tmp3 + movl(tmp4, Address(z, idx, Address::times_4, 0)); + + add2_with_carry(carry2, tmp3, tmp4, carry); + + movl(Address(z, idx, Address::times_4, 0), tmp3); + shrq(tmp3, 32); + + shlq(carry2, 32); + orq(tmp3, carry2); + movq(carry, tmp3); + + bind(L_post_third_loop_done); +} + +/** + * Code for BigInteger::multiplyToLen() instrinsic. + * + * rdi: x + * rax: xlen + * rsi: y + * rcx: ylen + * r8: z + * r11: zlen + * r12: tmp1 + * r13: tmp2 + * r14: tmp3 + * r15: tmp4 + * rbx: tmp5 + * + */ +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { + ShortBranchVerifier sbv(this); + assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx); + + push(tmp1); + push(tmp2); + push(tmp3); + push(tmp4); + push(tmp5); + + push(xlen); + push(zlen); + + const Register idx = tmp1; + const Register kdx = tmp2; + const Register xstart = tmp3; + + const Register y_idx = tmp4; + const Register carry = tmp5; + const Register product = xlen; + const Register x_xstart = zlen; // reuse register + + // First Loop. + // + // final static long LONG_MASK = 0xffffffffL; + // int xstart = xlen - 1; + // int ystart = ylen - 1; + // long carry = 0; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry; + // z[kdx] = (int)product; + // carry = product >>> 32; + // } + // z[xstart] = (int)carry; + // + + movl(idx, ylen); // idx = ylen; + movl(kdx, zlen); // kdx = xlen+ylen; + xorq(carry, carry); // carry = 0; + + Label L_done; + + movl(xstart, xlen); + decrementl(xstart); + jcc(Assembler::negative, L_done); + + multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + + Label L_second_loop; + testl(kdx, kdx); + jcc(Assembler::zero, L_second_loop); + + Label L_carry; + subl(kdx, 1); + jcc(Assembler::zero, L_carry); + + movl(Address(z, kdx, Address::times_4, 0), carry); + shrq(carry, 32); + subl(kdx, 1); + + bind(L_carry); + movl(Address(z, kdx, Address::times_4, 0), carry); + + // Second and third (nested) loops. + // + // for (int i = xstart-1; i >= 0; i--) { // Second loop + // carry = 0; + // for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop + // long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) + + // (z[k] & LONG_MASK) + carry; + // z[k] = (int)product; + // carry = product >>> 32; + // } + // z[i] = (int)carry; + // } + // + // i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = rdx + + const Register jdx = tmp1; + + bind(L_second_loop); + xorl(carry, carry); // carry = 0; + movl(jdx, ylen); // j = ystart+1 + + subl(xstart, 1); // i = xstart-1; + jcc(Assembler::negative, L_done); + + push (z); + + Label L_last_x; + lea(z, Address(z, xstart, Address::times_4, 4)); // z = z + k - j + subl(xstart, 1); // i = xstart-1; + jcc(Assembler::negative, L_last_x); + + if (UseBMI2Instructions) { + movq(rdx, Address(x, xstart, Address::times_4, 0)); + rorxq(rdx, rdx, 32); // convert big-endian to little-endian + } else { + movq(x_xstart, Address(x, xstart, Address::times_4, 0)); + rorq(x_xstart, 32); // convert big-endian to little-endian + } + + Label L_third_loop_prologue; + bind(L_third_loop_prologue); + + push (x); + push (xstart); + push (ylen); + + + if (UseBMI2Instructions) { + multiply_128_x_128_bmi2_loop(y, z, carry, x, jdx, ylen, product, tmp2, x_xstart, tmp3, tmp4); + } else { // !UseBMI2Instructions + multiply_128_x_128_loop(x_xstart, y, z, y_idx, jdx, ylen, carry, product, x); + } + + pop(ylen); + pop(xlen); + pop(x); + pop(z); + + movl(tmp3, xlen); + addl(tmp3, 1); + movl(Address(z, tmp3, Address::times_4, 0), carry); + subl(tmp3, 1); + jccb(Assembler::negative, L_done); + + shrq(carry, 32); + movl(Address(z, tmp3, Address::times_4, 0), carry); + jmp(L_second_loop); + + // Next infrequent code is moved outside loops. + bind(L_last_x); + if (UseBMI2Instructions) { + movl(rdx, Address(x, 0)); + } else { + movl(x_xstart, Address(x, 0)); + } + jmp(L_third_loop_prologue); + + bind(L_done); + + pop(zlen); + pop(xlen); + + pop(tmp5); + pop(tmp4); + pop(tmp3); + pop(tmp2); + pop(tmp1); +} +#endif + /** * Emits code to update CRC-32 with a byte value according to constants in table * diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 3b3073e633a..69c9e8aa360 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1221,6 +1221,28 @@ public: XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3, XMMRegister tmp4, Register tmp5, Register result); +#ifdef _LP64 + void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2); + void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_add_128_x_128(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, + Register carry, Register product, int offset); + void multiply_128_x_128_bmi2_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4); + void multiply_128_x_128_loop(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, Register jdx, + Register carry, Register product, + Register carry2); + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); +#endif + // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. void update_byte_crc32(Register crc, Register val, Register table); void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 0adb0d31e72..0000146f535 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -3677,6 +3677,70 @@ class StubGenerator: public StubCodeGenerator { return start; } + + /** + * Arguments: + * + * Input: + * c_rarg0 - x address + * c_rarg1 - x length + * c_rarg2 - y address + * c_rarg3 - y lenth + * not Win64 + * c_rarg4 - z address + * c_rarg5 - z length + * Win64 + * rsp+40 - z address + * rsp+48 - z length + */ + address generate_multiplyToLen() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + + address start = __ pc(); + // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) + // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register x = rdi; + const Register xlen = rax; + const Register y = rsi; + const Register ylen = rcx; + const Register z = r8; + const Register zlen = r11; + + // Next registers will be saved on stack in multiply_to_len(). + const Register tmp1 = r12; + const Register tmp2 = r13; + const Register tmp3 = r14; + const Register tmp4 = r15; + const Register tmp5 = rbx; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + +#ifndef _WIN64 + __ movptr(zlen, r9); // Save r9 in r11 - zlen +#endif + setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx + // ylen => rcx, z => r8, zlen => r11 + // r9 and r10 may be used to save non-volatile registers +#ifdef _WIN64 + // last 2 arguments (#4, #5) are on stack on Win64 + __ movptr(z, Address(rsp, 6 * wordSize)); + __ movptr(zlen, Address(rsp, 7 * wordSize)); +#endif + + __ movptr(xlen, rsi); + __ movptr(y, rdx); + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5); + + restore_arg_regs(); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } + #undef __ #define __ masm-> @@ -3917,6 +3981,11 @@ class StubGenerator: public StubCodeGenerator { generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry, &StubRoutines::_safefetchN_fault_pc, &StubRoutines::_safefetchN_continuation_pc); +#ifdef COMPILER2 + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } +#endif } public: diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 73e286a53a0..e73f93c705f 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -485,7 +485,7 @@ void VM_Version::get_processor_features() { } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -514,7 +514,8 @@ void VM_Version::get_processor_features() { (supports_tscinv_bit() ? ", tscinvbit": ""), (supports_tscinv() ? ", tscinv": ""), (supports_bmi1() ? ", bmi1" : ""), - (supports_bmi2() ? ", bmi2" : "")); + (supports_bmi2() ? ", bmi2" : ""), + (supports_adx() ? ", adx" : "")); _features_str = os::strdup(buf); // UseSSE is set to the smaller of what hardware supports and what @@ -566,7 +567,7 @@ void VM_Version::get_processor_features() { } } else if (UseCRC32Intrinsics) { if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) - warning("CRC32 Intrinsics requires AVX and CLMUL instructions (not available on this CPU)"); + warning("CRC32 Intrinsics requires CLMUL instructions (not available on this CPU)"); FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } @@ -689,7 +690,20 @@ void VM_Version::get_processor_features() { } #endif } + +#ifdef _LP64 + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + UseMultiplyToLenIntrinsic = true; + } +#else + if (UseMultiplyToLenIntrinsic) { + if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + warning("multiplyToLen intrinsic is not available in 32-bit VM"); + } + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); + } #endif +#endif // COMPILER2 // On new cpus instructions which update whole XMM register should be used // to prevent partial register stall due to dependencies on high half. @@ -832,6 +846,9 @@ void VM_Version::get_processor_features() { } } } + if(FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { + AllocatePrefetchInstr = 3; + } } // Use count leading zeros count instruction if available. @@ -844,25 +861,37 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); } - if (supports_bmi1()) { - if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { - UseBMI1Instructions = true; - } - } else if (UseBMI1Instructions) { - warning("BMI1 instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseBMI1Instructions, false); - } - // Use count trailing zeros instruction if available if (supports_bmi1()) { + // tzcnt does not require VEX prefix if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { - UseCountTrailingZerosInstruction = UseBMI1Instructions; + UseCountTrailingZerosInstruction = true; } } else if (UseCountTrailingZerosInstruction) { warning("tzcnt instruction is not available on this CPU"); FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); } + // BMI instructions use an encoding with VEX prefix. + // VEX prefix is generated only when AVX > 0. + if (supports_bmi1() && supports_avx()) { + if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { + UseBMI1Instructions = true; + } + } else if (UseBMI1Instructions) { + warning("BMI1 instructions are not available on this CPU (AVX is also required)"); + FLAG_SET_DEFAULT(UseBMI1Instructions, false); + } + + if (supports_bmi2() && supports_avx()) { + if (FLAG_IS_DEFAULT(UseBMI2Instructions)) { + UseBMI2Instructions = true; + } + } else if (UseBMI2Instructions) { + warning("BMI2 instructions are not available on this CPU (AVX is also required)"); + FLAG_SET_DEFAULT(UseBMI2Instructions, false); + } + // Use population count instruction if available. if (supports_popcnt()) { if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 3de7ae4a077..17c34cd525a 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -209,7 +209,9 @@ public: erms : 1, : 1, rtm : 1, - : 20; + : 7, + adx : 1, + : 12; } bits; }; @@ -260,7 +262,8 @@ protected: CPU_CLMUL = (1 << 21), // carryless multiply for CRC CPU_BMI1 = (1 << 22), CPU_BMI2 = (1 << 23), - CPU_RTM = (1 << 24) // Restricted Transactional Memory instructions + CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions + CPU_ADX = (1 << 25) } cpuFeatureFlags; enum { @@ -465,10 +468,16 @@ protected: } // Intel features. if(is_intel()) { + if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) + result |= CPU_ADX; if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) result |= CPU_BMI2; if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) result |= CPU_LZCNT; + // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw + if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + result |= CPU_3DNOW_PREFETCH; + } } return result; @@ -625,6 +634,7 @@ public: static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } + static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; } // Intel features static bool is_intel_family_core() { return is_intel() && extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 51e9f866cf2..4f54ad94a6a 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -1678,14 +1678,9 @@ void os::print_dll_info(outputStream *st) { dlclose(handle); #elif defined(__APPLE__) - uint32_t count; - uint32_t i; - - count = _dyld_image_count(); - for (i = 1; i < count; i++) { - const char *name = _dyld_get_image_name(i); - intptr_t slide = _dyld_get_image_vmaddr_slide(i); - st->print_cr(PTR_FORMAT " \t%s", slide, name); + for (uint32_t i = 1; i < _dyld_image_count(); i++) { + st->print_cr(PTR_FORMAT " \t%s", _dyld_get_image_header(i), + _dyld_get_image_name(i)); } #else st->print_cr("Error: Cannot print dynamic libraries."); diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 085330a6444..025880fa71a 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -134,6 +134,10 @@ CodeBuffer::~CodeBuffer() { // free any overflow storage delete _overflow_arena; + // Claim is that stack allocation ensures resources are cleaned up. + // This is resource clean up, let's hope that all were properly copied out. + free_strings(); + #ifdef ASSERT // Save allocation type to execute assert in ~ResourceObj() // which is called after this destructor. @@ -705,7 +709,7 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { relocate_code_to(&dest); // transfer strings and comments from buffer to blob - dest_blob->set_strings(_strings); + dest_blob->set_strings(_code_strings); // Done moving code bytes; were they the right size? assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); @@ -1005,11 +1009,11 @@ void CodeSection::decode() { void CodeBuffer::block_comment(intptr_t offset, const char * comment) { - _strings.add_comment(offset, comment); + _code_strings.add_comment(offset, comment); } const char* CodeBuffer::code_string(const char* str) { - return _strings.add_string(str); + return _code_strings.add_string(str); } class CodeString: public CHeapObj { @@ -1075,6 +1079,7 @@ CodeString* CodeStrings::find_last(intptr_t offset) const { } void CodeStrings::add_comment(intptr_t offset, const char * comment) { + check_valid(); CodeString* c = new CodeString(comment, offset); CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset); @@ -1090,11 +1095,32 @@ void CodeStrings::add_comment(intptr_t offset, const char * comment) { } void CodeStrings::assign(CodeStrings& other) { + other.check_valid(); + // Cannot do following because CodeStrings constructor is not alway run! + assert(is_null(), "Cannot assign onto non-empty CodeStrings"); _strings = other._strings; + other.set_null_and_invalidate(); +} + +// Deep copy of CodeStrings for consistent memory management. +// Only used for actual disassembly so this is cheaper than reference counting +// for the "normal" fastdebug case. +void CodeStrings::copy(CodeStrings& other) { + other.check_valid(); + check_valid(); + assert(is_null(), "Cannot copy onto non-empty CodeStrings"); + CodeString* n = other._strings; + CodeString** ps = &_strings; + while (n != NULL) { + *ps = new CodeString(n->string(),n->offset()); + ps = &((*ps)->_next); + n = n->next(); + } } void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const { - if (_strings != NULL) { + check_valid(); + if (_strings != NULL) { CodeString* c = find(offset); while (c && c->offset() == offset) { stream->bol(); @@ -1105,7 +1131,7 @@ void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) con } } - +// Also sets isNull() void CodeStrings::free() { CodeString* n = _strings; while (n) { @@ -1115,10 +1141,11 @@ void CodeStrings::free() { delete n; n = p; } - _strings = NULL; + set_null_and_invalidate(); } const char* CodeStrings::add_string(const char * string) { + check_valid(); CodeString* s = new CodeString(string); s->set_next(_strings); _strings = s; diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 5572a39af7d..023360ee67c 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -27,6 +27,7 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" +#include "utilities/debug.hpp" class CodeStrings; class PhaseCFG; @@ -245,15 +246,39 @@ class CodeStrings VALUE_OBJ_CLASS_SPEC { private: #ifndef PRODUCT CodeString* _strings; +#ifdef ASSERT + // Becomes true after copy-out, forbids further use. + bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env +#endif #endif CodeString* find(intptr_t offset) const; CodeString* find_last(intptr_t offset) const; + void set_null_and_invalidate() { +#ifndef PRODUCT + _strings = NULL; +#ifdef ASSERT + _defunct = true; +#endif +#endif + } + public: CodeStrings() { #ifndef PRODUCT _strings = NULL; +#ifdef ASSERT + _defunct = false; +#endif +#endif + } + + bool is_null() { +#ifdef ASSERT + return _strings == NULL; +#else + return true; #endif } @@ -261,8 +286,17 @@ public: void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN; + // MOVE strings from other to this; invalidate other. void assign(CodeStrings& other) PRODUCT_RETURN; + // COPY strings from other to this; leave other valid. + void copy(CodeStrings& other) PRODUCT_RETURN; void free() PRODUCT_RETURN; + // Guarantee that _strings are used at most once; assign invalidates a buffer. + inline void check_valid() const { +#ifdef ASSERT + assert(!_defunct, "Use of invalid CodeStrings"); +#endif + } }; // A CodeBuffer describes a memory space into which assembly @@ -330,7 +364,7 @@ class CodeBuffer: public StackObj { csize_t _total_size; // size in bytes of combined memory buffer OopRecorder* _oop_recorder; - CodeStrings _strings; + CodeStrings _code_strings; OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; @@ -531,7 +565,13 @@ class CodeBuffer: public StackObj { void initialize_oop_recorder(OopRecorder* r); OopRecorder* oop_recorder() const { return _oop_recorder; } - CodeStrings& strings() { return _strings; } + CodeStrings& strings() { return _code_strings; } + + void free_strings() { + if (!_code_strings.is_null()) { + _code_strings.free(); // sets _strings Null as a side-effect. + } + } // Code generation void relocate(address at, RelocationHolder const& rspec, int format = 0) { diff --git a/hotspot/src/share/vm/asm/register.hpp b/hotspot/src/share/vm/asm/register.hpp index d9918517dd9..7244b9f5dec 100644 --- a/hotspot/src/share/vm/asm/register.hpp +++ b/hotspot/src/share/vm/asm/register.hpp @@ -275,4 +275,101 @@ inline void assert_different_registers( ); } +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j + && c != d && c != e && c != f && c != g && c != h && c != i && c != j + && d != e && d != f && d != g && d != h && d != i && d != j + && e != f && e != g && e != h && e != i && e != j + && f != g && f != h && f != i && f != j + && g != h && g != i && g != j + && h != i && h != j + && i != j, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j)) + ); +} + +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j, + AbstractRegister k +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k + && d != e && d != f && d != g && d != h && d != i && d != j && d !=k + && e != f && e != g && e != h && e != i && e != j && e !=k + && f != g && f != h && f != i && f != j && f !=k + && g != h && g != i && g != j && g !=k + && h != i && h != j && h !=k + && i != j && i !=k + && j !=k, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k)) + ); +} + +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j, + AbstractRegister k, + AbstractRegister l +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k && a !=l + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k && b !=l + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k && c !=l + && d != e && d != f && d != g && d != h && d != i && d != j && d !=k && d !=l + && e != f && e != g && e != h && e != i && e != j && e !=k && e !=l + && f != g && f != h && f != i && f != j && f !=k && f !=l + && g != h && g != i && g != j && g !=k && g !=l + && h != i && h != j && h !=k && h !=l + && i != j && i !=k && i !=l + && j !=k && j !=l + && k !=l, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT + ", l=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l)) + ); +} + #endif // SHARE_VM_ASM_REGISTER_HPP diff --git a/hotspot/src/share/vm/ci/ciArrayKlass.hpp b/hotspot/src/share/vm/ci/ciArrayKlass.hpp index da749cdc61a..e5c74e8865c 100644 --- a/hotspot/src/share/vm/ci/ciArrayKlass.hpp +++ b/hotspot/src/share/vm/ci/ciArrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -52,11 +52,6 @@ public: ciType* base_element_type(); // JLS calls this the "element type" bool is_leaf_type(); // No subtypes of this array type. - ciInstance* component_mirror() { - // This is a real field in ArrayKlass, but we derive it from element_type. - return element_type()->java_mirror(); - } - // What kind of vmObject is this? bool is_array_klass() const { return true; } bool is_java_klass() const { return true; } diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 2e4ef93a946..27400cd8f8b 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -1101,6 +1101,22 @@ bool ciMethod::has_option(const char* option) { return CompilerOracle::has_option_string(mh, option); } +// ------------------------------------------------------------------ +// ciMethod::has_option_value +// +template +bool ciMethod::has_option_value(const char* option, T& value) { + check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, get_Method()); + return CompilerOracle::has_option_value(mh, option, value); +} +// Explicit instantiation for all OptionTypes supported. +template bool ciMethod::has_option_value(const char* option, intx& value); +template bool ciMethod::has_option_value(const char* option, uintx& value); +template bool ciMethod::has_option_value(const char* option, bool& value); +template bool ciMethod::has_option_value(const char* option, ccstr& value); + // ------------------------------------------------------------------ // ciMethod::can_be_compiled // diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 2b9cf376991..c1641000f93 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -269,6 +269,8 @@ class ciMethod : public ciMetadata { bool should_print_assembly(); bool break_at_execute(); bool has_option(const char *option); + template + bool has_option_value(const char* option, T& value); bool can_be_compiled(); bool can_be_osr_compiled(int entry_bci); void set_not_compilable(const char* reason = NULL); diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp index aa157e15283..08ce7963963 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.cpp +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp @@ -81,19 +81,38 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) { void ciMethodData::load_extra_data() { MethodData* mdo = get_MethodData(); + MutexLocker(mdo->extra_data_lock()); + // speculative trap entries also hold a pointer to a Method so need to be translated DataLayout* dp_src = mdo->extra_data_base(); - DataLayout* end_src = mdo->extra_data_limit(); + DataLayout* end_src = mdo->args_data_limit(); DataLayout* dp_dst = extra_data_base(); for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) { assert(dp_src < end_src, "moved past end of extra data"); - // New traps in the MDO can be added as we translate the copy so - // look at the entries in the copy. - switch(dp_dst->tag()) { + assert(((intptr_t)dp_dst) - ((intptr_t)extra_data_base()) == ((intptr_t)dp_src) - ((intptr_t)mdo->extra_data_base()), "source and destination don't match"); + + // New traps in the MDO may have been added since we copied the + // data (concurrent deoptimizations before we acquired + // extra_data_lock above) or can be removed (a safepoint may occur + // in the translate_from call below) as we translate the copy: + // update the copy as we go. + int tag = dp_src->tag(); + if (tag != DataLayout::arg_info_data_tag) { + memcpy(dp_dst, dp_src, ((intptr_t)MethodData::next_extra(dp_src)) - ((intptr_t)dp_src)); + } + + switch(tag) { case DataLayout::speculative_trap_data_tag: { ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst); SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src); + data_dst->translate_from(data_src); + +#ifdef ASSERT + SpeculativeTrapData* data_src2 = new SpeculativeTrapData(dp_src); + assert(data_src2->method() == data_src->method() && data_src2->bci() == data_src->bci(), "entries changed while translating"); +#endif + break; } case DataLayout::bit_data_tag: @@ -244,8 +263,8 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) { } ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) { - DataLayout* dp = data_layout_at(data_size()); - DataLayout* end = data_layout_at(data_size() + extra_data_size()); + DataLayout* dp = extra_data_base(); + DataLayout* end = args_data_limit(); two_free_slots = false; for (;dp < end; dp = MethodData::next_extra(dp)) { switch(dp->tag()) { @@ -492,8 +511,8 @@ ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_ ciArgInfoData *ciMethodData::arg_info() const { // Should be last, have to skip all traps. - DataLayout* dp = data_layout_at(data_size()); - DataLayout* end = data_layout_at(data_size() + extra_data_size()); + DataLayout* dp = extra_data_base(); + DataLayout* end = args_data_limit(); for (; dp < end; dp = MethodData::next_extra(dp)) { if (dp->tag() == DataLayout::arg_info_data_tag) return new ciArgInfoData(dp); @@ -535,8 +554,8 @@ template void ciMethodData::dump_replay_data_call_type_helper(outputStr } void ciMethodData::dump_replay_data_extra_data_helper(outputStream* out, int round, int& count) { - DataLayout* dp = data_layout_at(data_size()); - DataLayout* end = data_layout_at(data_size() + extra_data_size()); + DataLayout* dp = extra_data_base(); + DataLayout* end = args_data_limit(); for (;dp < end; dp = MethodData::next_extra(dp)) { switch(dp->tag()) { @@ -653,8 +672,8 @@ void ciMethodData::print_data_on(outputStream* st) { data->print_data_on(st); } st->print_cr("--- Extra data:"); - DataLayout* dp = data_layout_at(data_size()); - DataLayout* end = data_layout_at(data_size() + extra_data_size()); + DataLayout* dp = extra_data_base(); + DataLayout* end = args_data_limit(); for (;; dp = MethodData::next_extra(dp)) { assert(dp < end, "moved past end of extra data"); switch (dp->tag()) { diff --git a/hotspot/src/share/vm/ci/ciMethodData.hpp b/hotspot/src/share/vm/ci/ciMethodData.hpp index ec88c5dd26c..b96f479682d 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.hpp +++ b/hotspot/src/share/vm/ci/ciMethodData.hpp @@ -410,6 +410,9 @@ private: // Area dedicated to parameters. NULL if no parameter profiling for // this method. DataLayout* _parameters; + int parameters_size() const { + return _parameters == NULL ? 0 : parameters_type_data()->size_in_bytes(); + } ciMethodData(MethodData* md); ciMethodData(); @@ -461,9 +464,6 @@ private: address data_base() const { return (address) _data; } - DataLayout* limit_data_position() const { - return (DataLayout*)((address)data_base() + _data_size); - } void load_extra_data(); ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots); @@ -524,7 +524,9 @@ public: ciProfileData* next_data(ciProfileData* current); bool is_valid(ciProfileData* current) { return current != NULL; } - DataLayout* extra_data_base() const { return limit_data_position(); } + DataLayout* extra_data_base() const { return data_layout_at(data_size()); } + DataLayout* args_data_limit() const { return data_layout_at(data_size() + extra_data_size() - + parameters_size()); } // Get the data at an arbitrary bci, or NULL if there is none. If m // is not NULL look for a SpeculativeTrapData if any first. diff --git a/hotspot/src/share/vm/classfile/classFileStream.cpp b/hotspot/src/share/vm/classfile/classFileStream.cpp index 27479acb64a..4cd811f88b3 100644 --- a/hotspot/src/share/vm/classfile/classFileStream.cpp +++ b/hotspot/src/share/vm/classfile/classFileStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -30,7 +30,7 @@ void ClassFileStream::truncated_file_error(TRAPS) { THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file"); } -ClassFileStream::ClassFileStream(u1* buffer, int length, char* source) { +ClassFileStream::ClassFileStream(u1* buffer, int length, const char* source) { _buffer_start = buffer; _buffer_end = buffer + length; _current = buffer; diff --git a/hotspot/src/share/vm/classfile/classFileStream.hpp b/hotspot/src/share/vm/classfile/classFileStream.hpp index de392e7fa13..df44070252e 100644 --- a/hotspot/src/share/vm/classfile/classFileStream.hpp +++ b/hotspot/src/share/vm/classfile/classFileStream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -39,20 +39,20 @@ class ClassFileStream: public ResourceObj { u1* _buffer_start; // Buffer bottom u1* _buffer_end; // Buffer top (one past last element) u1* _current; // Current buffer position - char* _source; // Source of stream (directory name, ZIP/JAR archive name) + const char* _source; // Source of stream (directory name, ZIP/JAR archive name) bool _need_verify; // True if verification is on for the class file void truncated_file_error(TRAPS); public: // Constructor - ClassFileStream(u1* buffer, int length, char* source); + ClassFileStream(u1* buffer, int length, const char* source); // Buffer access u1* buffer() const { return _buffer_start; } int length() const { return _buffer_end - _buffer_start; } u1* current() const { return _current; } void set_current(u1* pos) { _current = pos; } - char* source() const { return _source; } + const char* source() const { return _source; } void set_verify(bool flag) { _need_verify = flag; } void check_truncated_file(bool b, TRAPS) { diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 19aec02c26f..5eab1812576 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -189,9 +189,10 @@ bool ClassPathEntry::is_lazy() { return false; } -ClassPathDirEntry::ClassPathDirEntry(char* dir) : ClassPathEntry() { - _dir = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass); - strcpy(_dir, dir); +ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() { + char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass); + strcpy(copy, dir); + _dir = copy; } @@ -235,8 +236,9 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() { _zip = zip; - _zip_name = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass); - strcpy(_zip_name, zip_name); + char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass); + strcpy(copy, zip_name); + _zip_name = copy; } ClassPathZipEntry::~ClassPathZipEntry() { @@ -304,7 +306,7 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi } } -LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() { +LazyClassPathEntry::LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() { _path = os::strdup_check_oom(path); _st = *st; _meta_index = NULL; @@ -314,7 +316,7 @@ LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool t } LazyClassPathEntry::~LazyClassPathEntry() { - os::free(_path); + os::free((void*)_path); } bool LazyClassPathEntry::is_jar_file() { @@ -563,17 +565,19 @@ void ClassLoader::check_shared_classpath(const char *path) { void ClassLoader::setup_bootstrap_search_path() { assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); - char* sys_class_path = os::strdup_check_oom(Arguments::get_sysclasspath()); - if (!PrintSharedArchiveAndExit) { + const char* sys_class_path = Arguments::get_sysclasspath(); + if (PrintSharedArchiveAndExit) { + // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily + // the same as the bootcp of the shared archive. + } else { trace_class_path("[Bootstrap loader class path=", sys_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) { - _shared_paths_misc_info->add_boot_classpath(Arguments::get_sysclasspath()); + _shared_paths_misc_info->add_boot_classpath(sys_class_path); } #endif setup_search_path(sys_class_path); - os::free(sys_class_path); } #if INCLUDE_CDS @@ -593,7 +597,7 @@ bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) { } #endif -void ClassLoader::setup_search_path(char *class_path) { +void ClassLoader::setup_search_path(const char *class_path) { int offset = 0; int len = (int)strlen(class_path); int end = 0; @@ -620,7 +624,7 @@ void ClassLoader::setup_search_path(char *class_path) { } } -ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, +ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st, bool lazy, bool throw_exception, TRAPS) { JavaThread* thread = JavaThread::current(); if (lazy) { @@ -687,11 +691,8 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { struct stat st; if (os::stat(path, &st) == 0) { if ((st.st_mode & S_IFREG) == S_IFREG) { - char orig_path[JVM_MAXPATHLEN]; char canonical_path[JVM_MAXPATHLEN]; - - strcpy(orig_path, path); - if (get_canonical_path(orig_path, canonical_path, JVM_MAXPATHLEN)) { + if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { char* error_msg = NULL; jzfile* zip; { @@ -737,7 +738,7 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) { } // Returns true IFF the file/dir exists and the entry was successfully created. -bool ClassLoader::update_class_path_entry_list(char *path, +bool ClassLoader::update_class_path_entry_list(const char *path, bool check_for_duplicates, bool throw_exception) { struct stat st; @@ -762,8 +763,8 @@ bool ClassLoader::update_class_path_entry_list(char *path, if (DumpSharedSpaces) { _shared_paths_misc_info->add_nonexist_path(path); } - return false; #endif + return false; } } @@ -1269,11 +1270,17 @@ void classLoader_init() { } -bool ClassLoader::get_canonical_path(char* orig, char* out, int len) { +bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) { assert(orig != NULL && out != NULL && len > 0, "bad arguments"); if (CanonicalizeEntry != NULL) { - JNIEnv* env = JavaThread::current()->jni_environment(); - if ((CanonicalizeEntry)(env, os::native_path(orig), out, len) < 0) { + JavaThread* THREAD = JavaThread::current(); + JNIEnv* env = THREAD->jni_environment(); + ResourceMark rm(THREAD); + + // os::native_path writes into orig_copy + char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(orig)+1); + strcpy(orig_copy, orig); + if ((CanonicalizeEntry)(env, os::native_path(orig_copy), out, len) < 0) { return false; } } else { diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index bd1fe24b6e2..8f0bf77ac37 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -72,11 +72,11 @@ class ClassPathEntry: public CHeapObj { class ClassPathDirEntry: public ClassPathEntry { private: - char* _dir; // Name of directory + const char* _dir; // Name of directory public: bool is_jar_file() { return false; } const char* name() { return _dir; } - ClassPathDirEntry(char* dir); + ClassPathDirEntry(const char* dir); ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) @@ -100,8 +100,8 @@ typedef struct { class ClassPathZipEntry: public ClassPathEntry { private: - jzfile* _zip; // The zip archive - char* _zip_name; // Name of zip archive + jzfile* _zip; // The zip archive + const char* _zip_name; // Name of zip archive public: bool is_jar_file() { return true; } const char* name() { return _zip_name; } @@ -119,7 +119,7 @@ class ClassPathZipEntry: public ClassPathEntry { // For lazier loading of boot class path entries class LazyClassPathEntry: public ClassPathEntry { private: - char* _path; // dir or file + const char* _path; // dir or file struct stat _st; MetaIndex* _meta_index; bool _has_error; @@ -129,7 +129,7 @@ class LazyClassPathEntry: public ClassPathEntry { public: bool is_jar_file(); const char* name() { return _path; } - LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception); + LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception); virtual ~LazyClassPathEntry(); u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS); @@ -216,17 +216,17 @@ class ClassLoader: AllStatic { static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index); static void setup_bootstrap_search_path(); - static void setup_search_path(char *class_path); + static void setup_search_path(const char *class_path); static void load_zip_library(); - static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st, + static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, bool lazy, bool throw_exception, TRAPS); // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library - static bool get_canonical_path(char* orig, char* out, int len); + static bool get_canonical_path(const char* orig, char* out, int len); public: - static bool update_class_path_entry_list(char *path, + static bool update_class_path_entry_list(const char *path, bool check_for_duplicates, bool throw_exception=true); static void print_bootclasspath(); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 1b2bd8a26b1..3b2cd141b0c 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -332,27 +332,6 @@ void ClassLoaderData::unload() { } } -#ifdef ASSERT -class AllAliveClosure : public OopClosure { - BoolObjectClosure* _is_alive_closure; - bool _found_dead; - public: - AllAliveClosure(BoolObjectClosure* is_alive_closure) : _is_alive_closure(is_alive_closure), _found_dead(false) {} - template void do_oop_work(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (!_is_alive_closure->do_object_b(obj)) { - _found_dead = true; - } - } - } - void do_oop(oop* p) { do_oop_work(p); } - void do_oop(narrowOop* p) { do_oop_work(p); } - bool found_dead() { return _found_dead; } -}; -#endif - oop ClassLoaderData::keep_alive_object() const { assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); return is_anonymous() ? _klasses->java_mirror() : class_loader(); @@ -362,15 +341,6 @@ bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const { bool alive = keep_alive() // null class loader and incomplete anonymous klasses. || is_alive_closure->do_object_b(keep_alive_object()); -#ifdef ASSERT - if (alive) { - AllAliveClosure all_alive_closure(is_alive_closure); - KlassToOopClosure klass_closure(&all_alive_closure); - const_cast(this)->oops_do(&all_alive_closure, &klass_closure, false); - assert(!all_alive_closure.found_dead(), err_msg("Found dead oop in alive cld: " PTR_FORMAT, p2i(this))); - } -#endif - return alive; } diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp index ed3eda08e9a..ee2e0ec6851 100644 --- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp @@ -59,8 +59,8 @@ public: }; - static void add_class_path_entry(char* path, bool check_for_duplicates, - ClassPathEntry* new_entry) { + static void add_class_path_entry(const char* path, bool check_for_duplicates, + ClassPathEntry* new_entry) { ClassLoader::add_to_list(new_entry); } static void setup_search_paths() {} diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index cfd3a68356c..5b5e20e610c 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -620,7 +620,6 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, // Two-way link between the array klass and its component mirror: // (array_klass) k -> mirror -> component_mirror -> array_klass -> k set_component_mirror(mirror(), comp_mirror()); - ArrayKlass::cast(k())->set_component_mirror(comp_mirror()); set_array_klass(comp_mirror(), k()); } else { assert(k->oop_is_instance(), "Must be"); @@ -682,10 +681,9 @@ void java_lang_Class::set_protection_domain(oop java_class, oop pd) { } void java_lang_Class::set_component_mirror(oop java_class, oop comp_mirror) { - if (_component_mirror_offset != 0) { + assert(_component_mirror_offset != 0, "must be set"); java_class->obj_field_put(_component_mirror_offset, comp_mirror); } -} oop java_lang_Class::component_mirror(oop java_class) { assert(_component_mirror_offset != 0, "must be set"); return java_class->obj_field(_component_mirror_offset); @@ -875,22 +873,27 @@ void java_lang_Class::compute_offsets() { assert(!offsets_computed, "offsets should be initialized only once"); offsets_computed = true; - Klass* klass_oop = SystemDictionary::Class_klass(); + Klass* k = SystemDictionary::Class_klass(); // The classRedefinedCount field is only present starting in 1.5, // so don't go fatal. compute_optional_offset(classRedefinedCount_offset, - klass_oop, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature()); + k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature()); // Needs to be optional because the old build runs Queens during bootstrapping // and jdk8-9 doesn't have coordinated pushes yet. compute_optional_offset(_class_loader_offset, - klass_oop, vmSymbols::classLoader_name(), + k, vmSymbols::classLoader_name(), vmSymbols::classloader_signature()); - compute_optional_offset(_component_mirror_offset, - klass_oop, vmSymbols::componentType_name(), + compute_offset(_component_mirror_offset, + k, vmSymbols::componentType_name(), vmSymbols::class_signature()); + // Init lock is a C union with component_mirror. Only instanceKlass mirrors have + // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops + // GC treats them the same. + _init_lock_offset = _component_mirror_offset; + CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index aeafbfbf8b1..ef3e8ec78b0 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -222,7 +222,6 @@ class java_lang_String : AllStatic { macro(java_lang_Class, oop_size, int_signature, false) \ macro(java_lang_Class, static_oop_field_count, int_signature, false) \ macro(java_lang_Class, protection_domain, object_signature, false) \ - macro(java_lang_Class, init_lock, object_signature, false) \ macro(java_lang_Class, signers, object_signature, false) class java_lang_Class : AllStatic { diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp index c988abdf9da..79457a0e5e2 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -139,7 +139,7 @@ bool SharedPathsMiscInfo::check(jint type, const char* path) { if (timestamp != st.st_mtime) { return fail("Timestamp mismatch"); } - if (filesize != st.st_size) { + if (filesize != st.st_size) { return fail("File size mismatch"); } } diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index 78b09256218..3f52648310f 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -165,7 +165,7 @@ public: out->print("Expecting that %s does not exist", path); break; case REQUIRED: - out->print("Expecting that file %s must exist and not altered", path); + out->print("Expecting that file %s must exist and is not altered", path); break; default: ShouldNotReachHere(); diff --git a/hotspot/src/share/vm/classfile/stringTable.cpp b/hotspot/src/share/vm/classfile/stringTable.cpp index 46f4eba59cd..b12134a1252 100644 --- a/hotspot/src/share/vm/classfile/stringTable.cpp +++ b/hotspot/src/share/vm/classfile/stringTable.cpp @@ -109,7 +109,7 @@ oop StringTable::lookup(int index, jchar* name, } } // If the bucket size is too deep check if this hash code is insufficient. - if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { + if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } return NULL; diff --git a/hotspot/src/share/vm/classfile/stringTable.hpp b/hotspot/src/share/vm/classfile/stringTable.hpp index af6f909f200..e8f42834d07 100644 --- a/hotspot/src/share/vm/classfile/stringTable.hpp +++ b/hotspot/src/share/vm/classfile/stringTable.hpp @@ -28,7 +28,7 @@ #include "memory/allocation.inline.hpp" #include "utilities/hashtable.hpp" -class StringTable : public Hashtable { +class StringTable : public RehashableHashtable { friend class VMStructs; friend class Symbol; @@ -55,11 +55,11 @@ private: // in the range [start_idx, end_idx). static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); - StringTable() : Hashtable((int)StringTableSize, + StringTable() : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry)) {} StringTable(HashtableBucket* t, int number_of_entries) - : Hashtable((int)StringTableSize, sizeof (HashtableEntry), t, + : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry), t, number_of_entries) {} public: // The string table diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index d688235f1f5..ba9d2a00b25 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -201,7 +201,7 @@ Symbol* SymbolTable::lookup(int index, const char* name, } } // If the bucket size is too deep check if this hash code is insufficient. - if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { + if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } return NULL; diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index c5dd75b82ea..81f3c085a00 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -73,7 +73,7 @@ class TempNewSymbol : public StackObj { operator Symbol*() { return _temp; } }; -class SymbolTable : public Hashtable { +class SymbolTable : public RehashableHashtable { friend class VMStructs; friend class ClassFileParser; @@ -109,10 +109,10 @@ private: Symbol* lookup(int index, const char* name, int len, unsigned int hash); SymbolTable() - : Hashtable(SymbolTableSize, sizeof (HashtableEntry)) {} + : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry)) {} SymbolTable(HashtableBucket* t, int number_of_entries) - : Hashtable(SymbolTableSize, sizeof (HashtableEntry), t, + : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry), t, number_of_entries) {} // Arena for permanent symbols (null class loader) that are never unloaded diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index e794d93a778..6f865acd431 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1243,7 +1243,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, tty->print_cr("]"); } -#if INCLUDE_CDS if (DumpLoadedClassList != NULL && classlist_file->is_open()) { // Only dump the classes that can be stored into CDS archive if (SystemDictionaryShared::is_sharing_possible(loader_data)) { @@ -1252,7 +1251,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, classlist_file->flush(); } } -#endif // notify a class loaded from shared object ClassLoadingService::notify_class_loaded(InstanceKlass::cast(ik()), @@ -1260,7 +1258,7 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, } return ik; } -#endif +#endif // INCLUDE_CDS instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 50fe81e8d24..a4cf130d5c9 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -399,7 +399,6 @@ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ template(protection_domain_name, "protection_domain") \ - template(init_lock_name, "init_lock") \ template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ template(dependencies_name, "dependencies") \ @@ -747,8 +746,6 @@ do_name( isPrimitive_name, "isPrimitive") \ do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \ do_name( getSuperclass_name, "getSuperclass") \ - do_intrinsic(_getComponentType, java_lang_Class, getComponentType_name, void_class_signature, F_RN) \ - do_name( getComponentType_name, "getComponentType") \ \ do_intrinsic(_getClassAccessFlags, sun_reflect_Reflection, getClassAccessFlags_name, class_int_signature, F_SN) \ do_name( getClassAccessFlags_name, "getClassAccessFlags") \ @@ -788,6 +785,11 @@ do_name( encodeISOArray_name, "encodeISOArray") \ do_signature(encodeISOArray_signature, "([CI[BII)I") \ \ + do_class(java_math_BigInteger, "java/math/BigInteger") \ + do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_R) \ + do_name( multiplyToLen_name, "multiplyToLen") \ + do_signature(multiplyToLen_signature, "([II[II[I)[I") \ + \ /* java/lang/ref/Reference */ \ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ \ diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp index 710ca948ddc..0e71d2d4c64 100644 --- a/hotspot/src/share/vm/code/codeBlob.cpp +++ b/hotspot/src/share/vm/code/codeBlob.cpp @@ -238,6 +238,7 @@ void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw( void BufferBlob::free( BufferBlob *blob ) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + blob->flush(); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::free((CodeBlob*)blob); diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index 7cf3be645f2..851b390e1e7 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -168,48 +168,134 @@ bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) { } } +enum OptionType { + IntxType, + UintxType, + BoolType, + CcstrType, + UnknownType +}; -class MethodOptionMatcher: public MethodMatcher { - const char * option; - public: - MethodOptionMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, const char * opt, MethodMatcher* next): - MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next) { - option = os::strdup_check_oom(opt); +/* Methods to map real type names to OptionType */ +template +static OptionType get_type_for() { + return UnknownType; +}; + +template<> OptionType get_type_for() { + return IntxType; +} + +template<> OptionType get_type_for() { + return UintxType; +} + +template<> OptionType get_type_for() { + return BoolType; +} + +template<> OptionType get_type_for() { + return CcstrType; +} + +template +static const T copy_value(const T value) { + return value; +} + +template<> const ccstr copy_value(const ccstr value) { + return (const ccstr)os::strdup_check_oom(value); +} + +template +class TypedMethodOptionMatcher : public MethodMatcher { + const char* _option; + OptionType _type; + const T _value; + +public: + TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode, + Symbol* method_name, Mode method_mode, + Symbol* signature, const char* opt, + const T value, MethodMatcher* next) : + MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next), + _type(get_type_for()), _value(copy_value(value)) { + _option = os::strdup_check_oom(opt); } - virtual ~MethodOptionMatcher() { - os::free((void*)option); + ~TypedMethodOptionMatcher() { + os::free((void*)_option); } - bool match(methodHandle method, const char* opt) { - MethodOptionMatcher* current = this; + TypedMethodOptionMatcher* match(methodHandle method, const char* opt) { + TypedMethodOptionMatcher* current = this; while (current != NULL) { - current = (MethodOptionMatcher*)current->find(method); + current = (TypedMethodOptionMatcher*)current->find(method); if (current == NULL) { - return false; + return NULL; } - if (strcmp(current->option, opt) == 0) { - return true; + if (strcmp(current->_option, opt) == 0) { + return current; } current = current->next(); } - return false; + return NULL; } - MethodOptionMatcher* next() { - return (MethodOptionMatcher*)_next; + TypedMethodOptionMatcher* next() { + return (TypedMethodOptionMatcher*)_next; } - virtual void print() { + OptionType get_type(void) { + return _type; + }; + + T value() { return _value; } + + void print() { + ttyLocker ttyl; print_base(); - tty->print(" %s", option); + tty->print(" %s", _option); + tty->print(" "); tty->cr(); } }; +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" intx %s", _option); + tty->print(" = " INTX_FORMAT, _value); + tty->cr(); +}; +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" uintx %s", _option); + tty->print(" = " UINTX_FORMAT, _value); + tty->cr(); +}; + +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" bool %s", _option); + tty->print(" = %s", _value ? "true" : "false"); + tty->cr(); +}; + +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" const char* %s", _option); + tty->print(" = '%s'", _value); + tty->cr(); +}; // this must parallel the command_names below enum OracleCommand { @@ -264,23 +350,46 @@ static MethodMatcher* add_predicate(OracleCommand command, return lists[command]; } - - +template static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode, Symbol* method_name, MethodMatcher::Mode m_mode, Symbol* signature, - const char* option) { - lists[OptionCommand] = new MethodOptionMatcher(class_name, c_mode, method_name, m_mode, - signature, option, lists[OptionCommand]); + const char* option, + T value) { + lists[OptionCommand] = new TypedMethodOptionMatcher(class_name, c_mode, method_name, m_mode, + signature, option, value, lists[OptionCommand]); return lists[OptionCommand]; } - -bool CompilerOracle::has_option_string(methodHandle method, const char* option) { - return lists[OptionCommand] != NULL && - ((MethodOptionMatcher*)lists[OptionCommand])->match(method, option); +template +static bool get_option_value(methodHandle method, const char* option, T& value) { + TypedMethodOptionMatcher* m; + if (lists[OptionCommand] != NULL + && (m = ((TypedMethodOptionMatcher*)lists[OptionCommand])->match(method, option)) != NULL + && m->get_type() == get_type_for()) { + value = m->value(); + return true; + } else { + return false; + } } +bool CompilerOracle::has_option_string(methodHandle method, const char* option) { + bool value = false; + get_option_value(method, option, value); + return value; +} + +template +bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { + return ::get_option_value(method, option, value); +} + +// Explicit instantiation for all OptionTypes supported. +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, intx& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, uintx& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, bool& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, ccstr& value); bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { quietly = true; @@ -422,6 +531,94 @@ static bool scan_line(const char * line, +// Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. +// On failure, error_msg contains description for the first error. +// For future extensions: set error_msg on first error. +static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, + Symbol* c_name, MethodMatcher::Mode c_match, + Symbol* m_name, MethodMatcher::Mode m_match, + Symbol* signature, + char* errorbuf, const int buf_size) { + total_bytes_read = 0; + int bytes_read = 0; + char flag[256]; + + // Read flag name. + if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", flag, &bytes_read) == 1) { + line += bytes_read; + total_bytes_read += bytes_read; + + // Read value. + if (strcmp(type, "intx") == 0) { + intx value; + if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); + } + } else if (strcmp(type, "uintx") == 0) { + uintx value; + if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "ccstr") == 0) { + ResourceMark rm; + char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); + if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "ccstrlist") == 0) { + // Accumulates several strings into one. The internal type is ccstr. + ResourceMark rm; + char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); + char* next_value = value; + if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + line += bytes_read; + next_value += bytes_read; + char* end_value = next_value-1; + while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + line += bytes_read; + *end_value = ' '; // override '\0' + next_value += bytes_read; + end_value = next_value-1; + } + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "bool") == 0) { + char value[256]; + if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { + if (strcmp(value, "true") == 0) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true); + } else if (strcmp(value, "false") == 0) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Value cannot be read for flag %s of type %s", flag, type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Type %s not supported ", type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Flag name for type %s should be alphanumeric ", type); + } + return NULL; +} + void CompilerOracle::parse_from_line(char* line) { if (line[0] == '\0') return; if (line[0] == '#') return; @@ -451,8 +648,10 @@ void CompilerOracle::parse_from_line(char* line) { int bytes_read; OracleCommand command = parse_command_name(line, &bytes_read); line += bytes_read; + ResourceMark rm; if (command == UnknownCommand) { + ttyLocker ttyl; tty->print_cr("CompilerOracle: unrecognized line"); tty->print_cr(" \"%s\"", original_line); return; @@ -474,7 +673,7 @@ void CompilerOracle::parse_from_line(char* line) { char method_name[256]; char sig[1024]; char errorbuf[1024]; - const char* error_msg = NULL; + const char* error_msg = NULL; // description of first error that appears MethodMatcher* match = NULL; if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) { @@ -493,43 +692,77 @@ void CompilerOracle::parse_from_line(char* line) { } if (command == OptionCommand) { - // Look for trailing options to support - // ciMethod::has_option("string") to control features in the - // compiler. Multiple options may follow the method name. - char option[256]; + // Look for trailing options. + // + // Two types of trailing options are + // supported: + // + // (1) CompileCommand=option,Klass::method,flag + // (2) CompileCommand=option,Klass::method,type,flag,value + // + // Type (1) is used to support ciMethod::has_option("someflag") + // (i.e., to check if a flag "someflag" is enabled for a method). + // + // Type (2) is used to support options with a value. Values can have the + // the following types: intx, uintx, bool, ccstr, and ccstrlist. + // + // For future extensions: extend scan_flag_and_value() + char option[256]; // stores flag for Type (1) and type of Type (2) while (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { if (match != NULL && !_quiet) { // Print out the last match added + ttyLocker ttyl; tty->print("CompilerOracle: %s ", command_names[command]); match->print(); } - match = add_option_string(c_name, c_match, m_name, m_match, signature, option); line += bytes_read; - } + + if (strcmp(option, "intx") == 0 + || strcmp(option, "uintx") == 0 + || strcmp(option, "bool") == 0 + || strcmp(option, "ccstr") == 0 + || strcmp(option, "ccstrlist") == 0 + ) { + + // Type (2) option: parse flag name and value. + match = scan_flag_and_value(option, line, bytes_read, + c_name, c_match, m_name, m_match, signature, + errorbuf, sizeof(errorbuf)); + if (match == NULL) { + error_msg = errorbuf; + break; + } + line += bytes_read; + } else { + // Type (1) option + match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true); + } + } // while( } else { - bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - jio_snprintf(errorbuf, sizeof(errorbuf), " Unrecognized text after command: %s", line); - error_msg = errorbuf; - } else { - match = add_predicate(command, c_name, c_match, m_name, m_match, signature); - } + match = add_predicate(command, c_name, c_match, m_name, m_match, signature); } } - if (match != NULL) { - if (!_quiet) { - ResourceMark rm; - tty->print("CompilerOracle: %s ", command_names[command]); - match->print(); - } - } else { + ttyLocker ttyl; + if (error_msg != NULL) { + // an error has happened tty->print_cr("CompilerOracle: unrecognized line"); tty->print_cr(" \"%s\"", original_line); if (error_msg != NULL) { tty->print_cr("%s", error_msg); } + } else { + // check for remaining characters + bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + tty->print_cr("CompilerOracle: unrecognized line"); + tty->print_cr(" \"%s\"", original_line); + tty->print_cr(" Unrecognized text %s after command ", line); + } else if (match != NULL && !_quiet) { + tty->print("CompilerOracle: %s ", command_names[command]); + match->print(); + } } } diff --git a/hotspot/src/share/vm/compiler/compilerOracle.hpp b/hotspot/src/share/vm/compiler/compilerOracle.hpp index df025f76be5..8a5981ff1f8 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.hpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp @@ -64,6 +64,11 @@ class CompilerOracle : AllStatic { // Check to see if this method has option set for it static bool has_option_string(methodHandle method, const char * option); + // Check if method has option and value set. If yes, overwrite value and return true, + // otherwise leave value unchanged and return false. + template + static bool has_option_value(methodHandle method, const char* option, T& value); + // Reads from string instead of file static void parse_from_string(const char* command_string, void (*parser)(char*)); diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index e9ad157ecd5..e4f6d3f5040 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -246,12 +246,12 @@ class decode_env { }; decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { - memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. _output = output ? output : tty; _code = code; if (code != NULL && code->is_nmethod()) _nm = (nmethod*) code; - _strings.assign(c); + _strings.copy(c); // by default, output pc but not bytes: _print_pc = true; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp index 159a445b325..1e75d669d5c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp @@ -22,372 +22,375 @@ * */ - #include "precompiled.hpp" +#include "code/codeCache.hpp" #include "code/nmethod.hpp" #include "gc_implementation/g1/g1CodeCacheRemSet.hpp" +#include "gc_implementation/g1/heapRegion.hpp" +#include "memory/heap.hpp" #include "memory/iterator.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/hashtable.inline.hpp" +#include "utilities/stack.inline.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL), _free(NULL) { - _top = bottom(); +class CodeRootSetTable : public Hashtable { + friend class G1CodeRootSetTest; + typedef HashtableEntry Entry; + + static CodeRootSetTable* volatile _purge_list; + + CodeRootSetTable* _purge_next; + + unsigned int compute_hash(nmethod* nm) { + uintptr_t hash = (uintptr_t)nm; + return hash ^ (hash >> 7); // code heap blocks are 128byte aligned + } + + Entry* new_entry(nmethod* nm); + + public: + CodeRootSetTable(int size) : Hashtable(size, sizeof(Entry)), _purge_next(NULL) {} + ~CodeRootSetTable(); + + // Needs to be protected locks + bool add(nmethod* nm); + bool remove(nmethod* nm); + + // Can be called without locking + bool contains(nmethod* nm); + + int entry_size() const { return BasicHashtable::entry_size(); } + + void copy_to(CodeRootSetTable* new_table); + void nmethods_do(CodeBlobClosure* blk); + + template + void remove_if(CB& should_remove); + + static void purge_list_append(CodeRootSetTable* tbl); + static void purge(); + + static size_t static_mem_size() { + return sizeof(_purge_list); + } +}; + +CodeRootSetTable* volatile CodeRootSetTable::_purge_list = NULL; + +CodeRootSetTable::Entry* CodeRootSetTable::new_entry(nmethod* nm) { + unsigned int hash = compute_hash(nm); + Entry* entry = (Entry*) new_entry_free_list(); + if (entry == NULL) { + entry = (Entry*) NEW_C_HEAP_ARRAY2(char, entry_size(), mtGC, CURRENT_PC); + } + entry->set_next(NULL); + entry->set_hash(hash); + entry->set_literal(nm); + return entry; } -void G1CodeRootChunk::reset() { - _next = _prev = NULL; - _free = NULL; - _top = bottom(); -} - -void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) { - NmethodOrLink* cur = bottom(); - while (cur != _top) { - if (is_nmethod(cur)) { - cl->do_code_blob(cur->_nmethod); +CodeRootSetTable::~CodeRootSetTable() { + for (int index = 0; index < table_size(); ++index) { + for (Entry* e = bucket(index); e != NULL; ) { + Entry* to_remove = e; + // read next before freeing. + e = e->next(); + unlink_entry(to_remove); + FREE_C_HEAP_ARRAY(char, to_remove, mtGC); } - cur++; + } + assert(number_of_entries() == 0, "should have removed all entries"); + free_buckets(); + for (BasicHashtableEntry* e = new_entry_free_list(); e != NULL; e = new_entry_free_list()) { + FREE_C_HEAP_ARRAY(char, e, mtGC); } } -bool G1CodeRootChunk::remove_lock_free(nmethod* method) { - NmethodOrLink* cur = bottom(); - - for (NmethodOrLink* cur = bottom(); cur != _top; cur++) { - if (cur->_nmethod == method) { - bool result = Atomic::cmpxchg_ptr(NULL, &cur->_nmethod, method) == method; - - if (!result) { - // Someone else cleared out this entry. - return false; - } - - // The method was cleared. Time to link it into the free list. - NmethodOrLink* prev_free; - do { - prev_free = (NmethodOrLink*)_free; - cur->_link = prev_free; - } while (Atomic::cmpxchg_ptr(cur, &_free, prev_free) != prev_free); - - return true; - } +bool CodeRootSetTable::add(nmethod* nm) { + if (!contains(nm)) { + Entry* e = new_entry(nm); + int index = hash_to_index(e->hash()); + add_entry(index, e); + return true; } - return false; } -G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) { - _free_list.initialize(); - _free_list.set_size(G1CodeRootChunk::word_size()); -} - -size_t G1CodeRootChunkManager::fl_mem_size() { - return _free_list.count() * _free_list.size(); -} - -void G1CodeRootChunkManager::free_all_chunks(FreeList* list) { - _num_chunks_handed_out -= list->count(); - _free_list.prepend(list); -} - -void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) { - _free_list.return_chunk_at_head(chunk); - _num_chunks_handed_out--; -} - -void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) { - size_t keep = _num_chunks_handed_out * keep_ratio / 100; - if (keep >= (size_t)_free_list.count()) { - return; +bool CodeRootSetTable::contains(nmethod* nm) { + int index = hash_to_index(compute_hash(nm)); + for (Entry* e = bucket(index); e != NULL; e = e->next()) { + if (e->literal() == nm) { + return true; + } } + return false; +} - FreeList temp; - temp.initialize(); - temp.set_size(G1CodeRootChunk::word_size()); +bool CodeRootSetTable::remove(nmethod* nm) { + int index = hash_to_index(compute_hash(nm)); + Entry* previous = NULL; + for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) { + if (e->literal() == nm) { + if (previous != NULL) { + previous->set_next(e->next()); + } else { + set_entry(index, e->next()); + } + free_entry(e); + return true; + } + } + return false; +} - _free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp); +void CodeRootSetTable::copy_to(CodeRootSetTable* new_table) { + for (int index = 0; index < table_size(); ++index) { + for (Entry* e = bucket(index); e != NULL; e = e->next()) { + new_table->add(e->literal()); + } + } + new_table->copy_freelist(this); +} - G1CodeRootChunk* cur = temp.get_chunk_at_head(); - while (cur != NULL) { - delete cur; - cur = temp.get_chunk_at_head(); +void CodeRootSetTable::nmethods_do(CodeBlobClosure* blk) { + for (int index = 0; index < table_size(); ++index) { + for (Entry* e = bucket(index); e != NULL; e = e->next()) { + blk->do_code_blob(e->literal()); + } } } -size_t G1CodeRootChunkManager::static_mem_size() { - return sizeof(G1CodeRootChunkManager); -} - - -G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() { - G1CodeRootChunk* result = _free_list.get_chunk_at_head(); - if (result == NULL) { - result = new G1CodeRootChunk(); +template +void CodeRootSetTable::remove_if(CB& should_remove) { + for (int index = 0; index < table_size(); ++index) { + Entry* previous = NULL; + Entry* e = bucket(index); + while (e != NULL) { + Entry* next = e->next(); + if (should_remove(e->literal())) { + if (previous != NULL) { + previous->set_next(next); + } else { + set_entry(index, next); + } + free_entry(e); + } else { + previous = e; + } + e = next; + } } - _num_chunks_handed_out++; - result->reset(); - return result; -} - -#ifndef PRODUCT - -size_t G1CodeRootChunkManager::num_chunks_handed_out() const { - return _num_chunks_handed_out; -} - -size_t G1CodeRootChunkManager::num_free_chunks() const { - return (size_t)_free_list.count(); -} - -#endif - -G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager; - -void G1CodeRootSet::purge_chunks(size_t keep_ratio) { - _default_chunk_manager.purge_chunks(keep_ratio); -} - -size_t G1CodeRootSet::free_chunks_static_mem_size() { - return _default_chunk_manager.static_mem_size(); -} - -size_t G1CodeRootSet::free_chunks_mem_size() { - return _default_chunk_manager.fl_mem_size(); -} - -G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) { - if (_manager == NULL) { - _manager = &_default_chunk_manager; - } - _list.initialize(); - _list.set_size(G1CodeRootChunk::word_size()); } G1CodeRootSet::~G1CodeRootSet() { - clear(); + delete _table; } -void G1CodeRootSet::add(nmethod* method) { - if (!contains(method)) { - // Find the first chunk that isn't full. - G1CodeRootChunk* cur = _list.head(); - while (cur != NULL) { - if (!cur->is_full()) { - break; - } - cur = cur->next(); - } - - // All chunks are full, get a new chunk. - if (cur == NULL) { - cur = new_chunk(); - _list.return_chunk_at_head(cur); - } - - // Add the nmethod. - bool result = cur->add(method); - - guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method)); - - _length++; - } +CodeRootSetTable* G1CodeRootSet::load_acquire_table() { + return (CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table); } -void G1CodeRootSet::remove_lock_free(nmethod* method) { - G1CodeRootChunk* found = find(method); - if (found != NULL) { - bool result = found->remove_lock_free(method); - if (result) { - Atomic::dec_ptr((volatile intptr_t*)&_length); - } - } - assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method)); +void G1CodeRootSet::allocate_small_table() { + _table = new CodeRootSetTable(SmallSize); } -nmethod* G1CodeRootSet::pop() { - while (true) { - G1CodeRootChunk* cur = _list.head(); - if (cur == NULL) { - assert(_length == 0, "when there are no chunks, there should be no elements"); - return NULL; - } - nmethod* result = cur->pop(); - if (result != NULL) { - _length--; - return result; - } else { - free(_list.get_chunk_at_head()); +void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) { + for (;;) { + table->_purge_next = _purge_list; + CodeRootSetTable* old = (CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next); + if (old == table->_purge_next) { + break; } } } -G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) { - G1CodeRootChunk* cur = _list.head(); - while (cur != NULL) { - if (cur->contains(method)) { - return cur; - } - cur = (G1CodeRootChunk*)cur->next(); +void CodeRootSetTable::purge() { + CodeRootSetTable* table = _purge_list; + _purge_list = NULL; + while (table != NULL) { + CodeRootSetTable* to_purge = table; + table = table->_purge_next; + delete to_purge; } - return NULL; } -void G1CodeRootSet::free(G1CodeRootChunk* chunk) { - free_chunk(chunk); +void G1CodeRootSet::move_to_large() { + CodeRootSetTable* temp = new CodeRootSetTable(LargeSize); + + _table->copy_to(temp); + + CodeRootSetTable::purge_list_append(_table); + + OrderAccess::release_store_ptr(&_table, temp); } -bool G1CodeRootSet::contains(nmethod* method) { - return find(method) != NULL; -} -void G1CodeRootSet::clear() { - free_all_chunks(&_list); - _length = 0; -} - -void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const { - G1CodeRootChunk* cur = _list.head(); - while (cur != NULL) { - cur->nmethods_do(blk); - cur = (G1CodeRootChunk*)cur->next(); - } +void G1CodeRootSet::purge() { + CodeRootSetTable::purge(); } size_t G1CodeRootSet::static_mem_size() { - return sizeof(G1CodeRootSet); + return CodeRootSetTable::static_mem_size(); +} + +void G1CodeRootSet::add(nmethod* method) { + bool added = false; + if (is_empty()) { + allocate_small_table(); + } + added = _table->add(method); + if (_length == Threshold) { + move_to_large(); + } + if (added) { + ++_length; + } +} + +bool G1CodeRootSet::remove(nmethod* method) { + bool removed = false; + if (_table != NULL) { + removed = _table->remove(method); + } + if (removed) { + _length--; + if (_length == 0) { + clear(); + } + } + return removed; +} + +bool G1CodeRootSet::contains(nmethod* method) { + CodeRootSetTable* table = load_acquire_table(); + if (table != NULL) { + return table->contains(method); + } + return false; +} + +void G1CodeRootSet::clear() { + delete _table; + _table = NULL; + _length = 0; } size_t G1CodeRootSet::mem_size() { - return G1CodeRootSet::static_mem_size() + _list.count() * _list.size(); + return sizeof(*this) + + (_table != NULL ? sizeof(CodeRootSetTable) + _table->entry_size() * _length : 0); +} + +void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const { + if (_table != NULL) { + _table->nmethods_do(blk); + } +} + +class CleanCallback : public StackObj { + class PointsIntoHRDetectionClosure : public OopClosure { + HeapRegion* _hr; + public: + bool _points_into; + PointsIntoHRDetectionClosure(HeapRegion* hr) : _hr(hr), _points_into(false) {} + + void do_oop(narrowOop* o) { + do_oop_work(o); + } + + void do_oop(oop* o) { + do_oop_work(o); + } + + template + void do_oop_work(T* p) { + if (_hr->is_in(oopDesc::load_decode_heap_oop(p))) { + _points_into = true; + } + } + }; + + PointsIntoHRDetectionClosure _detector; + CodeBlobToOopClosure _blobs; + + public: + CleanCallback(HeapRegion* hr) : _detector(hr), _blobs(&_detector, !CodeBlobToOopClosure::FixRelocations) {} + + bool operator() (nmethod* nm) { + _detector._points_into = false; + _blobs.do_code_blob(nm); + return _detector._points_into; + } +}; + +void G1CodeRootSet::clean(HeapRegion* owner) { + CleanCallback should_clean(owner); + if (_table != NULL) { + _table->remove_if(should_clean); + } } #ifndef PRODUCT -void G1CodeRootSet::test() { - G1CodeRootChunkManager mgr; - - assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet"); - - assert(G1CodeRootChunkManager::static_mem_size() > sizeof(void*), - err_msg("The chunk manager's static memory usage seems too small, is only "SIZE_FORMAT" bytes.", G1CodeRootChunkManager::static_mem_size())); - - // The number of chunks that we allocate for purge testing. - size_t const num_chunks = 10; - - { - G1CodeRootSet set1(&mgr); - assert(set1.is_empty(), "Code root set must be initially empty but is not."); - - assert(G1CodeRootSet::static_mem_size() > sizeof(void*), - err_msg("The code root set's static memory usage seems too small, is only "SIZE_FORMAT" bytes", G1CodeRootSet::static_mem_size())); - - set1.add((nmethod*)1); - assert(mgr.num_chunks_handed_out() == 1, - err_msg("Must have allocated and handed out one chunk, but handed out " - SIZE_FORMAT" chunks", mgr.num_chunks_handed_out())); - assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " - SIZE_FORMAT" elements", set1.length())); - - // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which - // we cannot access. - for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) { - set1.add((nmethod*)1); - } - assert(mgr.num_chunks_handed_out() == 1, - err_msg("Duplicate detection must have prevented allocation of further " - "chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out())); - assert(set1.length() == 1, - err_msg("Duplicate detection should not have increased the set size but " - "is "SIZE_FORMAT, set1.length())); - - size_t num_total_after_add = G1CodeRootChunk::word_size() + 1; - for (size_t i = 0; i < num_total_after_add - 1; i++) { - set1.add((nmethod*)(uintptr_t)(2 + i)); - } - assert(mgr.num_chunks_handed_out() > 1, - "After adding more code roots, more than one additional chunk should have been handed out"); - assert(set1.length() == num_total_after_add, - err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " - "need to be in the set, but there are only "SIZE_FORMAT, - num_total_after_add, set1.length())); - - size_t num_popped = 0; - while (set1.pop() != NULL) { - num_popped++; - } - assert(num_popped == num_total_after_add, - err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " - "were added", num_popped, num_total_after_add)); - assert(mgr.num_chunks_handed_out() == 0, - err_msg("After popping all elements, all chunks must have been returned " - "but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out())); - - mgr.purge_chunks(0); - assert(mgr.num_free_chunks() == 0, - err_msg("After purging everything, the free list must be empty but still " - "contains "SIZE_FORMAT" chunks", mgr.num_free_chunks())); - - // Add some more handed out chunks. - size_t i = 0; - while (mgr.num_chunks_handed_out() < num_chunks) { - set1.add((nmethod*)i); - i++; - } - +class G1CodeRootSetTest { + public: + static void test() { { - // Generate chunks on the free list. - G1CodeRootSet set2(&mgr); - size_t i = 0; - while (mgr.num_chunks_handed_out() < (num_chunks * 2)) { - set2.add((nmethod*)i); - i++; + G1CodeRootSet set1; + assert(set1.is_empty(), "Code root set must be initially empty but is not."); + + assert(G1CodeRootSet::static_mem_size() == sizeof(void*), + err_msg("The code root set's static memory usage is incorrect, "SIZE_FORMAT" bytes", G1CodeRootSet::static_mem_size())); + + set1.add((nmethod*)1); + assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " + SIZE_FORMAT" elements", set1.length())); + + const size_t num_to_add = (size_t)G1CodeRootSet::Threshold + 1; + + for (size_t i = 1; i <= num_to_add; i++) { + set1.add((nmethod*)1); } - // Exit of the scope of the set2 object will call the destructor that generates - // num_chunks elements on the free list. + assert(set1.length() == 1, + err_msg("Duplicate detection should not have increased the set size but " + "is "SIZE_FORMAT, set1.length())); + + for (size_t i = 2; i <= num_to_add; i++) { + set1.add((nmethod*)(uintptr_t)(i)); + } + assert(set1.length() == num_to_add, + err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " + "need to be in the set, but there are only "SIZE_FORMAT, + num_to_add, set1.length())); + + assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); + + size_t num_popped = 0; + for (size_t i = 1; i <= num_to_add; i++) { + bool removed = set1.remove((nmethod*)i); + if (removed) { + num_popped += 1; + } else { + break; + } + } + assert(num_popped == num_to_add, + err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " + "were added", num_popped, num_to_add)); + assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); + + G1CodeRootSet::purge(); + + assert(CodeRootSetTable::_purge_list == NULL, "should have purged old small tables"); + } - assert(mgr.num_chunks_handed_out() == num_chunks, - err_msg("Deletion of the second set must have resulted in giving back " - "those, but there are still "SIZE_FORMAT" additional handed out, expecting " - SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks)); - assert(mgr.num_free_chunks() == num_chunks, - err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " - "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks())); - - size_t const test_percentage = 50; - mgr.purge_chunks(test_percentage); - assert(mgr.num_chunks_handed_out() == num_chunks, - err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT, - mgr.num_chunks_handed_out())); - assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100), - err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks" - "but there are "SIZE_FORMAT, test_percentage, num_chunks, - mgr.num_free_chunks())); - // Purge the remainder of the chunks on the free list. - mgr.purge_chunks(0); - assert(mgr.num_free_chunks() == 0, "Free List must be empty"); - assert(mgr.num_chunks_handed_out() == num_chunks, - err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set " - "but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out())); - - // Exit of the scope of the set1 object will call the destructor that generates - // num_chunks additional elements on the free list. - } - - assert(mgr.num_chunks_handed_out() == 0, - err_msg("Deletion of the only set must have resulted in no chunks handed " - "out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out())); - assert(mgr.num_free_chunks() == num_chunks, - err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " - "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks())); - - // Restore initial state. - mgr.purge_chunks(0); - assert(mgr.num_free_chunks() == 0, "Free List must be empty"); - assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet"); -} + } +}; void TestCodeCacheRemSet_test() { - G1CodeRootSet::test(); + G1CodeRootSetTest::test(); } + #endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp index c351330f12f..87eb52a5b64 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp @@ -26,222 +26,64 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP #include "memory/allocation.hpp" -#include "memory/freeList.hpp" -#include "runtime/globals.hpp" class CodeBlobClosure; - -// The elements of the G1CodeRootChunk is either: -// 1) nmethod pointers -// 2) nodes in an internally chained free list -typedef union { - nmethod* _nmethod; - void* _link; -} NmethodOrLink; - -class G1CodeRootChunk : public CHeapObj { - private: - static const int NUM_ENTRIES = 32; - public: - G1CodeRootChunk* _next; - G1CodeRootChunk* _prev; - - NmethodOrLink* _top; - // First free position within the chunk. - volatile NmethodOrLink* _free; - - NmethodOrLink _data[NUM_ENTRIES]; - - NmethodOrLink* bottom() const { - return (NmethodOrLink*) &(_data[0]); - } - - NmethodOrLink* end() const { - return (NmethodOrLink*) &(_data[NUM_ENTRIES]); - } - - bool is_link(NmethodOrLink* nmethod_or_link) { - return nmethod_or_link->_link == NULL || - (bottom() <= nmethod_or_link->_link - && nmethod_or_link->_link < end()); - } - - bool is_nmethod(NmethodOrLink* nmethod_or_link) { - return !is_link(nmethod_or_link); - } - - public: - G1CodeRootChunk(); - ~G1CodeRootChunk() {} - - static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } - - // FreeList "interface" methods - - G1CodeRootChunk* next() const { return _next; } - G1CodeRootChunk* prev() const { return _prev; } - void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} - void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} - void clear_next() { set_next(NULL); } - void clear_prev() { set_prev(NULL); } - - size_t size() const { return word_size(); } - - void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } - void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } - void link_after(G1CodeRootChunk* ptr) { - link_next(ptr); - if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); - } - - bool is_free() { return true; } - - // New G1CodeRootChunk routines - - void reset(); - - bool is_empty() const { - return _top == bottom(); - } - - bool is_full() const { - return _top == end() && _free == NULL; - } - - bool contains(nmethod* method) { - NmethodOrLink* cur = bottom(); - while (cur != _top) { - if (cur->_nmethod == method) return true; - cur++; - } - return false; - } - - bool add(nmethod* method) { - if (is_full()) { - return false; - } - - if (_free != NULL) { - // Take from internally chained free list - NmethodOrLink* first_free = (NmethodOrLink*)_free; - _free = (NmethodOrLink*)_free->_link; - first_free->_nmethod = method; - } else { - // Take from top. - _top->_nmethod = method; - _top++; - } - - return true; - } - - bool remove_lock_free(nmethod* method); - - void nmethods_do(CodeBlobClosure* blk); - - nmethod* pop() { - if (_free != NULL) { - // Kill the free list. - _free = NULL; - } - - while (!is_empty()) { - _top--; - if (is_nmethod(_top)) { - return _top->_nmethod; - } - } - - return NULL; - } -}; - -// Manages free chunks. -class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC { - private: - // Global free chunk list management - FreeList _free_list; - // Total number of chunks handed out - size_t _num_chunks_handed_out; - - public: - G1CodeRootChunkManager(); - - G1CodeRootChunk* new_chunk(); - void free_chunk(G1CodeRootChunk* chunk); - // Free all elements of the given list. - void free_all_chunks(FreeList* list); - - void initialize(); - void purge_chunks(size_t keep_ratio); - - static size_t static_mem_size(); - size_t fl_mem_size(); - -#ifndef PRODUCT - size_t num_chunks_handed_out() const; - size_t num_free_chunks() const; -#endif -}; +class CodeRootSetTable; +class HeapRegion; +class nmethod; // Implements storage for a set of code roots. // All methods that modify the set are not thread-safe except if otherwise noted. class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { + friend class G1CodeRootSetTest; private: - // Global default free chunk manager instance. - static G1CodeRootChunkManager _default_chunk_manager; - G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); } - void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); } - // Free all elements of the given list. - void free_all_chunks(FreeList* list) { _manager->free_all_chunks(list); } + const static size_t SmallSize = 32; + const static size_t Threshold = 24; + const static size_t LargeSize = 512; - // Return the chunk that contains the given nmethod, NULL otherwise. - // Scans the list of chunks backwards, as this method is used to add new - // entries, which are typically added in bulk for a single nmethod. - G1CodeRootChunk* find(nmethod* method); - void free(G1CodeRootChunk* chunk); + CodeRootSetTable* _table; + CodeRootSetTable* load_acquire_table(); size_t _length; - FreeList _list; - G1CodeRootChunkManager* _manager; + + void move_to_large(); + void allocate_small_table(); public: - // If an instance is initialized with a chunk manager of NULL, use the global - // default one. - G1CodeRootSet(G1CodeRootChunkManager* manager = NULL); + G1CodeRootSet() : _table(NULL), _length(0) {} ~G1CodeRootSet(); - static void purge_chunks(size_t keep_ratio); + static void purge(); - static size_t free_chunks_static_mem_size(); - static size_t free_chunks_mem_size(); + static size_t static_mem_size(); - // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this - // method is likely to be repeatedly called with the same nmethod. void add(nmethod* method); - void remove_lock_free(nmethod* method); - nmethod* pop(); + bool remove(nmethod* method); + // Safe to call without synchronization, but may return false negatives. bool contains(nmethod* method); void clear(); void nmethods_do(CodeBlobClosure* blk) const; - bool is_empty() { return length() == 0; } + // Remove all nmethods which no longer contain pointers into our "owner" region + void clean(HeapRegion* owner); + + bool is_empty() { + bool empty = length() == 0; + assert(empty == (_table == NULL), "is empty only if table is deallocated"); + return empty; + } // Length in elements size_t length() const { return _length; } - // Static data memory size in bytes of this set. - static size_t static_mem_size(); // Memory size in bytes taken by this set. size_t mem_size(); - static void test() PRODUCT_RETURN; }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 3351607d946..b7bf1ffdb9c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -4670,6 +4670,56 @@ class G1KlassScanClosure : public KlassClosure { } }; +class G1CodeBlobClosure : public CodeBlobClosure { + class HeapRegionGatheringOopClosure : public OopClosure { + G1CollectedHeap* _g1h; + OopClosure* _work; + nmethod* _nm; + + template + void do_oop_work(T* p) { + _work->do_oop(p); + T oop_or_narrowoop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(oop_or_narrowoop)) { + oop o = oopDesc::decode_heap_oop_not_null(oop_or_narrowoop); + HeapRegion* hr = _g1h->heap_region_containing_raw(o); + assert(!_g1h->obj_in_cs(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in CS then evacuation failed and nm must already be in the remset"); + hr->add_strong_code_root(_nm); + } + } + + public: + HeapRegionGatheringOopClosure(OopClosure* oc) : _g1h(G1CollectedHeap::heap()), _work(oc), _nm(NULL) {} + + void do_oop(oop* o) { + do_oop_work(o); + } + + void do_oop(narrowOop* o) { + do_oop_work(o); + } + + void set_nm(nmethod* nm) { + _nm = nm; + } + }; + + HeapRegionGatheringOopClosure _oc; +public: + G1CodeBlobClosure(OopClosure* oc) : _oc(oc) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + if (!nm->test_set_oops_do_mark()) { + _oc.set_nm(nm); + nm->oops_do(&_oc); + nm->fix_oop_relocations(); + } + } + } +}; + class G1ParTask : public AbstractGangTask { protected: G1CollectedHeap* _g1h; @@ -4738,22 +4788,6 @@ public: } }; - class G1CodeBlobClosure: public CodeBlobClosure { - OopClosure* _f; - - public: - G1CodeBlobClosure(OopClosure* f) : _f(f) {} - void do_code_blob(CodeBlob* blob) { - nmethod* that = blob->as_nmethod_or_null(); - if (that != NULL) { - if (!that->test_set_oops_do_mark()) { - that->oops_do(_f); - that->fix_oop_relocations(); - } - } - } - }; - void work(uint worker_id) { if (worker_id >= _n_workers) return; // no work needed this round @@ -4944,7 +4978,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots, g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms); // Now scan the complement of the collection set. - MarkingCodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots, CodeBlobToOopClosure::FixRelocations); + G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots); g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i); @@ -5991,12 +6025,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { hot_card_cache->reset_hot_cache(); hot_card_cache->set_use_cache(true); - // Migrate the strong code roots attached to each region in - // the collection set. Ideally we would like to do this - // after we have finished the scanning/evacuation of the - // strong code roots for a particular heap region. - migrate_strong_code_roots(); - purge_code_root_memory(); if (g1_policy()->during_initial_mark_pause()) { @@ -7049,13 +7077,8 @@ class RegisterNMethodOopClosure: public OopClosure { " starting at "HR_FORMAT, _nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); - // HeapRegion::add_strong_code_root() avoids adding duplicate - // entries but having duplicates is OK since we "mark" nmethods - // as visited when we scan the strong code root lists during the GC. - hr->add_strong_code_root(_nm); - assert(hr->rem_set()->strong_code_roots_list_contains(_nm), - err_msg("failed to add code root "PTR_FORMAT" to remembered set of region "HR_FORMAT, - _nm, HR_FORMAT_PARAMS(hr))); + // HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries. + hr->add_strong_code_root_locked(_nm); } } @@ -7082,9 +7105,6 @@ class UnregisterNMethodOopClosure: public OopClosure { _nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); hr->remove_strong_code_root(_nm); - assert(!hr->rem_set()->strong_code_roots_list_contains(_nm), - err_msg("failed to remove code root "PTR_FORMAT" of region "HR_FORMAT, - _nm, HR_FORMAT_PARAMS(hr))); } } @@ -7112,28 +7132,9 @@ void G1CollectedHeap::unregister_nmethod(nmethod* nm) { nm->oops_do(®_cl, true); } -class MigrateCodeRootsHeapRegionClosure: public HeapRegionClosure { -public: - bool doHeapRegion(HeapRegion *hr) { - assert(!hr->isHumongous(), - err_msg("humongous region "HR_FORMAT" should not have been added to collection set", - HR_FORMAT_PARAMS(hr))); - hr->migrate_strong_code_roots(); - return false; - } -}; - -void G1CollectedHeap::migrate_strong_code_roots() { - MigrateCodeRootsHeapRegionClosure cl; - double migrate_start = os::elapsedTime(); - collection_set_iterate(&cl); - double migration_time_ms = (os::elapsedTime() - migrate_start) * 1000.0; - g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms); -} - void G1CollectedHeap::purge_code_root_memory() { double purge_start = os::elapsedTime(); - G1CodeRootSet::purge_chunks(G1CodeRootsChunkCacheKeepPercent); + G1CodeRootSet::purge(); double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0; g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 065a1205d92..d8611470ffb 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1662,12 +1662,6 @@ public: // Unregister the given nmethod from the G1 heap. virtual void unregister_nmethod(nmethod* nm); - // Migrate the nmethods in the code root lists of the regions - // in the collection set to regions in to-space. In the event - // of an evacuation failure, nmethods that reference objects - // that were not successfully evacuated are not migrated. - void migrate_strong_code_roots(); - // Free up superfluous code root memory. void purge_code_root_memory(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp index 4b25d904063..72d1ca179f8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp @@ -217,6 +217,8 @@ public: _update_rset_cl->set_region(hr); hr->object_iterate(&rspc); + hr->rem_set()->clean_strong_code_roots(hr); + hr->note_self_forwarding_removal_end(during_initial_mark, during_conc_mark, rspc.marked_bytes()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 4e3fde8b862..bf7e3533b71 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -275,9 +275,6 @@ double G1GCPhaseTimes::accounted_time_ms() { // Now subtract the time taken to fix up roots in generated code misc_time_ms += _cur_collection_code_root_fixup_time_ms; - // Strong code root migration time - misc_time_ms += _cur_strong_code_root_migration_time_ms; - // Strong code root purge time misc_time_ms += _cur_strong_code_root_purge_time_ms; @@ -328,7 +325,6 @@ void G1GCPhaseTimes::print(double pause_time_sec) { _last_obj_copy_times_ms.print(1, "Object Copy (ms)"); } print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); - print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index 4237c972a55..8421eb07b6a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -129,7 +129,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_par_time_ms; double _cur_collection_code_root_fixup_time_ms; - double _cur_strong_code_root_migration_time_ms; double _cur_strong_code_root_purge_time_ms; double _cur_evac_fail_recalc_used; @@ -233,10 +232,6 @@ class G1GCPhaseTimes : public CHeapObj { _cur_collection_code_root_fixup_time_ms = ms; } - void record_strong_code_root_migration_time(double ms) { - _cur_strong_code_root_migration_time_ms = ms; - } - void record_strong_code_root_purge_time(double ms) { _cur_strong_code_root_purge_time_ms = ms; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 33a930d96e4..f1628f63968 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -110,7 +110,7 @@ class ScanRSClosure : public HeapRegionClosure { G1CollectedHeap* _g1h; OopsInHeapRegionClosure* _oc; - CodeBlobToOopClosure* _code_root_cl; + CodeBlobClosure* _code_root_cl; G1BlockOffsetSharedArray* _bot_shared; G1SATBCardTableModRefBS *_ct_bs; @@ -122,7 +122,7 @@ class ScanRSClosure : public HeapRegionClosure { public: ScanRSClosure(OopsInHeapRegionClosure* oc, - CodeBlobToOopClosure* code_root_cl, + CodeBlobClosure* code_root_cl, uint worker_i) : _oc(oc), _code_root_cl(code_root_cl), @@ -242,7 +242,7 @@ public: }; void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, - CodeBlobToOopClosure* code_root_cl, + CodeBlobClosure* code_root_cl, uint worker_i) { double rs_time_start = os::elapsedTime(); HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i); @@ -321,7 +321,7 @@ void G1RemSet::cleanupHRRS() { } void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, - CodeBlobToOopClosure* code_root_cl, + CodeBlobClosure* code_root_cl, uint worker_i) { #if CARD_REPEAT_HISTO ct_freq_update_histo_and_reset(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 81e85593509..35279a52e20 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -96,7 +96,7 @@ public: // the "i" passed to the calling thread's work(i) function. // In the sequential case this param will be ignored. void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, - CodeBlobToOopClosure* code_root_cl, + CodeBlobClosure* code_root_cl, uint worker_i); // Prepare for and cleanup after an oops_into_collection_set_do @@ -108,7 +108,7 @@ public: void cleanup_after_oops_into_collection_set_do(); void scanRS(OopsInHeapRegionClosure* oc, - CodeBlobToOopClosure* code_root_cl, + CodeBlobClosure* code_root_cl, uint worker_i); void updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp index cdc13041a5d..69b1c1f8707 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp @@ -253,6 +253,7 @@ public: size_t occupied_cards = hrrs->occupied(); size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); if (code_root_mem_sz > max_code_root_mem_sz()) { + _max_code_root_mem_sz = code_root_mem_sz; _max_code_root_mem_sz_region = r; } size_t code_root_elems = hrrs->strong_code_roots_list_length(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 17ae309240d..1913327309c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -277,10 +277,6 @@ product(uintx, G1MixedGCCountTarget, 8, \ "The target number of mixed GCs after a marking cycle.") \ \ - experimental(uintx, G1CodeRootsChunkCacheKeepPercent, 10, \ - "The amount of code root chunks that should be kept at most " \ - "as percentage of already allocated.") \ - \ experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \ "Try to reclaim dead large objects at every young GC.") \ \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 5e5e9ee5880..aa6697a742c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -540,21 +540,17 @@ void HeapRegion::add_strong_code_root(nmethod* nm) { hrrs->add_strong_code_root(nm); } +void HeapRegion::add_strong_code_root_locked(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + HeapRegionRemSet* hrrs = rem_set(); + hrrs->add_strong_code_root_locked(nm); +} + void HeapRegion::remove_strong_code_root(nmethod* nm) { HeapRegionRemSet* hrrs = rem_set(); hrrs->remove_strong_code_root(nm); } -void HeapRegion::migrate_strong_code_roots() { - assert(in_collection_set(), "only collection set regions"); - assert(!isHumongous(), - err_msg("humongous region "HR_FORMAT" should not have been added to collection set", - HR_FORMAT_PARAMS(this))); - - HeapRegionRemSet* hrrs = rem_set(); - hrrs->migrate_strong_code_roots(); -} - void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const { HeapRegionRemSet* hrrs = rem_set(); hrrs->strong_code_roots_do(blk); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 6736ee77504..a311fd5e92d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -756,14 +756,9 @@ class HeapRegion: public G1OffsetTableContigSpace { // Routines for managing a list of code roots (attached to the // this region's RSet) that point into this heap region. void add_strong_code_root(nmethod* nm); + void add_strong_code_root_locked(nmethod* nm); void remove_strong_code_root(nmethod* nm); - // During a collection, migrate the successfully evacuated - // strong code roots that referenced into this region to the - // new regions that they now point into. Unsuccessfully - // evacuated code roots are not migrated. - void migrate_strong_code_roots(); - // Applies blk->do_code_blob() to each of the entries in // the strong code roots list for this region void strong_code_roots_do(CodeBlobClosure* blk) const; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 9edff815c69..419976c11dd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -448,10 +448,10 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { // Note that this may be a continued H region. HeapRegion* from_hr = _g1h->heap_region_containing_raw(from); - RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrm_index(); + RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index(); // If the region is already coarsened, return. - if (_coarse_map.at(from_hrs_ind)) { + if (_coarse_map.at(from_hrm_ind)) { if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" coarse map hit."); } @@ -460,7 +460,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { } // Otherwise find a per-region table to add it to. - size_t ind = from_hrs_ind & _mod_max_fine_entries_mask; + size_t ind = from_hrm_ind & _mod_max_fine_entries_mask; PerRegionTable* prt = find_region_table(ind, from_hr); if (prt == NULL) { MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); @@ -475,7 +475,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion, "Must be in range."); if (G1HRRSUseSparseTable && - _sparse_table.add_card(from_hrs_ind, card_index)) { + _sparse_table.add_card(from_hrm_ind, card_index)) { if (G1RecordHRRSOops) { HeapRegionRemSet::record(hr(), from); if (G1TraceHeapRegionRememberedSet) { @@ -495,7 +495,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" [tid %d] sparse table entry " "overflow(f: %d, t: %u)", - tid, from_hrs_ind, cur_hrm_ind); + tid, from_hrm_ind, cur_hrm_ind); } } @@ -516,7 +516,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { if (G1HRRSUseSparseTable) { // Transfer from sparse to fine-grain. - SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrs_ind); + SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrm_ind); assert(sprt_entry != NULL, "There should have been an entry"); for (int i = 0; i < SparsePRTEntry::cards_num(); i++) { CardIdx_t c = sprt_entry->card(i); @@ -525,7 +525,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { } } // Now we can delete the sparse entry. - bool res = _sparse_table.delete_entry(from_hrs_ind); + bool res = _sparse_table.delete_entry(from_hrm_ind); assert(res, "It should have been there."); } } @@ -926,8 +926,24 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, } // Code roots support +// +// The code root set is protected by two separate locking schemes +// When at safepoint the per-hrrs lock must be held during modifications +// except when doing a full gc. +// When not at safepoint the CodeCache_lock must be held during modifications. +// When concurrent readers access the contains() function +// (during the evacuation phase) no removals are allowed. void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { + assert(nm != NULL, "sanity"); + // Optimistic unlocked contains-check + if (!_code_roots.contains(nm)) { + MutexLockerEx ml(&_m, Mutex::_no_safepoint_check_flag); + add_strong_code_root_locked(nm); + } +} + +void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) { assert(nm != NULL, "sanity"); _code_roots.add(nm); } @@ -936,98 +952,21 @@ void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); assert_locked_or_safepoint(CodeCache_lock); - _code_roots.remove_lock_free(nm); + MutexLockerEx ml(CodeCache_lock->owned_by_self() ? NULL : &_m, Mutex::_no_safepoint_check_flag); + _code_roots.remove(nm); // Check that there were no duplicates guarantee(!_code_roots.contains(nm), "duplicate entry found"); } -class NMethodMigrationOopClosure : public OopClosure { - G1CollectedHeap* _g1h; - HeapRegion* _from; - nmethod* _nm; - - uint _num_self_forwarded; - - template void do_oop_work(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (_from->is_in(obj)) { - // Reference still points into the source region. - // Since roots are immediately evacuated this means that - // we must have self forwarded the object - assert(obj->is_forwarded(), - err_msg("code roots should be immediately evacuated. " - "Ref: "PTR_FORMAT", " - "Obj: "PTR_FORMAT", " - "Region: "HR_FORMAT, - p, (void*) obj, HR_FORMAT_PARAMS(_from))); - assert(obj->forwardee() == obj, - err_msg("not self forwarded? obj = "PTR_FORMAT, (void*)obj)); - - // The object has been self forwarded. - // Note, if we're during an initial mark pause, there is - // no need to explicitly mark object. It will be marked - // during the regular evacuation failure handling code. - _num_self_forwarded++; - } else { - // The reference points into a promotion or to-space region - HeapRegion* to = _g1h->heap_region_containing(obj); - to->rem_set()->add_strong_code_root(_nm); - } - } - } - -public: - NMethodMigrationOopClosure(G1CollectedHeap* g1h, HeapRegion* from, nmethod* nm): - _g1h(g1h), _from(from), _nm(nm), _num_self_forwarded(0) {} - - void do_oop(narrowOop* p) { do_oop_work(p); } - void do_oop(oop* p) { do_oop_work(p); } - - uint retain() { return _num_self_forwarded > 0; } -}; - -void HeapRegionRemSet::migrate_strong_code_roots() { - assert(hr()->in_collection_set(), "only collection set regions"); - assert(!hr()->isHumongous(), - err_msg("humongous region "HR_FORMAT" should not have been added to the collection set", - HR_FORMAT_PARAMS(hr()))); - - ResourceMark rm; - - // List of code blobs to retain for this region - GrowableArray to_be_retained(10); - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - while (!_code_roots.is_empty()) { - nmethod *nm = _code_roots.pop(); - if (nm != NULL) { - NMethodMigrationOopClosure oop_cl(g1h, hr(), nm); - nm->oops_do(&oop_cl); - if (oop_cl.retain()) { - to_be_retained.push(nm); - } - } - } - - // Now push any code roots we need to retain - assert(to_be_retained.is_empty() || hr()->evacuation_failed(), - "Retained nmethod list must be empty or " - "evacuation of this region failed"); - - while (to_be_retained.is_nonempty()) { - nmethod* nm = to_be_retained.pop(); - assert(nm != NULL, "sanity"); - add_strong_code_root(nm); - } -} - void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { _code_roots.nmethods_do(blk); } +void HeapRegionRemSet::clean_strong_code_roots(HeapRegion* hr) { + _code_roots.clean(hr); +} + size_t HeapRegionRemSet::strong_code_roots_mem_size() { return _code_roots.mem_size(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 70eae9bdf2b..687f1fb0a68 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -349,13 +349,13 @@ public: // Returns the memory occupancy of all static data structures associated // with remembered sets. static size_t static_mem_size() { - return OtherRegionsTable::static_mem_size() + G1CodeRootSet::free_chunks_static_mem_size(); + return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size(); } // Returns the memory occupancy of all free_list data structures associated // with remembered sets. static size_t fl_mem_size() { - return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::free_chunks_mem_size(); + return OtherRegionsTable::fl_mem_size(); } bool contains_reference(OopOrNarrowOopStar from) const { @@ -365,18 +365,15 @@ public: // Routines for managing the list of code roots that point into // the heap region that owns this RSet. void add_strong_code_root(nmethod* nm); + void add_strong_code_root_locked(nmethod* nm); void remove_strong_code_root(nmethod* nm); - // During a collection, migrate the successfully evacuated strong - // code roots that referenced into the region that owns this RSet - // to the RSets of the new regions that they now point into. - // Unsuccessfully evacuated code roots are not migrated. - void migrate_strong_code_roots(); - // Applies blk->do_code_blob() to each of the entries in // the strong code roots list void strong_code_roots_do(CodeBlobClosure* blk) const; + void clean_strong_code_roots(HeapRegion* hr); + // Returns the number of elements in the strong code roots list size_t strong_code_roots_list_length() const { return _code_roots.length(); diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index 2a81daf205d..96c480e4385 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -55,7 +55,9 @@ class InterpreterCodelet: public Stub { public: // Initialization/finalization void initialize(int size, - CodeStrings& strings) { _size = size; DEBUG_ONLY(_strings.assign(strings);) } + CodeStrings& strings) { _size = size; + DEBUG_ONLY(::new(&_strings) CodeStrings();) + DEBUG_ONLY(_strings.assign(strings);) } void finalize() { ShouldNotCallThis(); } // General info/converters diff --git a/hotspot/src/share/vm/memory/freeList.cpp b/hotspot/src/share/vm/memory/freeList.cpp index f1d4859a040..3ab6f09a8ae 100644 --- a/hotspot/src/share/vm/memory/freeList.cpp +++ b/hotspot/src/share/vm/memory/freeList.cpp @@ -34,7 +34,6 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" #endif // INCLUDE_ALL_GCS // Free list. A FreeList is used to access a linked list of chunks @@ -333,5 +332,4 @@ template class FreeList; template class FreeList; #if INCLUDE_ALL_GCS template class FreeList; -template class FreeList; #endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index 7ed1c07ca4f..cc514c05050 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -41,7 +41,7 @@ #define SET_ESTIMATED_SIZE(type, region) \ Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \ - (type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size + (uintx)(type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size class FileMapInfo; diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index 726c21db2da..06f9bf136ad 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -78,7 +78,6 @@ ArrayKlass::ArrayKlass(Symbol* name) { set_dimension(1); set_higher_dimension(NULL); set_lower_dimension(NULL); - set_component_mirror(NULL); // Arrays don't add any new methods, so their vtable is the same size as // the vtable of klass Object. int vtable_size = Universe::base_vtable_size(); @@ -160,14 +159,6 @@ void ArrayKlass::array_klasses_do(void f(Klass* k)) { } } -// GC support - -void ArrayKlass::oops_do(OopClosure* cl) { - Klass::oops_do(cl); - - cl->do_oop(adr_component_mirror()); -} - // JVM support jint ArrayKlass::compute_modifier_flags(TRAPS) const { @@ -182,8 +173,6 @@ jint ArrayKlass::jvmti_class_status() const { void ArrayKlass::remove_unshareable_info() { Klass::remove_unshareable_info(); - // Clear the java mirror - set_component_mirror(NULL); } void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { @@ -217,10 +206,6 @@ void ArrayKlass::oop_print_on(oop obj, outputStream* st) { void ArrayKlass::verify_on(outputStream* st) { Klass::verify_on(st); - - if (component_mirror() != NULL) { - guarantee(component_mirror()->klass() != NULL, "should have a class"); - } } void ArrayKlass::oop_verify_on(oop obj, outputStream* st) { diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index 3b55e031616..39ae5768aaf 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -39,7 +39,6 @@ class ArrayKlass: public Klass { Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). int _vtable_len; // size of vtable for this klass - oop _component_mirror; // component type, as a java/lang/Class protected: // Constructors @@ -70,13 +69,6 @@ class ArrayKlass: public Klass { // type of elements (T_OBJECT for both oop arrays and array-arrays) BasicType element_type() const { return layout_helper_element_type(layout_helper()); } - oop component_mirror() const { return _component_mirror; } - void set_component_mirror(oop m) { klass_oop_store(&_component_mirror, m); } - oop* adr_component_mirror() { return (oop*)&this->_component_mirror;} - - // Compiler/Interpreter offset - static ByteSize component_mirror_offset() { return in_ByteSize(offset_of(ArrayKlass, _component_mirror)); } - virtual Klass* java_super() const;//{ return SystemDictionary::Object_klass(); } // Allocation @@ -122,9 +114,6 @@ class ArrayKlass: public Klass { void array_klasses_do(void f(Klass* k)); void array_klasses_do(void f(Klass* k, TRAPS), TRAPS); - // GC support - virtual void oops_do(OopClosure* cl); - // Return a handle. static void complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, TRAPS); diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 620dffa0e1b..5af2104e594 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -565,7 +565,7 @@ protected: TRACE_DEFINE_KLASS_METHODS; // garbage collection support - virtual void oops_do(OopClosure* cl); + void oops_do(OopClosure* cl); // Iff the class loader (or mirror for anonymous classes) is alive the // Klass is considered alive. diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 40dfee7fbea..fdf8c7fd112 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -86,7 +86,7 @@ ProfileData::ProfileData() { char* ProfileData::print_data_on_helper(const MethodData* md) const { DataLayout* dp = md->extra_data_base(); - DataLayout* end = md->extra_data_limit(); + DataLayout* end = md->args_data_limit(); stringStream ss; for (;; dp = MethodData::next_extra(dp)) { assert(dp < end, "moved past end of extra data"); @@ -1048,14 +1048,15 @@ void MethodData::post_initialize(BytecodeStream* stream) { stream->next(); data->post_initialize(stream, this); } - if (_parameters_type_data_di != -1) { + if (_parameters_type_data_di != no_parameters) { parameters_type_data()->post_initialize(NULL, this); } } // Initialize the MethodData* corresponding to a given method. MethodData::MethodData(methodHandle method, int size, TRAPS) - : _extra_data_lock(Monitor::leaf, "MDO extra data lock") { + : _extra_data_lock(Monitor::leaf, "MDO extra data lock"), + _parameters_type_data_di(parameters_uninitialized) { No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; // Set the method back-pointer. @@ -1111,7 +1112,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size); dp->initialize(DataLayout::parameters_type_data_tag, 0, parms_cell); } else { - _parameters_type_data_di = -1; + _parameters_type_data_di = no_parameters; } // Set an initial hint. Don't use set_hint_di() because @@ -1236,7 +1237,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) { } ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) { - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); for (;; dp = next_extra(dp)) { assert(dp < end, "moved past end of extra data"); @@ -1285,7 +1286,7 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi "code needs to be adjusted"); DataLayout* dp = extra_data_base(); - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); // Allocation in the extra data space has to be atomic because not // all entries have the same size and non atomic concurrent @@ -1330,7 +1331,7 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi ArgInfoData *MethodData::arg_info() { DataLayout* dp = extra_data_base(); - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); for (; dp < end; dp = next_extra(dp)) { if (dp->tag() == DataLayout::arg_info_data_tag) return new ArgInfoData(dp); @@ -1357,7 +1358,7 @@ void MethodData::print_value_on(outputStream* st) const { void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); - if (_parameters_type_data_di != -1) { + if (_parameters_type_data_di != no_parameters) { parameters_type_data()->print_data_on(st); } for ( ; is_valid(data); data = next_data(data)) { @@ -1367,7 +1368,7 @@ void MethodData::print_data_on(outputStream* st) const { } st->print_cr("--- Extra data:"); DataLayout* dp = extra_data_base(); - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); for (;; dp = next_extra(dp)) { assert(dp < end, "moved past end of extra data"); // No need for "OrderAccess::load_acquire" ops, @@ -1565,7 +1566,7 @@ public: // redefined method void MethodData::clean_extra_data(CleanExtraDataClosure* cl) { DataLayout* dp = extra_data_base(); - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); int shift = 0; for (; dp < end; dp = next_extra(dp)) { @@ -1610,7 +1611,7 @@ void MethodData::clean_extra_data(CleanExtraDataClosure* cl) { void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) { #ifdef ASSERT DataLayout* dp = extra_data_base(); - DataLayout* end = extra_data_limit(); + DataLayout* end = args_data_limit(); for (; dp < end; dp = next_extra(dp)) { switch(dp->tag()) { diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index ad290402d90..edb82ae9ddb 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2107,7 +2107,12 @@ private: // data index for the area dedicated to parameters. -1 if no // parameter profiling. + enum { no_parameters = -2, parameters_uninitialized = -1 }; int _parameters_type_data_di; + int parameters_size_in_bytes() const { + ParametersTypeData* param = parameters_type_data(); + return param == NULL ? 0 : param->size_in_bytes(); + } // Beginning of the data entries intptr_t _data[1]; @@ -2130,7 +2135,7 @@ private: // Helper for data_at DataLayout* limit_data_position() const { - return (DataLayout*)((address)data_base() + _data_size); + return data_layout_at(_data_size); } bool out_of_bounds(int data_index) const { return data_index >= data_size(); @@ -2371,10 +2376,11 @@ public: } // Add a handful of extra data records, for trap tracking. - DataLayout* extra_data_base() const { return limit_data_position(); } + DataLayout* extra_data_base() const { return limit_data_position(); } DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); } - int extra_data_size() const { return (address)extra_data_limit() - - (address)extra_data_base(); } + DataLayout* args_data_limit() const { return (DataLayout*)((address)this + size_in_bytes() - + parameters_size_in_bytes()); } + int extra_data_size() const { return (address)extra_data_limit() - (address)extra_data_base(); } static DataLayout* next_extra(DataLayout* dp); // Return (uint)-1 for overflow. @@ -2429,11 +2435,12 @@ public: // Return pointer to area dedicated to parameters in MDO ParametersTypeData* parameters_type_data() const { - return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; + assert(_parameters_type_data_di != parameters_uninitialized, "called too early"); + return _parameters_type_data_di != no_parameters ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; } int parameters_type_data_di() const { - assert(_parameters_type_data_di != -1, "no args type data"); + assert(_parameters_type_data_di != parameters_uninitialized && _parameters_type_data_di != no_parameters, "no args type data"); return _parameters_type_data_di; } @@ -2480,8 +2487,8 @@ public: static bool profile_return_jsr292_only(); void clean_method_data(BoolObjectClosure* is_alive); - void clean_weak_method_links(); + Mutex* extra_data_lock() { return &_extra_data_lock; } }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index d745cbb022b..e4a5e20b43f 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -650,6 +650,9 @@ product(bool, UseMathExactIntrinsics, true, \ "Enables intrinsification of various java.lang.Math functions") \ \ + product(bool, UseMultiplyToLenIntrinsic, false, \ + "Enables intrinsification of BigInteger.multiplyToLen()") \ + \ product(bool, UseTypeSpeculation, true, \ "Speculatively propagate types from profiles") \ \ diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 04d91ff034a..ccf23118bb3 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -1830,8 +1830,8 @@ ArrayCopyNode* ArrayCopyNode::make(GraphKit* kit, bool may_throw, Node* dest, Node* dest_offset, Node* length, bool alloc_tightly_coupled, - Node* src_length, Node* dest_length, - Node* src_klass, Node* dest_klass) { + Node* src_klass, Node* dest_klass, + Node* src_length, Node* dest_length) { ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled); Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac); diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 2d6df8a5829..8c57610919d 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -1138,8 +1138,8 @@ public: Node* dest, Node* dest_offset, Node* length, bool alloc_tightly_coupled, - Node* src_length = NULL, Node* dest_length = NULL, - Node* src_klass = NULL, Node* dest_klass = NULL); + Node* src_klass = NULL, Node* dest_klass = NULL, + Node* src_length = NULL, Node* dest_length = NULL); void connect_outputs(GraphKit* kit); diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 5a98e8e254d..a84cd34474a 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -601,6 +601,10 @@ class Compile : public Phase { bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); } + template + bool method_has_option_value(const char * option, T& value) { + return method() != NULL && method()->has_option_value(option, value); + } #ifndef PRODUCT bool trace_opto_output() const { return _trace_opto_output; } bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; } diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index a4c84b63846..d32e83199c7 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -945,7 +945,8 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 || strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 || - strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0) + strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 || + strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0) ))) { call->dump(); fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name)); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 8339cce6ea4..9f60b701469 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -285,6 +285,7 @@ class LibraryCallKit : public GraphKit { bool inline_updateCRC32(); bool inline_updateBytesCRC32(); bool inline_updateByteBufferCRC32(); + bool inline_multiplyToLen(); }; @@ -293,8 +294,12 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { vmIntrinsics::ID id = m->intrinsic_id(); assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); - if (DisableIntrinsic[0] != '\0' - && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) { + ccstr disable_intr = NULL; + + if ((DisableIntrinsic[0] != '\0' + && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) || + (method_has_option_value("DisableIntrinsic", disable_intr) + && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)) { // disabled by a user request on the command line: // example: -XX:DisableIntrinsic=_hashCode,_getClass return NULL; @@ -477,6 +482,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { if (!UseAESIntrinsics) return NULL; break; + case vmIntrinsics::_multiplyToLen: + if (!UseMultiplyToLenIntrinsic) return NULL; + break; + case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: if (!UseAESIntrinsics) return NULL; @@ -836,7 +845,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: case vmIntrinsics::_getSuperclass: - case vmIntrinsics::_getComponentType: case vmIntrinsics::_getClassAccessFlags: return inline_native_Class_query(intrinsic_id()); case vmIntrinsics::_floatToRawIntBits: @@ -876,6 +884,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB(predicate); + case vmIntrinsics::_multiplyToLen: + return inline_multiplyToLen(); + case vmIntrinsics::_encodeISOArray: return inline_encodeISOArray(); @@ -3400,10 +3411,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { prim_return_value = null(); return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR); break; - case vmIntrinsics::_getComponentType: - prim_return_value = null(); - return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR); - break; case vmIntrinsics::_getClassAccessFlags: prim_return_value = intcon(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); return_type = TypeInt::INT; // not bool! 6297094 @@ -3520,17 +3527,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { } break; - case vmIntrinsics::_getComponentType: - if (generate_array_guard(kls, region) != NULL) { - // Be sure to pin the oop load to the guard edge just created: - Node* is_array_ctrl = region->in(region->req()-1); - Node* cma = basic_plus_adr(kls, in_bytes(ArrayKlass::component_mirror_offset())); - Node* cmo = make_load(is_array_ctrl, cma, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered); - phi->add_req(cmo); - } - query_value = null(); // non-array case is null - break; - case vmIntrinsics::_getClassAccessFlags: p = basic_plus_adr(kls, in_bytes(Klass::access_flags_offset())); query_value = make_load(NULL, p, TypeInt::INT, T_INT, MemNode::unordered); @@ -3859,7 +3855,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { Node* orig_tail = _gvn.transform(new SubINode(orig_length, start)); Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length); - newcopy = new_array(klass_node, length, 0); // no argments to push + newcopy = new_array(klass_node, length, 0); // no arguments to push // Generate a direct call to the right arraycopy function(s). // We know the copy is disjoint but we might not know if the @@ -3869,7 +3865,8 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { Node* alloc = tightly_coupled_allocation(newcopy, NULL); - ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL); + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL, + load_object_klass(original), klass_node); if (!is_copyOfRange) { ac->set_copyof(); } else { @@ -4792,8 +4789,8 @@ bool LibraryCallKit::inline_arraycopy() { // Create LoadRange and LoadKlass nodes for use during macro expansion here // so the compiler has a chance to eliminate them: during macro expansion, // we have to set their control (CastPP nodes are eliminated). - load_array_length(src), load_array_length(dest), - load_object_klass(src), load_object_klass(dest)); + load_object_klass(src), load_object_klass(dest), + load_array_length(src), load_array_length(dest)); if (notest) { ac->set_arraycopy_notest(); @@ -4924,6 +4921,106 @@ bool LibraryCallKit::inline_encodeISOArray() { return true; } +//-------------inline_multiplyToLen----------------------------------- +bool LibraryCallKit::inline_multiplyToLen() { + assert(UseMultiplyToLenIntrinsic, "not implementated on this platform"); + + address stubAddr = StubRoutines::multiplyToLen(); + if (stubAddr == NULL) { + return false; // Intrinsic's stub is not implemented on this platform + } + const char* stubName = "multiplyToLen"; + + assert(callee()->signature()->size() == 5, "multiplyToLen has 5 parameters"); + + Node* x = argument(1); + Node* xlen = argument(2); + Node* y = argument(3); + Node* ylen = argument(4); + Node* z = argument(5); + + const Type* x_type = x->Value(&_gvn); + const Type* y_type = y->Value(&_gvn); + const TypeAryPtr* top_x = x_type->isa_aryptr(); + const TypeAryPtr* top_y = y_type->isa_aryptr(); + if (top_x == NULL || top_x->klass() == NULL || + top_y == NULL || top_y->klass() == NULL) { + // failed array check + return false; + } + + BasicType x_elem = x_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + BasicType y_elem = y_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + if (x_elem != T_INT || y_elem != T_INT) { + return false; + } + + // Set the original stack and the reexecute bit for the interpreter to reexecute + // the bytecode that invokes BigInteger.multiplyToLen() if deoptimization happens + // on the return from z array allocation in runtime. + { PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + Node* x_start = array_element_address(x, intcon(0), x_elem); + Node* y_start = array_element_address(y, intcon(0), y_elem); + // 'x_start' points to x array + scaled xlen + // 'y_start' points to y array + scaled ylen + + // Allocate the result array + Node* zlen = _gvn.transform(new AddINode(xlen, ylen)); + Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT))); + + IdealKit ideal(this); + +#define __ ideal. + Node* one = __ ConI(1); + Node* zero = __ ConI(0); + IdealVariable need_alloc(ideal), z_alloc(ideal); __ declarations_done(); + __ set(need_alloc, zero); + __ set(z_alloc, z); + __ if_then(z, BoolTest::eq, null()); { + __ increment (need_alloc, one); + } __ else_(); { + // Update graphKit memory and control from IdealKit. + sync_kit(ideal); + Node* zlen_arg = load_array_length(z); + // Update IdealKit memory and control from graphKit. + __ sync_kit(this); + __ if_then(zlen_arg, BoolTest::lt, zlen); { + __ increment (need_alloc, one); + } __ end_if(); + } __ end_if(); + + __ if_then(__ value(need_alloc), BoolTest::ne, zero); { + // Update graphKit memory and control from IdealKit. + sync_kit(ideal); + Node * narr = new_array(klass_node, zlen, 1); + // Update IdealKit memory and control from graphKit. + __ sync_kit(this); + __ set(z_alloc, narr); + } __ end_if(); + + sync_kit(ideal); + z = __ value(z_alloc); + _gvn.set_type(z, TypeAryPtr::INTS); + // Final sync IdealKit and GraphKit. + final_sync(ideal); +#undef __ + + Node* z_start = array_element_address(z, intcon(0), T_INT); + + Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::multiplyToLen_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + x_start, xlen, y_start, ylen, z_start, zlen); + } // original reexecute is set back here + + C->set_has_split_ifs(true); // Has chance for split-if optimization + set_result(z); + return true; +} + + /** * Calculate CRC32 for byte. * int java.util.zip.CRC32.update(int crc, int b) diff --git a/hotspot/src/share/vm/opto/macroArrayCopy.cpp b/hotspot/src/share/vm/opto/macroArrayCopy.cpp index e2676651e5d..8b8a177d20c 100644 --- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp @@ -506,6 +506,8 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* Node* src_klass = ac->in(ArrayCopyNode::SrcKlass); Node* dest_klass = ac->in(ArrayCopyNode::DestKlass); + assert(src_klass != NULL && dest_klass != NULL, "should have klasses"); + // Generate the subtype check. // This might fold up statically, or then again it might not. // @@ -1209,6 +1211,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { // (7) src_offset + length must not exceed length of src. Node* alen = ac->in(ArrayCopyNode::SrcLen); + assert(alen != NULL, "need src len"); generate_limit_guard(&ctrl, src_offset, length, alen, @@ -1216,6 +1219,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { // (8) dest_offset + length must not exceed length of dest. alen = ac->in(ArrayCopyNode::DestLen); + assert(alen != NULL, "need dest len"); generate_limit_guard(&ctrl, dest_offset, length, alen, diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 694a1eccda6..3d8271dc92a 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1799,13 +1799,6 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { } const Type* aift = load_array_final_field(tkls, klass); if (aift != NULL) return aift; - if (tkls->offset() == in_bytes(ArrayKlass::component_mirror_offset()) - && klass->is_array_klass()) { - // The field is ArrayKlass::_component_mirror. Return its (constant) value. - // (Folds up aClassConstant.getComponentType, common in Arrays.copyOf.) - assert(Opcode() == Op_LoadP, "must load an oop from _component_mirror"); - return TypeInstPtr::make(klass->as_array_klass()->component_mirror()); - } if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) { // The field is Klass::_java_mirror. Return its (constant) value. // (Folds up the 2nd indirection in anObjConstant.getClass().) @@ -2200,18 +2193,15 @@ Node* LoadNode::klass_identity_common(PhaseTransform *phase ) { } // Simplify k.java_mirror.as_klass to plain k, where k is a Klass*. - // Simplify ak.component_mirror.array_klass to plain ak, ak an ArrayKlass. // See inline_native_Class_query for occurrences of these patterns. // Java Example: x.getClass().isAssignableFrom(y) - // Java Example: Array.newInstance(x.getClass().getComponentType(), n) // // This improves reflective code, often making the Class // mirror go completely dead. (Current exception: Class // mirrors may appear in debug info, but we could clean them out by // introducing a new debug info operator for Klass*.java_mirror). if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass() - && (offset == java_lang_Class::klass_offset_in_bytes() || - offset == java_lang_Class::array_klass_offset_in_bytes())) { + && offset == java_lang_Class::klass_offset_in_bytes()) { // We are loading a special hidden field from a Class mirror, // the field which points to its Klass or ArrayKlass metaobject. if (base->is_Load()) { @@ -2223,9 +2213,6 @@ Node* LoadNode::klass_identity_common(PhaseTransform *phase ) { && adr2->is_AddP() ) { int mirror_field = in_bytes(Klass::java_mirror_offset()); - if (offset == java_lang_Class::array_klass_offset_in_bytes()) { - mirror_field = in_bytes(ArrayKlass::component_mirror_offset()); - } if (tkls->offset() == mirror_field) { return adr2->in(AddPNode::Base); } @@ -2799,9 +2786,10 @@ bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* p assert(n->is_ClearArray(), "sanity"); intptr_t offset; AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset); - // This method is called only before Allocate nodes are expanded during - // macro nodes expansion. Before that ClearArray nodes are only generated - // in LibraryCallKit::generate_arraycopy() which follows allocations. + // This method is called only before Allocate nodes are expanded + // during macro nodes expansion. Before that ClearArray nodes are + // only generated in PhaseMacroExpand::generate_arraycopy() (before + // Allocate nodes are expanded) which follows allocations. assert(alloc != NULL, "should have allocation"); if (alloc->_idx == instance_id) { // Can not bypass initialization of the instance we are looking for. diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 3e063ae987e..2b0688a90b8 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -42,10 +42,14 @@ NodeHash::NodeHash(uint est_max_size) : _max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ), _a(Thread::current()->resource_area()), _table( NEW_ARENA_ARRAY( _a , Node* , _max ) ), // (Node**)_a->Amalloc(_max * sizeof(Node*)) ), - _inserts(0), _insert_limit( insert_limit() ), - _look_probes(0), _lookup_hits(0), _lookup_misses(0), + _inserts(0), _insert_limit( insert_limit() ) +#ifndef PRODUCT + ,_look_probes(0), _lookup_hits(0), _lookup_misses(0), + _delete_probes(0), _delete_hits(0), _delete_misses(0), _total_insert_probes(0), _total_inserts(0), - _insert_probes(0), _grows(0) { + _insert_probes(0), _grows(0) +#endif +{ // _sentinel must be in the current node space _sentinel = new ProjNode(NULL, TypeFunc::Control); memset(_table,0,sizeof(Node*)*_max); @@ -56,11 +60,14 @@ NodeHash::NodeHash(Arena *arena, uint est_max_size) : _max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ), _a(arena), _table( NEW_ARENA_ARRAY( _a , Node* , _max ) ), - _inserts(0), _insert_limit( insert_limit() ), - _look_probes(0), _lookup_hits(0), _lookup_misses(0), + _inserts(0), _insert_limit( insert_limit() ) +#ifndef PRODUCT + ,_look_probes(0), _lookup_hits(0), _lookup_misses(0), _delete_probes(0), _delete_hits(0), _delete_misses(0), _total_insert_probes(0), _total_inserts(0), - _insert_probes(0), _grows(0) { + _insert_probes(0), _grows(0) +#endif +{ // _sentinel must be in the current node space _sentinel = new ProjNode(NULL, TypeFunc::Control); memset(_table,0,sizeof(Node*)*_max); @@ -87,15 +94,15 @@ Node *NodeHash::hash_find( const Node *n ) { // ((Node*)n)->set_hash( n->hash() ); uint hash = n->hash(); if (hash == Node::NO_HASH) { - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); return NULL; } uint key = hash & (_max-1); uint stride = key | 0x01; - debug_only( _look_probes++ ); + NOT_PRODUCT( _look_probes++ ); Node *k = _table[key]; // Get hashed value if( !k ) { // ?Miss? - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); return NULL; // Miss! } @@ -108,16 +115,16 @@ Node *NodeHash::hash_find( const Node *n ) { if( n->in(i)!=k->in(i)) // Different inputs? goto collision; // "goto" is a speed hack... if( n->cmp(*k) ) { // Check for any special bits - debug_only( _lookup_hits++ ); + NOT_PRODUCT( _lookup_hits++ ); return k; // Hit! } } collision: - debug_only( _look_probes++ ); + NOT_PRODUCT( _look_probes++ ); key = (key + stride/*7*/) & (_max-1); // Stride through table with relative prime k = _table[key]; // Get hashed value if( !k ) { // ?Miss? - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); return NULL; // Miss! } } @@ -132,16 +139,16 @@ Node *NodeHash::hash_find_insert( Node *n ) { // n->set_hash( ); uint hash = n->hash(); if (hash == Node::NO_HASH) { - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); return NULL; } uint key = hash & (_max-1); uint stride = key | 0x01; // stride must be relatively prime to table siz uint first_sentinel = 0; // replace a sentinel if seen. - debug_only( _look_probes++ ); + NOT_PRODUCT( _look_probes++ ); Node *k = _table[key]; // Get hashed value if( !k ) { // ?Miss? - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); _table[key] = n; // Insert into table! debug_only(n->enter_hash_lock()); // Lock down the node while in the table. check_grow(); // Grow table if insert hit limit @@ -160,16 +167,16 @@ Node *NodeHash::hash_find_insert( Node *n ) { if( n->in(i)!=k->in(i)) // Different inputs? goto collision; // "goto" is a speed hack... if( n->cmp(*k) ) { // Check for any special bits - debug_only( _lookup_hits++ ); + NOT_PRODUCT( _lookup_hits++ ); return k; // Hit! } } collision: - debug_only( _look_probes++ ); + NOT_PRODUCT( _look_probes++ ); key = (key + stride) & (_max-1); // Stride through table w/ relative prime k = _table[key]; // Get hashed value if( !k ) { // ?Miss? - debug_only( _lookup_misses++ ); + NOT_PRODUCT( _lookup_misses++ ); key = (first_sentinel == 0) ? key : first_sentinel; // ?saw sentinel? _table[key] = n; // Insert into table! debug_only(n->enter_hash_lock()); // Lock down the node while in the table. @@ -200,7 +207,7 @@ void NodeHash::hash_insert( Node *n ) { uint stride = key | 0x01; while( 1 ) { // While probing hash table - debug_only( _insert_probes++ ); + NOT_PRODUCT( _insert_probes++ ); Node *k = _table[key]; // Get hashed value if( !k || (k == _sentinel) ) break; // Found a slot assert( k != n, "already inserted" ); @@ -218,7 +225,7 @@ bool NodeHash::hash_delete( const Node *n ) { Node *k; uint hash = n->hash(); if (hash == Node::NO_HASH) { - debug_only( _delete_misses++ ); + NOT_PRODUCT( _delete_misses++ ); return false; } uint key = hash & (_max-1); @@ -226,10 +233,10 @@ bool NodeHash::hash_delete( const Node *n ) { debug_only( uint counter = 0; ); for( ; /* (k != NULL) && (k != _sentinel) */; ) { debug_only( counter++ ); - debug_only( _delete_probes++ ); + NOT_PRODUCT( _delete_probes++ ); k = _table[key]; // Get hashed value if( !k ) { // Miss? - debug_only( _delete_misses++ ); + NOT_PRODUCT( _delete_misses++ ); #ifdef ASSERT if( VerifyOpto ) { for( uint i=0; i < _max; i++ ) @@ -239,7 +246,7 @@ bool NodeHash::hash_delete( const Node *n ) { return false; // Miss! Not in chain } else if( n == k ) { - debug_only( _delete_hits++ ); + NOT_PRODUCT( _delete_hits++ ); _table[key] = _sentinel; // Hit! Label as deleted entry debug_only(((Node*)n)->exit_hash_lock()); // Unlock the node upon removal from table. return true; @@ -271,11 +278,13 @@ void NodeHash::grow() { uint old_max = _max; Node **old_table = _table; // Construct new table with twice the space +#ifndef PRODUCT _grows++; _total_inserts += _inserts; _total_insert_probes += _insert_probes; - _inserts = 0; _insert_probes = 0; +#endif + _inserts = 0; _max = _max << 1; _table = NEW_ARENA_ARRAY( _a , Node* , _max ); // (Node**)_a->Amalloc( _max * sizeof(Node*) ); memset(_table,0,sizeof(Node*)*_max); diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index c3749dbcf70..a3e06c825a7 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -100,7 +100,6 @@ public: #ifndef PRODUCT Node *find_index(uint idx); // For debugging void dump(); // For debugging, dump statistics -#endif uint _grows; // For debugging, count of table grow()s uint _look_probes; // For debugging, count of hash probes uint _lookup_hits; // For debugging, count of hash_finds @@ -111,6 +110,7 @@ public: uint _delete_misses; // For debugging, count of hash probes for deletes uint _total_inserts; // For debugging, total inserts into hash table uint _total_insert_probes; // For debugging, total probes while inserting +#endif }; diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 0bf5c9da587..ece252c1af9 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -922,6 +922,30 @@ const TypeFunc* OptoRuntime::digestBase_implCompressMB_Type() { return TypeFunc::make(domain, range); } +const TypeFunc* OptoRuntime::multiplyToLen_Type() { + // create input type (domain) + int num_args = 6; + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // x + fields[argp++] = TypeInt::INT; // xlen + fields[argp++] = TypePtr::NOTNULL; // y + fields[argp++] = TypeInt::INT; // ylen + fields[argp++] = TypePtr::NOTNULL; // z + fields[argp++] = TypeInt::INT; // zlen + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // no result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = NULL; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); + return TypeFunc::make(domain, range); +} + + + //------------- Interpreter state access for on stack replacement const TypeFunc* OptoRuntime::osr_end_Type() { // create input type (domain) diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index 612afc58807..3257d789ad0 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -310,6 +310,8 @@ private: static const TypeFunc* sha_implCompress_Type(); static const TypeFunc* digestBase_implCompressMB_Type(); + static const TypeFunc* multiplyToLen_Type(); + static const TypeFunc* updateBytesCRC32_Type(); // leaf on stack replacement interpreter accessor types diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index aa28aca328a..1a51e80e00e 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1403,14 +1403,6 @@ JVM_QUICK_ENTRY(jboolean, JVM_IsPrimitiveClass(JNIEnv *env, jclass cls)) JVM_END -JVM_ENTRY(jclass, JVM_GetComponentType(JNIEnv *env, jclass cls)) - JVMWrapper("JVM_GetComponentType"); - oop mirror = JNIHandles::resolve_non_null(cls); - oop result = Reflection::array_component_type(mirror, CHECK_NULL); - return (jclass) JNIHandles::make_local(env, result); -JVM_END - - JVM_ENTRY(jint, JVM_GetClassModifiers(JNIEnv *env, jclass cls)) JVMWrapper("JVM_GetClassModifiers"); if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) { diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 016bed8875e..72278843ab2 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -483,9 +483,6 @@ JVM_IsArrayClass(JNIEnv *env, jclass cls); JNIEXPORT jboolean JNICALL JVM_IsPrimitiveClass(JNIEnv *env, jclass cls); -JNIEXPORT jclass JNICALL -JVM_GetComponentType(JNIEnv *env, jclass cls); - JNIEXPORT jint JNICALL JVM_GetClassModifiers(JNIEnv *env, jclass cls); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index f630d5d35cc..b94b7142b7e 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -191,7 +191,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // It is not guaranteed that we can get such information here only // by analyzing bytecode in deoptimized frames. This is why this flag // is set during method compilation (see Compile::Process_OopMap_Node()). - bool save_oop_result = chunk->at(0)->scope()->return_oop(); + // If the previous frame was popped, we don't have a result. + bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution(); Handle return_value; if (save_oop_result) { // Reallocation may trigger GC. If deoptimization happened on return from diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index cc35fea494b..42c9ed3e8ef 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -390,7 +390,7 @@ oop Reflection::array_component_type(oop mirror, TRAPS) { return NULL; } - oop result = ArrayKlass::cast(klass)->component_mirror(); + oop result = java_lang_Class::component_mirror(mirror); #ifdef ASSERT oop result2 = NULL; if (ArrayKlass::cast(klass)->dimension() == 1) { diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index 6febb5bcee9..f35cce9f5e9 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -135,6 +135,8 @@ address StubRoutines::_sha512_implCompressMB = NULL; address StubRoutines::_updateBytesCRC32 = NULL; address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_multiplyToLen = NULL; + double (* StubRoutines::_intrinsic_log )(double) = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; double (* StubRoutines::_intrinsic_exp )(double) = NULL; diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp index 46d93a52916..60f24843abf 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp @@ -202,6 +202,8 @@ class StubRoutines: AllStatic { static address _updateBytesCRC32; static address _crc_table_adr; + static address _multiplyToLen; + // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for // constant folding in the compiler to ensure equivalence. If the @@ -358,6 +360,8 @@ class StubRoutines: AllStatic { static address updateBytesCRC32() { return _updateBytesCRC32; } static address crc_table_addr() { return _crc_table_adr; } + static address multiplyToLen() {return _multiplyToLen; } + static address select_fill_function(BasicType t, bool aligned, const char* &name); static address zero_aligned_words() { return _zero_aligned_words; } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index aa6d5558f51..d3ad9bd9b88 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -274,7 +274,6 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \ volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \ nonstatic_field(ArrayKlass, _vtable_len, int) \ - nonstatic_field(ArrayKlass, _component_mirror, oop) \ nonstatic_field(CompiledICHolder, _holder_method, Method*) \ nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \ nonstatic_field(ConstantPool, _tags, Array*) \ @@ -811,6 +810,7 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ + static_field(StubRoutines, _multiplyToLen, address) \ \ /*****************/ \ /* SharedRuntime */ \ diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp index c0c73c425fc..85c8d5f26bb 100644 --- a/hotspot/src/share/vm/utilities/hashtable.cpp +++ b/hotspot/src/share/vm/utilities/hashtable.cpp @@ -37,21 +37,22 @@ #include "utilities/numberSeq.hpp" -// This is a generic hashtable, designed to be used for the symbol -// and string tables. -// -// It is implemented as an open hash table with a fixed number of buckets. -// -// %note: -// - HashtableEntrys are allocated in blocks to reduce the space overhead. +// This hashtable is implemented as an open hash table with a fixed number of buckets. -template BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) { - BasicHashtableEntry* entry; - - if (_free_list) { +template BasicHashtableEntry* BasicHashtable::new_entry_free_list() { + BasicHashtableEntry* entry = NULL; + if (_free_list != NULL) { entry = _free_list; _free_list = _free_list->next(); - } else { + } + return entry; +} + +// HashtableEntrys are allocated in blocks to reduce the space overhead. +template BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) { + BasicHashtableEntry* entry = new_entry_free_list(); + + if (entry == NULL) { if (_first_free_entry + _entry_size >= _end_block) { int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); int len = _entry_size * block_size; @@ -84,9 +85,9 @@ template HashtableEntry* Hashtable::new_entry( // This is somewhat an arbitrary heuristic but if one bucket gets to // rehash_count which is currently 100, there's probably something wrong. -template bool BasicHashtable::check_rehash_table(int count) { - assert(table_size() != 0, "underflow"); - if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) { +template bool RehashableHashtable::check_rehash_table(int count) { + assert(this->table_size() != 0, "underflow"); + if (count > (((double)this->number_of_entries()/(double)this->table_size())*rehash_multiple)) { // Set a flag for the next safepoint, which should be at some guaranteed // safepoint interval. return true; @@ -94,13 +95,13 @@ template bool BasicHashtable::check_rehash_table(int count) { return false; } -template juint Hashtable::_seed = 0; +template juint RehashableHashtable::_seed = 0; // Create a new table and using alternate hash code, populate the new table // with the existing elements. This can be used to change the hash code // and could in the future change the size of the table. -template void Hashtable::move_to(Hashtable* new_table) { +template void RehashableHashtable::move_to(RehashableHashtable* new_table) { // Initialize the global seed for hashing. _seed = AltHashing::compute_seed(); @@ -110,7 +111,7 @@ template void Hashtable::move_to(Hashtable* ne // Iterate through the table and create a new entry for the new table for (int i = 0; i < new_table->table_size(); ++i) { - for (HashtableEntry* p = bucket(i); p != NULL; ) { + for (HashtableEntry* p = this->bucket(i); p != NULL; ) { HashtableEntry* next = p->next(); T string = p->literal(); // Use alternate hashing algorithm on the symbol in the first table @@ -239,11 +240,11 @@ template void Hashtable::reverse(void* boundary) { } } -template int Hashtable::literal_size(Symbol *symbol) { +template int RehashableHashtable::literal_size(Symbol *symbol) { return symbol->size() * HeapWordSize; } -template int Hashtable::literal_size(oop oop) { +template int RehashableHashtable::literal_size(oop oop) { // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, // and the String.value array is shared by several Strings. However, starting from JDK8, // the String.value array is not shared anymore. @@ -256,12 +257,12 @@ template int Hashtable::literal_size(oop oop) { // Note: if you create a new subclass of Hashtable, you will need to // add a new function Hashtable::literal_size(MyNewType lit) -template void Hashtable::dump_table(outputStream* st, const char *table_name) { +template void RehashableHashtable::dump_table(outputStream* st, const char *table_name) { NumberSeq summary; int literal_bytes = 0; for (int i = 0; i < this->table_size(); ++i) { int count = 0; - for (HashtableEntry* e = bucket(i); + for (HashtableEntry* e = this->bucket(i); e != NULL; e = e->next()) { count++; literal_bytes += literal_size(e->literal()); @@ -271,7 +272,7 @@ template void Hashtable::dump_table(outputStream* st double num_buckets = summary.num(); double num_entries = summary.sum(); - int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); + int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket); int entry_bytes = (int)num_entries * sizeof(HashtableEntry); int total_bytes = literal_bytes + bucket_bytes + entry_bytes; @@ -354,12 +355,20 @@ template void BasicHashtable::verify_lookup_length(double load) // Explicitly instantiate these types +#if INCLUDE_ALL_GCS +template class Hashtable; +template class HashtableEntry; +template class BasicHashtable; +#endif template class Hashtable; +template class RehashableHashtable; +template class RehashableHashtable; template class Hashtable; template class Hashtable; template class Hashtable; #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) template class Hashtable; +template class RehashableHashtable; #endif // SOLARIS || CHECK_UNHANDLED_OOPS template class Hashtable; template class Hashtable; diff --git a/hotspot/src/share/vm/utilities/hashtable.hpp b/hotspot/src/share/vm/utilities/hashtable.hpp index fcebf72ea95..9546323b496 100644 --- a/hotspot/src/share/vm/utilities/hashtable.hpp +++ b/hotspot/src/share/vm/utilities/hashtable.hpp @@ -178,11 +178,6 @@ protected: void verify_lookup_length(double load); #endif - enum { - rehash_count = 100, - rehash_multiple = 60 - }; - void initialize(int table_size, int entry_size, int number_of_entries); // Accessor @@ -194,12 +189,12 @@ protected: // The following method is not MT-safe and must be done under lock. BasicHashtableEntry** bucket_addr(int i) { return _buckets[i].entry_addr(); } + // Attempt to get an entry from the free list + BasicHashtableEntry* new_entry_free_list(); + // Table entry management BasicHashtableEntry* new_entry(unsigned int hashValue); - // Check that the table is unbalanced - bool check_rehash_table(int count); - // Used when moving the entry to another table // Clean up links, but do not add to free_list void unlink_entry(BasicHashtableEntry* entry) { @@ -277,8 +272,30 @@ protected: return (HashtableEntry**)BasicHashtable::bucket_addr(i); } +}; + +template class RehashableHashtable : public Hashtable { + protected: + + enum { + rehash_count = 100, + rehash_multiple = 60 + }; + + // Check that the table is unbalanced + bool check_rehash_table(int count); + + public: + RehashableHashtable(int table_size, int entry_size) + : Hashtable(table_size, entry_size) { } + + RehashableHashtable(int table_size, int entry_size, + HashtableBucket* buckets, int number_of_entries) + : Hashtable(table_size, entry_size, buckets, number_of_entries) { } + + // Function to move these elements into the new table. - void move_to(Hashtable* new_table); + void move_to(RehashableHashtable* new_table); static bool use_alternate_hashcode() { return _seed != 0; } static juint seed() { return _seed; } @@ -292,7 +309,6 @@ protected: static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} static int literal_size(Klass *k) {Unimplemented(); return 0;} -public: void dump_table(outputStream* st, const char *table_name); private: diff --git a/hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java b/hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java new file mode 100644 index 00000000000..30e525e687e --- /dev/null +++ b/hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, 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 8055910 + * @summary Arrays.copyOf doesn't perform subtype check + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayOfNoTypeCheck + * + */ + +import java.util.Arrays; + +public class TestArrayOfNoTypeCheck { + + static class A { + } + + static class B extends A { + } + + static B[] test(A[] arr) { + return Arrays.copyOf(arr, 10, B[].class); + } + + static public void main(String[] args) { + A[] arr = new A[20]; + for (int i = 0; i < 20000; i++) { + test(arr); + } + A[] arr2 = new A[20]; + arr2[0] = new A(); + boolean exception = false; + try { + test(arr2); + } catch (ArrayStoreException ase) { + exception = true; + } + if (!exception) { + throw new RuntimeException("TEST FAILED: ArrayStoreException not thrown"); + } + } +} diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java index 7f70f1c2a70..e0010c2a8f1 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build AddExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class AddExactIntTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java index e577202a87a..38efa5d3867 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build AddExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class AddExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java index ae37263e52f..be55af8c02f 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build DecrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class DecrementExactIntTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java index 5e42bb1b16e..8a48401c712 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build DecrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class DecrementExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java index 32bf0c698ba..657a3f7723d 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build IncrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class IncrementExactIntTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java index b0f50869c70..7915f9fd028 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build IncrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class IncrementExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java index cecd6ce2d02..ba7506526da 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ import com.oracle.java.testlibrary.Platform; +import intrinsics.Verifier; import java.io.FileOutputStream; import java.lang.reflect.Executable; @@ -79,10 +80,10 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest { System.out.println("Expected intrinsic count is " + expectedIntrinsicCount + " name " + getIntrinsicId()); - final FileOutputStream out = new FileOutputStream(getVMOption("LogFile") + ".verify.properties"); + final FileOutputStream out = new FileOutputStream(getVMOption("LogFile") + Verifier.PROPERTY_FILE_SUFFIX); Properties expectedProps = new Properties(); - expectedProps.setProperty("intrinsic.name", getIntrinsicId()); - expectedProps.setProperty("intrinsic.expectedCount", String.valueOf(expectedIntrinsicCount)); + expectedProps.setProperty(Verifier.INTRINSIC_NAME_PROPERTY, getIntrinsicId()); + expectedProps.setProperty(Verifier.INTRINSIC_EXPECTED_COUNT_PROPERTY, String.valueOf(expectedIntrinsicCount)); expectedProps.store(out, null); out.close(); diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java index d565ce7c9bd..d192f66469a 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build MultiplyExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class MultiplyExactIntTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java index e7ac5303b5b..bbca388fc01 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build MultiplyExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class MultiplyExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java index 5aacf77dbba..a8a1def13b5 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build NegateExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class NegateExactIntTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java index 37d13a5823e..ebdbdcca07b 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build NegateExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class NegateExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java index 7cd22479131..e3f7c460de9 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build SubtractExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java index 4ab26097487..ddb28fc0ee4 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build SubtractExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission @@ -35,7 +36,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class SubtractExactLongTest { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/Verifier.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/Verifier.java deleted file mode 100644 index 7b26d64c648..00000000000 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/Verifier.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -import java.io.BufferedReader; -import java.io.FileReader; -import java.util.Properties; - -public class Verifier { - - public static void main(String[] args) throws Exception { - if (args.length == 0) - throw new RuntimeException("Test bug, nothing to verify"); - for (String hsLogFile : args) { - verify(hsLogFile); - } - } - - private static void verify(String hsLogFile) throws Exception { - System.out.println("Verifying " + hsLogFile); - - final Properties expectedProperties = new Properties(); - final FileReader reader = new FileReader(hsLogFile + ".verify.properties"); - expectedProperties.load(reader); - reader.close(); - - int fullMatchCnt = 0; - int suspectCnt = 0; - final String intrinsicId = expectedProperties.getProperty("intrinsic.name"); - final String prefix = " 0 && !isExpected)) { + throw new RuntimeException( + "Unexpected count of intrinsic " + + intrinsicID + + " is expected:" + isExpected + + ", matched: " + fullMatchCnt + + ", suspected: " + suspectCnt); + } + } + }; + + void verify(Properties expectedProperties, int fullMathCnt, + int suspectCnt) { + throw new RuntimeException("Default strategy is not implemented."); + } + } + + public static final String PROPERTY_FILE_SUFFIX = ".verify.properties"; + public static final String INTRINSIC_NAME_PROPERTY = "intrinsic.name"; + public static final String INTRINSIC_IS_EXPECTED_PROPERTY + = "intrinsic.expected"; + public static final String INTRINSIC_EXPECTED_COUNT_PROPERTY + = "intrinsic.expectedCount"; + private static final String DEFAULT_STRATEGY + = VerificationStrategy.VERIFY_STRONG_EQUALITY.name(); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + throw new RuntimeException("Test bug, nothing to verify"); + } + for (String hsLogFile : args) { + verify(hsLogFile); + } + } + + private static void verify(String hsLogFile) throws Exception { + System.out.println("Verifying " + hsLogFile); + + Properties expectedProperties = new Properties(); + FileReader reader = new FileReader(hsLogFile + + Verifier.PROPERTY_FILE_SUFFIX); + expectedProperties.load(reader); + reader.close(); + + int fullMatchCnt = 0; + int suspectCnt = 0; + String intrinsicId = expectedProperties.getProperty( + Verifier.INTRINSIC_NAME_PROPERTY); + String prefix = " { + boolean isTiered = IntrinsicPredicates.WHITE_BOX.getBooleanVMFlag( + "TieredCompilation"); + long tieredMaxLevel = IntrinsicPredicates.WHITE_BOX.getIntxVMFlag( + "TieredStopAtLevel"); + boolean maxLevelIsReachable = (tieredMaxLevel + == IntrinsicPredicates.TIERED_MAX_LEVEL); + return Platform.isServer() && (!isTiered || maxLevelIsReachable); + }; + + public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha1" }, + null); + + public static final BooleanSupplier SHA256_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha256" }, + null); + + public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha512" }, + null); + + public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE + = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, + new OrPredicate( + IntrinsicPredicates.SHA256_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.SHA512_INSTRUCTION_AVAILABLE)); + + public static final BooleanSupplier SHA1_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA1Intrinsics")); + + public static final BooleanSupplier SHA256_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA256_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA256Intrinsics")); + + public static final BooleanSupplier SHA512_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA512_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA512Intrinsics")); + + private static BooleanSupplier booleanOptionValue(String option) { + return () -> IntrinsicPredicates.WHITE_BOX.getBooleanVMFlag(option); + } + + private IntrinsicPredicates() { + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java index fa4b3636121..0211514e532 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -27,6 +27,7 @@ public class Platform { private static final String osName = System.getProperty("os.name"); private static final String dataModel = System.getProperty("sun.arch.data.model"); private static final String vmVersion = System.getProperty("java.vm.version"); + private static final String javaVersion = System.getProperty("java.version"); private static final String osArch = System.getProperty("os.arch"); private static final String vmName = System.getProperty("java.vm.name"); @@ -83,7 +84,8 @@ public class Platform { } public static boolean isDebugBuild() { - return vmVersion.toLowerCase().contains("debug"); + return (vmVersion.toLowerCase().contains("debug") || + javaVersion.toLowerCase().contains("debug")); } public static String getVMVersion() { diff --git a/jaxp/.hgignore b/jaxp/.hgignore index 970fc82946b..195f7dbfed1 100644 --- a/jaxp/.hgignore +++ b/jaxp/.hgignore @@ -2,6 +2,6 @@ ^dist/ ^drop/ ^drop_included/ -^webrev/ +^webrev /nbproject/private/ ^.hgtip diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 1f4c324b640..ea01e6ee220 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -272,3 +272,4 @@ a5aea8318ae4a9c2105228568688875142d70344 jdk9-b26 2bfaf29cc90b19948938e3ef1a0983eee68806c7 jdk9-b27 dc1e26434b3fd7e9b8eeab149103c1e30965f95c jdk9-b28 30adcd13a313ea91e81164801a2f89282756d933 jdk9-b29 +d181d4002214e4914d5525bd5ee13369311c765c jdk9-b30 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java index 28fbc69270e..58700e2934b 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java @@ -973,6 +973,7 @@ public abstract class XMLScanner fStringBuffer2.append('\n'); } } else if (c != -1 && XMLChar.isHighSurrogate(c)) { + fStringBuffer3.clear(); if (scanSurrogates(fStringBuffer3)) { stringBuffer.append(fStringBuffer3); if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Catalog.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Catalog.java index a5c0e683825..0e5cb5a3e3f 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Catalog.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Catalog.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// Catalog.java - Represents OASIS Open Catalog files. - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -25,28 +19,24 @@ package com.sun.org.apache.xml.internal.resolver; import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl; import com.sun.org.apache.xerces.internal.utils.SecuritySupport; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.io.DataInputStream; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -import java.net.URL; -import java.net.MalformedURLException; - -import javax.xml.parsers.SAXParserFactory; - -import com.sun.org.apache.xml.internal.resolver.CatalogManager; +import com.sun.org.apache.xml.internal.resolver.helpers.FileURL; import com.sun.org.apache.xml.internal.resolver.helpers.PublicId; import com.sun.org.apache.xml.internal.resolver.readers.CatalogReader; +import com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader; import com.sun.org.apache.xml.internal.resolver.readers.SAXCatalogReader; import com.sun.org.apache.xml.internal.resolver.readers.TR9401CatalogReader; -import com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader; -import com.sun.org.apache.xml.internal.resolver.helpers.FileURL; +import java.io.DataInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Vector; +import javax.xml.parsers.SAXParserFactory; /** * Represents OASIS Open Catalog files. @@ -154,8 +144,6 @@ import com.sun.org.apache.xml.internal.resolver.helpers.FileURL; * *

Additional catalogs may also be loaded with the * {@link #parseCatalog} method.

- * - * * *

Change Log:

*
@@ -823,7 +811,7 @@ public class Catalog { catalogCwd = FileURL.makeURL("basename"); } catch (MalformedURLException e) { String userdir = SecuritySupport.getSystemProperty("user.dir"); - userdir.replace('\\', '/'); + userdir = userdir.replace('\\', '/'); catalogManager.debug.message(1, "Malformed URL on cwd", userdir); catalogCwd = null; } @@ -2113,66 +2101,113 @@ public class Catalog { } } - /** - * Perform character normalization on a URI reference. - * - * @param uriref The URI reference - * @return The normalized URI reference. - */ - protected String normalizeURI(String uriref) { - if (uriref == null) { - return null; + + /** + * Perform character normalization on a URI reference. + * + * @param uriref The URI reference + * @return The normalized URI reference. + */ + protected String normalizeURI(String uriref) { + if (uriref == null) { + return null; + } + final int length = uriref.length(); + for (int i = 0; i < length; ++i) { + char c = uriref.charAt(i); + if ((c <= 0x20) // ctrl + || (c > 0x7F) // high ascii + || (c == 0x22) // " + || (c == 0x3C) // < + || (c == 0x3E) // > + || (c == 0x5C) // \ + || (c == 0x5E) // ^ + || (c == 0x60) // ` + || (c == 0x7B) // { + || (c == 0x7C) // | + || (c == 0x7D) // } + || (c == 0x7F)) { + return normalizeURI(uriref, i); + } + } + return uriref; } - byte[] bytes; - try { - bytes = uriref.getBytes("UTF-8"); - } catch (UnsupportedEncodingException uee) { - // this can't happen - catalogManager.debug.message(1, "UTF-8 is an unsupported encoding!?"); - return uriref; + /** + * Perform character normalization on a URI reference. + * + * @param uriref The URI reference + * @param index The index of the first character which requires escaping. + * @return The normalized URI reference. + */ + private String normalizeURI(String uriref, int index) { + final StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < index; ++i) { + buffer.append(uriref.charAt(i)); + } + final byte[] bytes; + try { + bytes = uriref.substring(index).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException uee) { + // this can't happen + catalogManager.debug.message(1, "UTF-8 is an unsupported encoding!?"); + return uriref; + } + for (int count = 0; count < bytes.length; ++count) { + int ch = bytes[count] & 0xFF; + if ((ch <= 0x20) // ctrl + || (ch > 0x7F) // high ascii + || (ch == 0x22) // " + || (ch == 0x3C) // < + || (ch == 0x3E) // > + || (ch == 0x5C) // \ + || (ch == 0x5E) // ^ + || (ch == 0x60) // ` + || (ch == 0x7B) // { + || (ch == 0x7C) // | + || (ch == 0x7D) // } + || (ch == 0x7F)) { + writeEncodedByte(ch, buffer); + } + else { + buffer.append((char) bytes[count]); + } + } + return buffer.toString(); } - StringBuilder newRef = new StringBuilder(bytes.length); - for (int count = 0; count < bytes.length; count++) { - int ch = bytes[count] & 0xFF; - - if ((ch <= 0x20) // ctrl - || (ch > 0x7F) // high ascii - || (ch == 0x22) // " - || (ch == 0x3C) // < - || (ch == 0x3E) // > - || (ch == 0x5C) // \ - || (ch == 0x5E) // ^ - || (ch == 0x60) // ` - || (ch == 0x7B) // { - || (ch == 0x7C) // | - || (ch == 0x7D) // } - || (ch == 0x7F)) { - newRef.append(encodedByte(ch)); - } else { - newRef.append((char) bytes[count]); - } + /** + * Perform %-encoding on a single byte. + * + * @param b The 8-bit integer that represents the byte. (Bytes are signed + * but encoding needs to look at the bytes unsigned.) + * @return The %-encoded string for the byte in question. + */ + protected String encodedByte(int b) { + StringBuilder buffer = new StringBuilder(3); + writeEncodedByte(b, buffer); + return buffer.toString(); } - return newRef.toString(); - } - - /** - * Perform %-encoding on a single byte. - * - * @param b The 8-bit integer that represents th byte. (Bytes are signed - but encoding needs to look at the bytes unsigned.) - * @return The %-encoded string for the byte in question. - */ - protected String encodedByte (int b) { - String hex = Integer.toHexString(b).toUpperCase(); - if (hex.length() < 2) { - return "%0" + hex; - } else { - return "%" + hex; + /** + * Perform %-encoding on a single byte. + * + * @param b The 8-bit integer that represents the byte. (Bytes are signed + * but encoding needs to look at the bytes unsigned.) + * @param buffer The target for the %-encoded string for the byte in question. + */ + private void writeEncodedByte(int b, StringBuilder buffer) { + String hex = Integer.toHexString(b).toUpperCase(Locale.ENGLISH); + if (hex.length() < 2) { + buffer.append("%0"); + buffer.append(hex); + } + else { + buffer.append('%'); + buffer.append(hex); + } } - } // ----------------------------------------------------------------- diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogEntry.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogEntry.java index 076e2f52b98..e90d8faa51c 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogEntry.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogEntry.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// CatalogEntry.java - Represents Catalog entries - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -53,18 +47,18 @@ import java.util.Vector; */ public class CatalogEntry { /** The nextEntry is the ordinal number of the next entry type. */ - protected static int nextEntry = 0; + static int nextEntry = 0; /** * The entryTypes vector maps catalog entry names * (e.g., 'BASE' or 'SYSTEM') to their type (1, 2, etc.). * Names are case sensitive. */ - protected static Hashtable entryTypes = new Hashtable(); + static final Hashtable entryTypes = new Hashtable(); /** The entryTypes vector maps catalog entry types to the number of arguments they're required to have. */ - protected static Vector entryArgs = new Vector(); + static final Vector entryArgs = new Vector(); /** * Adds a new catalog entry type. diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogException.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogException.java index c0b5404376c..1fc92db135b 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogException.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogException.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// CatalogException.java - Catalog exception - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -36,6 +30,9 @@ package com.sun.org.apache.xml.internal.resolver; * */ public class CatalogException extends Exception { + + private static final long serialVersionUID = 4007157171817798450L; + /** A wrapper around another exception */ public static final int WRAPPER = 1; /** An invalid entry */ @@ -56,8 +53,8 @@ public class CatalogException extends Exception { /** * The embedded exception if tunnelling, or null. */ - private Exception exception = null; - private int exceptionType = 0; + private final Exception exception; + private final int exceptionType; /** * Create a new CatalogException. diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogManager.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogManager.java index ab8cd27c647..b5fccbf04aa 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogManager.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/CatalogManager.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// CatalogManager.java - Access CatalogManager.properties - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -124,78 +118,78 @@ import sun.reflect.misc.ReflectUtil; */ public class CatalogManager { - private static String pFiles = "xml.catalog.files"; - private static String pVerbosity = "xml.catalog.verbosity"; - private static String pPrefer = "xml.catalog.prefer"; - private static String pStatic = "xml.catalog.staticCatalog"; - private static String pAllowPI = "xml.catalog.allowPI"; - private static String pClassname = "xml.catalog.className"; - private static String pIgnoreMissing = "xml.catalog.ignoreMissing"; + private static final String pFiles = "xml.catalog.files"; + private static final String pVerbosity = "xml.catalog.verbosity"; + private static final String pPrefer = "xml.catalog.prefer"; + private static final String pStatic = "xml.catalog.staticCatalog"; + private static final String pAllowPI = "xml.catalog.allowPI"; + private static final String pClassname = "xml.catalog.className"; + private static final String pIgnoreMissing = "xml.catalog.ignoreMissing"; - /** A static CatalogManager instance for sharing */ - private static CatalogManager staticManager = new CatalogManager(); + /** A static CatalogManager instance for sharing */ + private static final CatalogManager staticManager = new CatalogManager(); - /** The bootstrap resolver to use when loading XML Catalogs. */ - private BootstrapResolver bResolver = new BootstrapResolver(); + /** The bootstrap resolver to use when loading XML Catalogs. */ + private BootstrapResolver bResolver = new BootstrapResolver(); - /** Flag to ignore missing property files and/or properties */ - private boolean ignoreMissingProperties + /** Flag to ignore missing property files and/or properties */ + private boolean ignoreMissingProperties = (SecuritySupport.getSystemProperty(pIgnoreMissing) != null - || SecuritySupport.getSystemProperty(pFiles) != null); + || SecuritySupport.getSystemProperty(pFiles) != null); - /** Holds the resources after they are loaded from the file. */ - private ResourceBundle resources; + /** Holds the resources after they are loaded from the file. */ + private ResourceBundle resources; - /** The name of the CatalogManager properties file. */ - private String propertyFile = "CatalogManager.properties"; + /** The name of the CatalogManager properties file. */ + private String propertyFile = "CatalogManager.properties"; - /** The location of the propertyFile */ - private URL propertyFileURI = null; + /** The location of the propertyFile */ + private URL propertyFileURI = null; - /** Default catalog files list. */ - private String defaultCatalogFiles = "./xcatalog"; + /** Default catalog files list. */ + private String defaultCatalogFiles = "./xcatalog"; - /** Current catalog files list. */ - private String catalogFiles = null; + /** Current catalog files list. */ + private String catalogFiles = null; - /** Did the catalogFiles come from the properties file? */ - private boolean fromPropertiesFile = false; + /** Did the catalogFiles come from the properties file? */ + private boolean fromPropertiesFile = false; - /** Default verbosity level if there is no property setting for it. */ - private int defaultVerbosity = 1; + /** Default verbosity level if there is no property setting for it. */ + private int defaultVerbosity = 1; - /** Current verbosity level. */ - private Integer verbosity = null; + /** Current verbosity level. */ + private Integer verbosity = null; - /** Default preference setting. */ - private boolean defaultPreferPublic = true; + /** Default preference setting. */ + private boolean defaultPreferPublic = true; - /** Current preference setting. */ - private Boolean preferPublic = null; + /** Current preference setting. */ + private Boolean preferPublic = null; - /** Default setting of the static catalog flag. */ - private boolean defaultUseStaticCatalog = true; + /** Default setting of the static catalog flag. */ + private boolean defaultUseStaticCatalog = true; - /** Current setting of the static catalog flag. */ - private Boolean useStaticCatalog = null; + /** Current setting of the static catalog flag. */ + private Boolean useStaticCatalog = null; - /** The static catalog used by this manager. */ - private static Catalog staticCatalog = null; + /** The static catalog used by this manager. */ + private static volatile Catalog staticCatalog = null; - /** Default setting of the oasisXMLCatalogPI flag. */ - private boolean defaultOasisXMLCatalogPI = true; + /** Default setting of the oasisXMLCatalogPI flag. */ + private boolean defaultOasisXMLCatalogPI = true; - /** Current setting of the oasisXMLCatalogPI flag. */ - private Boolean oasisXMLCatalogPI = null; + /** Current setting of the oasisXMLCatalogPI flag. */ + private Boolean oasisXMLCatalogPI = null; - /** Default setting of the relativeCatalogs flag. */ - private boolean defaultRelativeCatalogs = true; + /** Default setting of the relativeCatalogs flag. */ + private boolean defaultRelativeCatalogs = true; - /** Current setting of the relativeCatalogs flag. */ - private Boolean relativeCatalogs = null; + /** Current setting of the relativeCatalogs flag. */ + private Boolean relativeCatalogs = null; - /** Current catalog class name. */ - private String catalogClassName = null; + /** Current catalog class name. */ + private String catalogClassName = null; /** * Indicates whether implementation parts should use * service loader (or similar). @@ -203,26 +197,26 @@ public class CatalogManager { */ private boolean useServicesMechanism; - /** The manager's debug object. Used for printing debugging messages. - * - *

This field is public so that objects that have access to this - * CatalogManager can use this debug object.

- */ - public Debug debug = null; + /** The manager's debug object. Used for printing debugging messages. + * + *

This field is public so that objects that have access to this + * CatalogManager can use this debug object.

+ */ + public Debug debug = null; - /** Constructor. */ - public CatalogManager() { - init(); - } + /** Constructor. */ + public CatalogManager() { + init(); + } - /** Constructor that specifies an explicit property file. */ - public CatalogManager(String propertyFile) { - this.propertyFile = propertyFile; - init(); + /** Constructor that specifies an explicit property file. */ + public CatalogManager(String propertyFile) { + this.propertyFile = propertyFile; + init(); } private void init() { - debug = new Debug(); + debug = new Debug(); // Note that we don't setDebug() here; we do that lazily. Either the // user will set it explicitly, or we'll do it automagically if they // read from the propertyFile for some other reason. That way, there's @@ -231,616 +225,638 @@ public class CatalogManager { if (System.getSecurityManager() == null) { useServicesMechanism = true; } - } - /** Set the bootstrap resolver.*/ - public void setBootstrapResolver(BootstrapResolver resolver) { - bResolver = resolver; - } + // Make sure verbosity is set by xml.catalog.verbosity sysprop + // setting, if defined. + queryVerbosityFromSysProp(); + } - /** Get the bootstrap resolver.*/ - public BootstrapResolver getBootstrapResolver() { - return bResolver; - } + /** Set the bootstrap resolver + * @param resolver the bootstrap resolver + */ + public void setBootstrapResolver(BootstrapResolver resolver) { + bResolver = resolver; + } - /** - * Load the properties from the propertyFile and build the - * resources from it. - */ - private synchronized void readProperties() { - try { - propertyFileURI = CatalogManager.class.getResource("/"+propertyFile); - InputStream in = - CatalogManager.class.getResourceAsStream("/"+propertyFile); - if (in==null) { - if (!ignoreMissingProperties) { - System.err.println("Cannot find "+propertyFile); - // there's no reason to give this warning more than once - ignoreMissingProperties = true; + /** Get the bootstrap resolver + * @return the bootstrap resolver + */ + public BootstrapResolver getBootstrapResolver() { + return bResolver; + } + + /** Query system property for verbosity level. */ + private void queryVerbosityFromSysProp() { + String verbStr = SecuritySupport.getSystemProperty(pVerbosity); + if (verbStr != null) { + try { + int verb = Integer.parseInt(verbStr.trim()); + verbosity = new Integer(verb); + debug.setDebug(verb); + } catch (Exception e) { + System.err.println("Cannot parse verbosity: \"" + verbStr + "\""); + } } - return; - } - resources = new PropertyResourceBundle(in); - } catch (MissingResourceException mre) { - if (!ignoreMissingProperties) { - System.err.println("Cannot read "+propertyFile); - } - } catch (java.io.IOException e) { - if (!ignoreMissingProperties) { - System.err.println("Failure trying to read "+propertyFile); - } } - // This is a bit of a hack. After we've successfully read the properties, - // use them to set the default debug level, if the user hasn't already set - // the default debug level. - if (verbosity == null) { - try { - String verbStr = resources.getString("verbosity"); - int verb = Integer.parseInt(verbStr.trim()); - debug.setDebug(verb); - verbosity = new Integer(verb); - } catch (Exception e) { - // nop - } - } - } - - /** - * Allow access to the static CatalogManager - */ - public static CatalogManager getStaticManager() { - return staticManager; - } - - /** - * How are missing properties handled? - * - *

If true, missing or unreadable property files will - * not be reported. Otherwise, a message will be sent to System.err. - *

- */ - public boolean getIgnoreMissingProperties() { - return ignoreMissingProperties; - } - - /** - * How should missing properties be handled? - * - *

If ignore is true, missing or unreadable property files will - * not be reported. Otherwise, a message will be sent to System.err. - *

- */ - public void setIgnoreMissingProperties(boolean ignore) { - ignoreMissingProperties = ignore; - } - - /** - * How are missing properties handled? - * - *

If ignore is true, missing or unreadable property files will - * not be reported. Otherwise, a message will be sent to System.err. - *

- * - * @deprecated No longer static; use get/set methods. - */ - public void ignoreMissingProperties(boolean ignore) { - setIgnoreMissingProperties(ignore); - } - - /** - * Obtain the verbosity setting from the properties. - * - * @return The verbosity level from the propertyFile or the - * defaultVerbosity. - */ - private int queryVerbosity () { - String defaultVerbStr = Integer.toString(defaultVerbosity); - - String verbStr = SecuritySupport.getSystemProperty(pVerbosity); - - if (verbStr == null) { - if (resources==null) readProperties(); - if (resources != null) { + /** + * Load the properties from the propertyFile and build the + * resources from it. + */ + private synchronized void readProperties() { try { - verbStr = resources.getString("verbosity"); + propertyFileURI = CatalogManager.class.getResource("/"+propertyFile); + InputStream in = + CatalogManager.class.getResourceAsStream("/"+propertyFile); + if (in==null) { + if (!ignoreMissingProperties) { + System.err.println("Cannot find "+propertyFile); + // there's no reason to give this warning more than once + ignoreMissingProperties = true; + } + return; + } + resources = new PropertyResourceBundle(in); + } catch (MissingResourceException mre) { + if (!ignoreMissingProperties) { + System.err.println("Cannot read "+propertyFile); + } + } catch (java.io.IOException e) { + if (!ignoreMissingProperties) { + System.err.println("Failure trying to read "+propertyFile); + } + } + + // This is a bit of a hack. After we've successfully read the properties, + // use them to set the default debug level, if the user hasn't already set + // the default debug level. + if (verbosity == null) { + try { + String verbStr = resources.getString("verbosity"); + int verb = Integer.parseInt(verbStr.trim()); + debug.setDebug(verb); + verbosity = new Integer(verb); + } catch (Exception e) { + // nop + } + } + } + + /** + * Allow access to the static CatalogManager + */ + public static CatalogManager getStaticManager() { + return staticManager; + } + + /** + * How are missing properties handled? + * + *

If true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ */ + public boolean getIgnoreMissingProperties() { + return ignoreMissingProperties; + } + + /** + * How should missing properties be handled? + * + *

If ignore is true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ */ + public void setIgnoreMissingProperties(boolean ignore) { + ignoreMissingProperties = ignore; + } + + /** + * How are missing properties handled? + * + *

If ignore is true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ * + * @deprecated No longer static; use get/set methods. + */ + public void ignoreMissingProperties(boolean ignore) { + setIgnoreMissingProperties(ignore); + } + + /** + * Obtain the verbosity setting from the properties. + * + * @return The verbosity level from the propertyFile or the + * defaultVerbosity. + */ + private int queryVerbosity () { + String defaultVerbStr = Integer.toString(defaultVerbosity); + + String verbStr = SecuritySupport.getSystemProperty(pVerbosity); + + if (verbStr == null) { + if (resources==null) readProperties(); + if (resources != null) { + try { + verbStr = resources.getString("verbosity"); + } catch (MissingResourceException e) { + verbStr = defaultVerbStr; + } + } else { + verbStr = defaultVerbStr; + } + } + + int verb = defaultVerbosity; + + try { + verb = Integer.parseInt(verbStr.trim()); + } catch (Exception e) { + System.err.println("Cannot parse verbosity: \"" + verbStr + "\""); + } + + // This is a bit of a hack. After we've successfully got the verbosity, + // we have to use it to set the default debug level, + // if the user hasn't already set the default debug level. + if (verbosity == null) { + debug.setDebug(verb); + verbosity = new Integer(verb); + } + + return verb; + } + + /** + * What is the current verbosity? + */ + public int getVerbosity() { + if (verbosity == null) { + verbosity = new Integer(queryVerbosity()); + } + + return verbosity.intValue(); + } + + /** + * Set the current verbosity. + */ + public void setVerbosity (int verbosity) { + this.verbosity = new Integer(verbosity); + debug.setDebug(verbosity); + } + + /** + * What is the current verbosity? + * + * @deprecated No longer static; use get/set methods. + */ + public int verbosity () { + return getVerbosity(); + } + + /** + * Obtain the relativeCatalogs setting from the properties. + * + * @return The relativeCatalogs setting from the propertyFile or the + * defaultRelativeCatalogs. + */ + private boolean queryRelativeCatalogs () { + if (resources==null) readProperties(); + + if (resources==null) return defaultRelativeCatalogs; + + try { + String allow = resources.getString("relative-catalogs"); + return (allow.equalsIgnoreCase("true") + || allow.equalsIgnoreCase("yes") + || allow.equalsIgnoreCase("1")); } catch (MissingResourceException e) { - verbStr = defaultVerbStr; + return defaultRelativeCatalogs; } - } else { - verbStr = defaultVerbStr; - } } - int verb = defaultVerbosity; - - try { - verb = Integer.parseInt(verbStr.trim()); - } catch (Exception e) { - System.err.println("Cannot parse verbosity: \"" + verbStr + "\""); - } - - // This is a bit of a hack. After we've successfully got the verbosity, - // we have to use it to set the default debug level, - // if the user hasn't already set the default debug level. - if (verbosity == null) { - debug.setDebug(verb); - verbosity = new Integer(verb); - } - - return verb; - } - - /** - * What is the current verbosity? - */ - public int getVerbosity() { - if (verbosity == null) { - verbosity = new Integer(queryVerbosity()); - } - - return verbosity.intValue(); - } - - /** - * Set the current verbosity. - */ - public void setVerbosity (int verbosity) { - this.verbosity = new Integer(verbosity); - debug.setDebug(verbosity); - } - - /** - * What is the current verbosity? - * - * @deprecated No longer static; use get/set methods. - */ - public int verbosity () { - return getVerbosity(); - } - - /** - * Obtain the relativeCatalogs setting from the properties. - * - * @return The relativeCatalogs setting from the propertyFile or the - * defaultRelativeCatalogs. - */ - private boolean queryRelativeCatalogs () { - if (resources==null) readProperties(); - - if (resources==null) return defaultRelativeCatalogs; - - try { - String allow = resources.getString("relative-catalogs"); - return (allow.equalsIgnoreCase("true") - || allow.equalsIgnoreCase("yes") - || allow.equalsIgnoreCase("1")); - } catch (MissingResourceException e) { - return defaultRelativeCatalogs; - } - } - - /** - * Get the relativeCatalogs setting. - * - *

This property is used when the catalogFiles property is - * interrogated. If true, then relative catalog entry file names - * are returned. If false, relative catalog entry file names are - * made absolute with respect to the properties file before returning - * them.

- * - *

This property only applies when the catalog files - * come from a properties file. If they come from a system property or - * the default list, they are never considered relative. (What would - * they be relative to?)

- * - *

In the properties, a value of 'yes', 'true', or '1' is considered - * true, anything else is false.

- * - * @return The relativeCatalogs setting from the propertyFile or the - * defaultRelativeCatalogs. - */ - public boolean getRelativeCatalogs () { - if (relativeCatalogs == null) { - relativeCatalogs = new Boolean(queryRelativeCatalogs()); - } - - return relativeCatalogs.booleanValue(); - } - - /** - * Set the relativeCatalogs setting. - * - * @see #getRelativeCatalogs() - */ - public void setRelativeCatalogs (boolean relative) { - relativeCatalogs = new Boolean(relative); - } - - /** - * Get the relativeCatalogs setting. - * - * @deprecated No longer static; use get/set methods. - */ - public boolean relativeCatalogs () { - return getRelativeCatalogs(); - } - - /** - * Obtain the list of catalog files from the properties. - * - * @return A semicolon delimited list of catlog file URIs - */ - private String queryCatalogFiles () { - String catalogList = SecuritySupport.getSystemProperty(pFiles); - fromPropertiesFile = false; - - if (catalogList == null) { - if (resources == null) readProperties(); - if (resources != null) { - try { - catalogList = resources.getString("catalogs"); - fromPropertiesFile = true; - } catch (MissingResourceException e) { - System.err.println(propertyFile + ": catalogs not found."); - catalogList = null; + /** + * Get the relativeCatalogs setting. + * + *

This property is used when the catalogFiles property is + * interrogated. If true, then relative catalog entry file names + * are returned. If false, relative catalog entry file names are + * made absolute with respect to the properties file before returning + * them.

+ * + *

This property only applies when the catalog files + * come from a properties file. If they come from a system property or + * the default list, they are never considered relative. (What would + * they be relative to?)

+ * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The relativeCatalogs setting from the propertyFile or the + * defaultRelativeCatalogs. + */ + public boolean getRelativeCatalogs () { + if (relativeCatalogs == null) { + relativeCatalogs = queryRelativeCatalogs() ? Boolean.TRUE : Boolean.FALSE; } - } + + return relativeCatalogs.booleanValue(); } - if (catalogList == null) { - catalogList = defaultCatalogFiles; + /** + * Set the relativeCatalogs setting. + * + * @see #getRelativeCatalogs() + */ + public void setRelativeCatalogs (boolean relative) { + relativeCatalogs = relative ? Boolean.TRUE : Boolean.FALSE; } - return catalogList; - } - - /** - * Return the current list of catalog files. - * - * @return A vector of the catalog file names or null if no catalogs - * are available in the properties. - */ - public Vector getCatalogFiles() { - if (catalogFiles == null) { - catalogFiles = queryCatalogFiles(); + /** + * Get the relativeCatalogs setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean relativeCatalogs () { + return getRelativeCatalogs(); } - StringTokenizer files = new StringTokenizer(catalogFiles, ";"); - Vector catalogs = new Vector(); - while (files.hasMoreTokens()) { - String catalogFile = files.nextToken(); - URL absURI = null; + /** + * Obtain the list of catalog files from the properties. + * + * @return A semicolon delimited list of catlog file URIs + */ + private String queryCatalogFiles () { + String catalogList = SecuritySupport.getSystemProperty(pFiles); + fromPropertiesFile = false; - if (fromPropertiesFile && !relativeCatalogs()) { - try { - absURI = new URL(propertyFileURI, catalogFile); - catalogFile = absURI.toString(); - } catch (MalformedURLException mue) { - absURI = null; + if (catalogList == null) { + if (resources == null) readProperties(); + if (resources != null) { + try { + catalogList = resources.getString("catalogs"); + fromPropertiesFile = true; + } catch (MissingResourceException e) { + System.err.println(propertyFile + ": catalogs not found."); + catalogList = null; + } + } } - } - catalogs.add(catalogFile); + if (catalogList == null) { + catalogList = defaultCatalogFiles; + } + + return catalogList; } - return catalogs; - } + /** + * Return the current list of catalog files. + * + * @return A vector of the catalog file names or null if no catalogs + * are available in the properties. + */ + public Vector getCatalogFiles() { + if (catalogFiles == null) { + catalogFiles = queryCatalogFiles(); + } - /** - * Set the list of catalog files. - */ - public void setCatalogFiles(String fileList) { - catalogFiles = fileList; - fromPropertiesFile = false; - } + StringTokenizer files = new StringTokenizer(catalogFiles, ";"); + Vector catalogs = new Vector(); + while (files.hasMoreTokens()) { + String catalogFile = files.nextToken(); + URL absURI = null; - /** - * Return the current list of catalog files. - * - * @return A vector of the catalog file names or null if no catalogs - * are available in the properties. - * - * @deprecated No longer static; use get/set methods. - */ - public Vector catalogFiles() { - return getCatalogFiles(); - } + if (fromPropertiesFile && !relativeCatalogs()) { + try { + absURI = new URL(propertyFileURI, catalogFile); + catalogFile = absURI.toString(); + } catch (MalformedURLException mue) { + absURI = null; + } + } - /** - * Obtain the preferPublic setting from the properties. - * - *

In the properties, a value of 'public' is true, - * anything else is false.

- * - * @return True if prefer is public or the - * defaultPreferSetting. - */ - private boolean queryPreferPublic () { - String prefer = SecuritySupport.getSystemProperty(pPrefer); + catalogs.add(catalogFile); + } - if (prefer == null) { - if (resources==null) readProperties(); - if (resources==null) return defaultPreferPublic; - try { - prefer = resources.getString("prefer"); - } catch (MissingResourceException e) { - return defaultPreferPublic; - } + return catalogs; } - if (prefer == null) { - return defaultPreferPublic; + /** + * Set the list of catalog files. + */ + public void setCatalogFiles(String fileList) { + catalogFiles = fileList; + fromPropertiesFile = false; } - return (prefer.equalsIgnoreCase("public")); - } - - /** - * Return the current prefer public setting. - * - * @return True if public identifiers are preferred. - */ - public boolean getPreferPublic () { - if (preferPublic == null) { - preferPublic = new Boolean(queryPreferPublic()); - } - return preferPublic.booleanValue(); - } - - /** - * Set the prefer public setting. - */ - public void setPreferPublic (boolean preferPublic) { - this.preferPublic = new Boolean(preferPublic); - } - - /** - * Return the current prefer public setting. - * - * @return True if public identifiers are preferred. - * - * @deprecated No longer static; use get/set methods. - */ - public boolean preferPublic () { - return getPreferPublic(); - } - - /** - * Obtain the static-catalog setting from the properties. - * - *

In the properties, a value of 'yes', 'true', or '1' is considered - * true, anything else is false.

- * - * @return The static-catalog setting from the propertyFile or the - * defaultUseStaticCatalog. - */ - private boolean queryUseStaticCatalog () { - String staticCatalog = SecuritySupport.getSystemProperty(pStatic); - - if (staticCatalog == null) { - if (resources==null) readProperties(); - if (resources==null) return defaultUseStaticCatalog; - try { - staticCatalog = resources.getString("static-catalog"); - } catch (MissingResourceException e) { - return defaultUseStaticCatalog; - } + /** + * Return the current list of catalog files. + * + * @return A vector of the catalog file names or null if no catalogs + * are available in the properties. + * + * @deprecated No longer static; use get/set methods. + */ + public Vector catalogFiles() { + return getCatalogFiles(); } - if (staticCatalog == null) { - return defaultUseStaticCatalog; + /** + * Obtain the preferPublic setting from the properties. + * + *

In the properties, a value of 'public' is true, + * anything else is false.

+ * + * @return True if prefer is public or the + * defaultPreferSetting. + */ + private boolean queryPreferPublic () { + String prefer = SecuritySupport.getSystemProperty(pPrefer); + + if (prefer == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultPreferPublic; + try { + prefer = resources.getString("prefer"); + } catch (MissingResourceException e) { + return defaultPreferPublic; + } + } + + if (prefer == null) { + return defaultPreferPublic; + } + + return (prefer.equalsIgnoreCase("public")); } - return (staticCatalog.equalsIgnoreCase("true") - || staticCatalog.equalsIgnoreCase("yes") - || staticCatalog.equalsIgnoreCase("1")); - } - - /** - * Get the current use static catalog setting. - */ - public boolean getUseStaticCatalog() { - if (useStaticCatalog == null) { - useStaticCatalog = new Boolean(queryUseStaticCatalog()); + /** + * Return the current prefer public setting. + * + * @return True if public identifiers are preferred. + */ + public boolean getPreferPublic () { + if (preferPublic == null) { + preferPublic = queryPreferPublic() ? Boolean.TRUE : Boolean.FALSE; + } + return preferPublic.booleanValue(); } - return useStaticCatalog.booleanValue(); - } - - /** - * Set the use static catalog setting. - */ - public void setUseStaticCatalog(boolean useStatic) { - useStaticCatalog = new Boolean(useStatic); - } - - /** - * Get the current use static catalog setting. - * - * @deprecated No longer static; use get/set methods. - */ - public boolean staticCatalog() { - return getUseStaticCatalog(); - } - - /** - * Get a new catalog instance. - * - * This method always returns a new instance of the underlying catalog class. - */ - public Catalog getPrivateCatalog() { - Catalog catalog = staticCatalog; - - if (useStaticCatalog == null) { - useStaticCatalog = new Boolean(getUseStaticCatalog()); + /** + * Set the prefer public setting. + */ + public void setPreferPublic (boolean preferPublic) { + this.preferPublic = preferPublic ? Boolean.TRUE : Boolean.FALSE; } - if (catalog == null || !useStaticCatalog.booleanValue()) { + /** + * Return the current prefer public setting. + * + * @return True if public identifiers are preferred. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean preferPublic () { + return getPreferPublic(); + } - try { - String catalogClassName = getCatalogClassName(); + /** + * Obtain the static-catalog setting from the properties. + * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The static-catalog setting from the propertyFile or the + * defaultUseStaticCatalog. + */ + private boolean queryUseStaticCatalog () { + String staticCatalog = SecuritySupport.getSystemProperty(pStatic); + if (staticCatalog == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultUseStaticCatalog; + try { + staticCatalog = resources.getString("static-catalog"); + } catch (MissingResourceException e) { + return defaultUseStaticCatalog; + } + } + + if (staticCatalog == null) { + return defaultUseStaticCatalog; + } + + return (staticCatalog.equalsIgnoreCase("true") + || staticCatalog.equalsIgnoreCase("yes") + || staticCatalog.equalsIgnoreCase("1")); + } + + /** + * Get the current use static catalog setting. + */ + public boolean getUseStaticCatalog() { + if (useStaticCatalog == null) { + useStaticCatalog = queryUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE; + } + + return useStaticCatalog.booleanValue(); + } + + /** + * Set the use static catalog setting. + */ + public void setUseStaticCatalog(boolean useStatic) { + useStaticCatalog = useStatic ? Boolean.TRUE : Boolean.FALSE; + } + + /** + * Get the current use static catalog setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean staticCatalog() { + return getUseStaticCatalog(); + } + + /** + * Get a new catalog instance. + * + * This method always returns a new instance of the underlying catalog class. + */ + public Catalog getPrivateCatalog() { + Catalog catalog = staticCatalog; + + if (useStaticCatalog == null) { + useStaticCatalog = getUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE; + } + + if (catalog == null || !useStaticCatalog.booleanValue()) { + + try { + String catalogClassName = getCatalogClassName(); + + if (catalogClassName == null) { + catalog = new Catalog(); + } else { + try { + catalog = (Catalog) ReflectUtil.forName(catalogClassName).newInstance(); + } catch (ClassNotFoundException cnfe) { + debug.message(1,"Catalog class named '" + + catalogClassName + + "' could not be found. Using default."); + catalog = new Catalog(); + } catch (ClassCastException cnfe) { + debug.message(1,"Class named '" + + catalogClassName + + "' is not a Catalog. Using default."); + catalog = new Catalog(); + } + } + + catalog.setCatalogManager(this); + catalog.setupReaders(); + catalog.loadSystemCatalogs(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (useStaticCatalog.booleanValue()) { + staticCatalog = catalog; + } + } + + return catalog; + } + + /** + * Get a catalog instance. + * + * If this manager uses static catalogs, the same static catalog will + * always be returned. Otherwise a new catalog will be returned. + */ + public Catalog getCatalog() { + Catalog catalog = staticCatalog; + + if (useStaticCatalog == null) { + useStaticCatalog = getUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE; + } + + if (catalog == null || !useStaticCatalog.booleanValue()) { + catalog = getPrivateCatalog(); + if (useStaticCatalog.booleanValue()) { + staticCatalog = catalog; + } + } + + return catalog; + } + + /** + *

Obtain the oasisXMLCatalogPI setting from the properties.

+ * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The oasisXMLCatalogPI setting from the propertyFile or the + * defaultOasisXMLCatalogPI. + */ + public boolean queryAllowOasisXMLCatalogPI () { + String allow = SecuritySupport.getSystemProperty(pAllowPI); + + if (allow == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultOasisXMLCatalogPI; + try { + allow = resources.getString("allow-oasis-xml-catalog-pi"); + } catch (MissingResourceException e) { + return defaultOasisXMLCatalogPI; + } + } + + if (allow == null) { + return defaultOasisXMLCatalogPI; + } + + return (allow.equalsIgnoreCase("true") + || allow.equalsIgnoreCase("yes") + || allow.equalsIgnoreCase("1")); + } + + /** + * Get the current XML Catalog PI setting. + */ + public boolean getAllowOasisXMLCatalogPI () { + if (oasisXMLCatalogPI == null) { + oasisXMLCatalogPI = queryAllowOasisXMLCatalogPI() ? Boolean.TRUE : Boolean.FALSE; + } + + return oasisXMLCatalogPI.booleanValue(); + } + + public boolean useServicesMechanism() { + return useServicesMechanism; + } + /** + * Set the XML Catalog PI setting + */ + public void setAllowOasisXMLCatalogPI(boolean allowPI) { + oasisXMLCatalogPI = allowPI ? Boolean.TRUE : Boolean.FALSE; + } + + /** + * Get the current XML Catalog PI setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean allowOasisXMLCatalogPI() { + return getAllowOasisXMLCatalogPI(); + } + + /** + * Obtain the Catalog class name setting from the properties. + * + */ + public String queryCatalogClassName () { + String className = SecuritySupport.getSystemProperty(pClassname); + + if (className == null) { + if (resources==null) readProperties(); + if (resources==null) return null; + try { + return resources.getString("catalog-class-name"); + } catch (MissingResourceException e) { + return null; + } + } + + return className; + } + + /** + * Get the current Catalog class name. + */ + public String getCatalogClassName() { if (catalogClassName == null) { - catalog = new Catalog(); - } else { - try { - catalog = (Catalog) ReflectUtil.forName(catalogClassName).newInstance(); - } catch (ClassNotFoundException cnfe) { - debug.message(1,"Catalog class named '" - + catalogClassName - + "' could not be found. Using default."); - catalog = new Catalog(); - } catch (ClassCastException cnfe) { - debug.message(1,"Class named '" - + catalogClassName - + "' is not a Catalog. Using default."); - catalog = new Catalog(); - } + catalogClassName = queryCatalogClassName(); } - catalog.setCatalogManager(this); - catalog.setupReaders(); - catalog.loadSystemCatalogs(); - } catch (Exception ex) { - ex.printStackTrace(); - } - - if (useStaticCatalog.booleanValue()) { - staticCatalog = catalog; - } + return catalogClassName; } - return catalog; - } - - /** - * Get a catalog instance. - * - * If this manager uses static catalogs, the same static catalog will - * always be returned. Otherwise a new catalog will be returned. - */ - public Catalog getCatalog() { - Catalog catalog = staticCatalog; - - if (useStaticCatalog == null) { - useStaticCatalog = new Boolean(getUseStaticCatalog()); + /** + * Set the Catalog class name. + */ + public void setCatalogClassName(String className) { + catalogClassName = className; } - if (catalog == null || !useStaticCatalog.booleanValue()) { - catalog = getPrivateCatalog(); - if (useStaticCatalog.booleanValue()) { - staticCatalog = catalog; - } + /** + * Get the current Catalog class name. + * + * @deprecated No longer static; use get/set methods. + */ + public String catalogClassName() { + return getCatalogClassName(); } - - return catalog; - } - - /** - *

Obtain the oasisXMLCatalogPI setting from the properties.

- * - *

In the properties, a value of 'yes', 'true', or '1' is considered - * true, anything else is false.

- * - * @return The oasisXMLCatalogPI setting from the propertyFile or the - * defaultOasisXMLCatalogPI. - */ - public boolean queryAllowOasisXMLCatalogPI () { - String allow = SecuritySupport.getSystemProperty(pAllowPI); - - if (allow == null) { - if (resources==null) readProperties(); - if (resources==null) return defaultOasisXMLCatalogPI; - try { - allow = resources.getString("allow-oasis-xml-catalog-pi"); - } catch (MissingResourceException e) { - return defaultOasisXMLCatalogPI; - } - } - - if (allow == null) { - return defaultOasisXMLCatalogPI; - } - - return (allow.equalsIgnoreCase("true") - || allow.equalsIgnoreCase("yes") - || allow.equalsIgnoreCase("1")); - } - - /** - * Get the current XML Catalog PI setting. - */ - public boolean getAllowOasisXMLCatalogPI () { - if (oasisXMLCatalogPI == null) { - oasisXMLCatalogPI = new Boolean(queryAllowOasisXMLCatalogPI()); - } - - return oasisXMLCatalogPI.booleanValue(); - } - - public boolean useServicesMechanism() { - return useServicesMechanism; - } - /** - * Set the XML Catalog PI setting - */ - public void setAllowOasisXMLCatalogPI(boolean allowPI) { - oasisXMLCatalogPI = new Boolean(allowPI); - } - - /** - * Get the current XML Catalog PI setting. - * - * @deprecated No longer static; use get/set methods. - */ - public boolean allowOasisXMLCatalogPI() { - return getAllowOasisXMLCatalogPI(); - } - - /** - * Obtain the Catalog class name setting from the properties. - * - */ - public String queryCatalogClassName () { - String className = SecuritySupport.getSystemProperty(pClassname); - - if (className == null) { - if (resources==null) readProperties(); - if (resources==null) return null; - try { - return resources.getString("catalog-class-name"); - } catch (MissingResourceException e) { - return null; - } - } - - return className; - } - - /** - * Get the current Catalog class name. - */ - public String getCatalogClassName() { - if (catalogClassName == null) { - catalogClassName = queryCatalogClassName(); - } - - return catalogClassName; - } - - /** - * Set the Catalog class name. - */ - public void setCatalogClassName(String className) { - catalogClassName = className; - } - - /** - * Get the current Catalog class name. - * - * @deprecated No longer static; use get/set methods. - */ - public String catalogClassName() { - return getCatalogClassName(); - } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Resolver.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Resolver.java index 721d67c8d4e..d566895ccce 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Resolver.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/Resolver.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// Resolver.java - Represents an extension of OASIS Open Catalog files. - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -94,7 +88,7 @@ public class Resolver extends Catalog { SAXCatalogReader saxReader = new SAXCatalogReader(spf); - saxReader.setCatalogParser(null, "XMLCatalog", + saxReader.setCatalogParser(null, "XCatalog", "com.sun.org.apache.xml.internal.resolver.readers.XCatalogReader"); saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName, diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/BootstrapResolver.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/BootstrapResolver.java index 9d5df419b6a..5bdf3d8e94a 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/BootstrapResolver.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/BootstrapResolver.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// BootstrapResolver.java - Resolve entities and URIs internally - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -65,14 +59,17 @@ public class BootstrapResolver implements EntityResolver, URIResolver { /** System identifier for OASIS XML Catalog files. */ public static final String xmlCatalogSysId = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"; + /** Public identifier for legacy Apache XCatalog files. There is no official system identifier for XCatalog files. */ + public static final String xCatalogPubId = "-//DTD XCatalog//EN"; + /** Private hash used for public identifiers. */ - private Hashtable publicMap = new Hashtable(); + private final Hashtable publicMap = new Hashtable(); /** Private hash used for system identifiers. */ - private Hashtable systemMap = new Hashtable(); + private final Hashtable systemMap = new Hashtable(); /** Private hash used for URIs. */ - private Hashtable uriMap = new Hashtable(); + private final Hashtable uriMap = new Hashtable(); /** Constructor. */ public BootstrapResolver() { @@ -91,6 +88,11 @@ public class BootstrapResolver implements EntityResolver, URIResolver { if (url != null) { uriMap.put(xmlCatalogXSD, url.toString()); } + + url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/xcatalog.dtd"); + if (url != null) { + publicMap.put(xCatalogPubId, url.toString()); + } } /** SAX resolveEntity API. */ diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Debug.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Debug.java index fbf2b8f2674..6a6c03a48e5 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Debug.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Debug.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// Debug.java - Print debug messages - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/FileURL.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/FileURL.java index e5a5605323e..6717739005a 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/FileURL.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/FileURL.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// FileURL.java - Construct a file: scheme URL - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Namespaces.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Namespaces.java index 02624a61615..6511cf26224 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Namespaces.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/Namespaces.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// Namespaces.java - Analyze namespace nodes in a DOM tree - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -47,8 +41,9 @@ public class Namespaces { String name = element.getTagName(); String prefix = ""; - if (name.indexOf(':') > 0) { - prefix = name.substring(0, name.indexOf(':')); + final int indexOfColon = name.indexOf(':'); + if (indexOfColon > 0) { + prefix = name.substring(0, indexOfColon); } return prefix; @@ -64,8 +59,9 @@ public class Namespaces { public static String getLocalName(Element element) { String name = element.getTagName(); - if (name.indexOf(':') > 0) { - name = name.substring(name.indexOf(':')+1); + final int indexOfColon = name.indexOf(':'); + if (indexOfColon > 0) { + name = name.substring(indexOfColon + 1); } return name; @@ -85,7 +81,7 @@ public class Namespaces { return null; } - if (prefix.equals("")) { + if (prefix.length() == 0) { if (((Element) node).hasAttribute("xmlns")) { return ((Element) node).getAttribute("xmlns"); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/PublicId.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/PublicId.java index 8211a770db5..d70f4f034ac 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/PublicId.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/helpers/PublicId.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// PublicId.java - Information about public identifiers - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -34,7 +28,8 @@ package com.sun.org.apache.xml.internal.resolver.helpers; * */ public abstract class PublicId { - protected PublicId() { } + + protected PublicId() {} /** * Normalize a public identifier. @@ -58,18 +53,17 @@ public abstract class PublicId { * @return The normalized identifier. */ public static String normalize(String publicId) { - String normal = publicId.replace('\t', ' '); - normal = normal.replace('\r', ' '); - normal = normal.replace('\n', ' '); - normal = normal.trim(); + String normal = publicId.replace('\t', ' '); + normal = normal.replace('\r', ' '); + normal = normal.replace('\n', ' '); + normal = normal.trim(); - int pos; + int pos; - while ((pos = normal.indexOf(" ")) >= 0) { - normal = normal.substring(0, pos) + normal.substring(pos+1); - } - - return normal; + while ((pos = normal.indexOf(" ")) >= 0) { + normal = normal.substring(0, pos) + normal.substring(pos+1); + } + return normal; } /** @@ -83,21 +77,24 @@ public abstract class PublicId { * @return The normalized identifier. */ public static String encodeURN(String publicId) { - String urn = PublicId.normalize(publicId); + String urn = PublicId.normalize(publicId); - urn = PublicId.stringReplace(urn, "%", "%25"); - urn = PublicId.stringReplace(urn, ";", "%3B"); - urn = PublicId.stringReplace(urn, "'", "%27"); - urn = PublicId.stringReplace(urn, "?", "%3F"); - urn = PublicId.stringReplace(urn, "#", "%23"); - urn = PublicId.stringReplace(urn, "+", "%2B"); - urn = PublicId.stringReplace(urn, " ", "+"); - urn = PublicId.stringReplace(urn, "::", ";"); - urn = PublicId.stringReplace(urn, ":", "%3A"); - urn = PublicId.stringReplace(urn, "//", ":"); - urn = PublicId.stringReplace(urn, "/", "%2F"); + urn = PublicId.stringReplace(urn, "%", "%25"); + urn = PublicId.stringReplace(urn, ";", "%3B"); + urn = PublicId.stringReplace(urn, "'", "%27"); + urn = PublicId.stringReplace(urn, "?", "%3F"); + urn = PublicId.stringReplace(urn, "#", "%23"); + urn = PublicId.stringReplace(urn, "+", "%2B"); + urn = PublicId.stringReplace(urn, " ", "+"); + urn = PublicId.stringReplace(urn, "::", ";"); + urn = PublicId.stringReplace(urn, ":", "%3A"); + urn = PublicId.stringReplace(urn, "//", ":"); + urn = PublicId.stringReplace(urn, "/", "%2F"); - return "urn:publicid:" + urn; + StringBuilder buffer = new StringBuilder(13 + urn.length()); + buffer.append("urn:publicid:"); + buffer.append(urn); + return buffer.toString(); } /** @@ -111,51 +108,62 @@ public abstract class PublicId { * @return The normalized identifier. */ public static String decodeURN(String urn) { - String publicId = ""; + String publicId; + if (urn.startsWith("urn:publicid:")) { + publicId = urn.substring(13); + } + else { + return urn; + } - if (urn.startsWith("urn:publicid:")) { - publicId = urn.substring(13); - } else { - return urn; - } + final boolean hasEscape = (publicId.indexOf('%') >= 0); + if (hasEscape) { + publicId = PublicId.stringReplace(publicId, "%2F", "/"); + } + publicId = PublicId.stringReplace(publicId, ":", "//"); + if (hasEscape) { + publicId = PublicId.stringReplace(publicId, "%3A", ":"); + } + publicId = PublicId.stringReplace(publicId, ";", "::"); + publicId = PublicId.stringReplace(publicId, "+", " "); + if (hasEscape) { + publicId = PublicId.stringReplace(publicId, "%2B", "+"); + publicId = PublicId.stringReplace(publicId, "%23", "#"); + publicId = PublicId.stringReplace(publicId, "%3F", "?"); + publicId = PublicId.stringReplace(publicId, "%27", "'"); + publicId = PublicId.stringReplace(publicId, "%3B", ";"); + publicId = PublicId.stringReplace(publicId, "%25", "%"); + } - publicId = PublicId.stringReplace(publicId, "%2F", "/"); - publicId = PublicId.stringReplace(publicId, ":", "//"); - publicId = PublicId.stringReplace(publicId, "%3A", ":"); - publicId = PublicId.stringReplace(publicId, ";", "::"); - publicId = PublicId.stringReplace(publicId, "+", " "); - publicId = PublicId.stringReplace(publicId, "%2B", "+"); - publicId = PublicId.stringReplace(publicId, "%23", "#"); - publicId = PublicId.stringReplace(publicId, "%3F", "?"); - publicId = PublicId.stringReplace(publicId, "%27", "'"); - publicId = PublicId.stringReplace(publicId, "%3B", ";"); - publicId = PublicId.stringReplace(publicId, "%25", "%"); - - return publicId; - } + return publicId; + } /** * Replace one string with another. - * */ private static String stringReplace(String str, - String oldStr, - String newStr) { - - String result = ""; - int pos = str.indexOf(oldStr); - - // System.out.println(str + ": " + oldStr + " => " + newStr); - - while (pos >= 0) { - // System.out.println(str + " (" + pos + ")"); - result += str.substring(0, pos); - result += newStr; - str = str.substring(pos+1); - - pos = str.indexOf(oldStr); - } - - return result + str; + String oldStr, + String newStr) { + int pos = str.indexOf(oldStr); + if (pos >= 0) { + final StringBuilder buffer = new StringBuilder(); + final int oldStrLength = oldStr.length(); + int start = 0; + do { + for (int i = start; i < pos; ++i) { + buffer.append(str.charAt(i)); + } + buffer.append(newStr); + start = pos + oldStrLength; + pos = str.indexOf(oldStr, start); + } + while (pos >= 0); + final int strLength = str.length(); + for (int i = start; i < strLength; ++i) { + buffer.append(str.charAt(i)); + } + return buffer.toString(); + } + return str; } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/CatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/CatalogReader.java index cc8bd09f2cb..444b38769dc 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/CatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/CatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// CatalogReader.java - An interface for reading catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogParser.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogParser.java index ff4af953946..c0e34011ab0 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogParser.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogParser.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// DOMCatalogParser.java - An interface for reading catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogReader.java index bd14b28ae39..22d131fe0f7 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/DOMCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// DOMCatalogReader.java - Read XML Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/ExtendedXMLCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/ExtendedXMLCatalogReader.java index a638a4757e4..2fd0dc6b1e2 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/ExtendedXMLCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/ExtendedXMLCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// ExtendedXMLCatalogReader.java - Read XML Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -166,7 +160,7 @@ public class ExtendedXMLCatalogReader extends OASISXMLCatalogReader { String baseURI = (String) baseURIStack.peek(); if (!baseURI.equals(popURI)) { - entryType = catalog.BASE; + entryType = Catalog.BASE; entryArgs.add(baseURI); debug.message(4, "(reset) xml:base", baseURI); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/OASISXMLCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/OASISXMLCatalogReader.java index f1d6b8983b5..04ddf623199 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/OASISXMLCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/OASISXMLCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// OASISXMLCatalogReader.java - Read XML Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -23,16 +17,16 @@ package com.sun.org.apache.xml.internal.resolver.readers; -import java.util.Stack; -import java.util.Vector; -import java.util.Enumeration; import com.sun.org.apache.xml.internal.resolver.Catalog; import com.sun.org.apache.xml.internal.resolver.CatalogEntry; import com.sun.org.apache.xml.internal.resolver.CatalogException; import com.sun.org.apache.xml.internal.resolver.helpers.PublicId; - -import org.xml.sax.*; +import java.util.Enumeration; +import java.util.Stack; +import java.util.Vector; +import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.*; +import org.xml.sax.*; /** * Parse OASIS Entity Resolution Technical Committee @@ -71,6 +65,17 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo return catalog; } + /** Default constructor */ + public OASISXMLCatalogReader() { + super(); + } + + /** Constructor allowing for providing custom SAX parser factory */ + public OASISXMLCatalogReader(SAXParserFactory parserFactory, Catalog catalog) { + super(parserFactory); + setCatalog(catalog); + } + /** * Are we in an extension namespace? * @@ -102,7 +107,7 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo return; } - /** The SAX startDocument method does nothing. */ + /** The SAX startDocument */ public void startDocument () throws SAXException { baseURIStack.push(catalog.getCurrentBase()); @@ -371,14 +376,14 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo } if (localName.equals("doctype")) { - entryType = catalog.DOCTYPE; + entryType = Catalog.DOCTYPE; entryArgs.add(atts.getValue("name")); entryArgs.add(atts.getValue("uri")); } else if (localName.equals("document")) { - entryType = catalog.DOCUMENT; + entryType = Catalog.DOCUMENT; entryArgs.add(atts.getValue("uri")); } else if (localName.equals("dtddecl")) { - entryType = catalog.DTDDECL; + entryType = Catalog.DTDDECL; entryArgs.add(atts.getValue("publicId")); entryArgs.add(atts.getValue("uri")); } else if (localName.equals("entity")) { @@ -432,7 +437,7 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo && checkAttributes(atts, attName2); } - /** The SAX endElement method does nothing. */ + /** The SAX endElement */ public void endElement (String namespaceURI, String localName, String qName) @@ -452,7 +457,7 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo String baseURI = (String) baseURIStack.peek(); if (!baseURI.equals(popURI)) { - entryType = catalog.BASE; + entryType = Catalog.BASE; entryArgs.add(baseURI); debug.message(4, "(reset) xml:base", baseURI); @@ -477,7 +482,7 @@ public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalo String override = (String) overrideStack.peek(); if (!override.equals(popOverride)) { - entryType = catalog.OVERRIDE; + entryType = Catalog.OVERRIDE; entryArgs.add(override); overrideStack.push(override); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogParser.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogParser.java index 782744bc5ee..b70f7dc64fe 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogParser.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogParser.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// SAXCatalogParser.java - An interface for reading catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java index 105cb7671ae..d5d5d2aca27 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// SAXCatalogReader.java - Read XML Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -77,427 +71,423 @@ import sun.reflect.misc.ReflectUtil; * */ public class SAXCatalogReader implements CatalogReader, ContentHandler, DocumentHandler { - /** The SAX Parser Factory */ - protected SAXParserFactory parserFactory = null; + /** The SAX Parser Factory */ + protected SAXParserFactory parserFactory = null; - /** The SAX Parser Class */ - protected String parserClass = null; + /** The SAX Parser Class */ + protected String parserClass = null; - /** + /** * Mapping table from QNames to CatalogParser classes. * *

Each key in this hash table has the form "elementname" * or "{namespaceuri}elementname". The former is used if the * namespace URI is null.

*/ - protected Hashtable namespaceMap = new Hashtable(); + protected Hashtable namespaceMap = new Hashtable(); - /** The parser in use for the current catalog. */ - private SAXCatalogParser saxParser = null; + /** The parser in use for the current catalog. */ + private SAXCatalogParser saxParser = null; - /** Set if something goes horribly wrong. It allows the class to + /** Set if something goes horribly wrong. It allows the class to * ignore the rest of the events that are received. */ - private boolean abandonHope = false; + private boolean abandonHope = false; - /** The Catalog that we're working for. */ - private Catalog catalog; + /** The Catalog that we're working for. */ + private Catalog catalog; - /** Set the XML SAX Parser Factory. - */ - public void setParserFactory(SAXParserFactory parserFactory) { - this.parserFactory = parserFactory; - } + /** Set the XML SAX Parser Factory. + */ + public void setParserFactory(SAXParserFactory parserFactory) { + this.parserFactory = parserFactory; + } - /** Set the XML SAX Parser Class - */ - public void setParserClass(String parserClass) { - this.parserClass = parserClass; - } + /** Set the XML SAX Parser Class + */ + public void setParserClass(String parserClass) { + this.parserClass = parserClass; + } - /** Get the parser factory currently in use. */ - public SAXParserFactory getParserFactory() { - return parserFactory; - } + /** Get the parser factory currently in use. */ + public SAXParserFactory getParserFactory() { + return parserFactory; + } - /** Get the parser class currently in use. */ - public String getParserClass() { - return parserClass; - } + /** Get the parser class currently in use. */ + public String getParserClass() { + return parserClass; + } - /** The debug class to use for this reader. - * - * This is a bit of a hack. Anyway, whenever we read for a catalog, - * we extract the debug object - * from the catalog's manager so that we can use it to print messages. - * - * In production, we don't really expect any messages so it doesn't - * really matter. But it's still a bit of a hack. - */ - protected Debug debug = CatalogManager.getStaticManager().debug; + /** The debug class to use for this reader. + * + * This is a bit of a hack. Anyway, whenever we read for a catalog, + * we extract the debug object + * from the catalog's manager so that we can use it to print messages. + * + * In production, we don't really expect any messages so it doesn't + * really matter. But it's still a bit of a hack. + */ + protected Debug debug = CatalogManager.getStaticManager().debug; - /** The constructor */ - public SAXCatalogReader() { - parserFactory = null; - parserClass = null; - } + /** The constructor */ + public SAXCatalogReader() { + parserFactory = null; + parserClass = null; + } - /** The constructor */ - public SAXCatalogReader(SAXParserFactory parserFactory) { - this.parserFactory = parserFactory; - } + /** The constructor */ + public SAXCatalogReader(SAXParserFactory parserFactory) { + this.parserFactory = parserFactory; + } - /** The constructor */ - public SAXCatalogReader(String parserClass) { - this.parserClass = parserClass; - } + /** The constructor */ + public SAXCatalogReader(String parserClass) { + this.parserClass = parserClass; + } - /** Set the SAXCatalogParser class for the given namespace/root + /** + * Set the SAXCatalogParser class for the given namespace/root * element type. */ - public void setCatalogParser(String namespaceURI, - String rootElement, - String parserClass) { - if (namespaceURI == null) { - namespaceMap.put(rootElement, parserClass); - } else { - namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass); + public void setCatalogParser(String namespaceURI, + String rootElement, + String parserClass) { + namespaceURI = namespaceURI != null ? namespaceURI.trim() : ""; + namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass); } - } - /** Get the SAXCatalogParser class for the given namespace/root + /** + * Get the SAXCatalogParser class for the given namespace/root * element type. */ - public String getCatalogParser(String namespaceURI, - String rootElement) { - if (namespaceURI == null) { - return (String) namespaceMap.get(rootElement); - } else { - return (String) namespaceMap.get("{"+namespaceURI+"}"+rootElement); - } - } - - /** - * Parse an XML Catalog file. - * - * @param catalog The catalog to which this catalog file belongs - * @param fileUrl The URL or filename of the catalog file to process - * - * @throws MalformedURLException Improper fileUrl - * @throws IOException Error reading catalog file - */ - public void readCatalog(Catalog catalog, String fileUrl) - throws MalformedURLException, IOException, - CatalogException { - - URL url = null; - - try { - url = new URL(fileUrl); - } catch (MalformedURLException e) { - url = new URL("file:///" + fileUrl); + public String getCatalogParser(String namespaceURI, + String rootElement) { + namespaceURI = namespaceURI != null ? namespaceURI.trim() : ""; + return (String) namespaceMap.get("{"+namespaceURI+"}"+rootElement); } - debug = catalog.getCatalogManager().debug; + /** + * Parse an XML Catalog file. + * + * @param catalog The catalog to which this catalog file belongs + * @param fileUrl The URL or filename of the catalog file to process + * + * @throws MalformedURLException Improper fileUrl + * @throws IOException Error reading catalog file + */ + public void readCatalog(Catalog catalog, String fileUrl) + throws MalformedURLException, IOException, + CatalogException { - try { - URLConnection urlCon = url.openConnection(); - readCatalog(catalog, urlCon.getInputStream()); - } catch (FileNotFoundException e) { - catalog.getCatalogManager().debug.message(1, "Failed to load catalog, file not found", + URL url = null; + + try { + url = new URL(fileUrl); + } catch (MalformedURLException e) { + url = new URL("file:///" + fileUrl); + } + + debug = catalog.getCatalogManager().debug; + + try { + URLConnection urlCon = url.openConnection(); + readCatalog(catalog, urlCon.getInputStream()); + } catch (FileNotFoundException e) { + catalog.getCatalogManager().debug.message(1, "Failed to load catalog, file not found", url.toString()); - } - } - - /** - * Parse an XML Catalog stream. - * - * @param catalog The catalog to which this catalog file belongs - * @param is The input stream from which the catalog will be read - * - * @throws MalformedURLException Improper fileUrl - * @throws IOException Error reading catalog file - * @throws CatalogException A Catalog exception - */ - public void readCatalog(Catalog catalog, InputStream is) - throws IOException, CatalogException { - - // Create an instance of the parser - if (parserFactory == null && parserClass == null) { - debug.message(1, "Cannot read SAX catalog without a parser"); - throw new CatalogException(CatalogException.UNPARSEABLE); - } - - debug = catalog.getCatalogManager().debug; - EntityResolver bResolver = catalog.getCatalogManager().getBootstrapResolver(); - - this.catalog = catalog; - - try { - if (parserFactory != null) { - SAXParser parser = parserFactory.newSAXParser(); - SAXParserHandler spHandler = new SAXParserHandler(); - spHandler.setContentHandler(this); - if (bResolver != null) { - spHandler.setEntityResolver(bResolver); } - parser.parse(new InputSource(is), spHandler); - } else { - Parser parser = (Parser) ReflectUtil.forName(parserClass).newInstance(); - parser.setDocumentHandler(this); - if (bResolver != null) { - parser.setEntityResolver(bResolver); + } + + /** + * Parse an XML Catalog stream. + * + * @param catalog The catalog to which this catalog file belongs + * @param is The input stream from which the catalog will be read + * + * @throws MalformedURLException Improper fileUrl + * @throws IOException Error reading catalog file + * @throws CatalogException A Catalog exception + */ + public void readCatalog(Catalog catalog, InputStream is) + throws IOException, CatalogException { + + // Create an instance of the parser + if (parserFactory == null && parserClass == null) { + debug.message(1, "Cannot read SAX catalog without a parser"); + throw new CatalogException(CatalogException.UNPARSEABLE); } - parser.parse(new InputSource(is)); - } - } catch (ClassNotFoundException cnfe) { - throw new CatalogException(CatalogException.UNPARSEABLE); - } catch (IllegalAccessException iae) { - throw new CatalogException(CatalogException.UNPARSEABLE); - } catch (InstantiationException ie) { - throw new CatalogException(CatalogException.UNPARSEABLE); - } catch (ParserConfigurationException pce) { - throw new CatalogException(CatalogException.UNKNOWN_FORMAT); - } catch (SAXException se) { - Exception e = se.getException(); - // FIXME: there must be a better way - UnknownHostException uhe = new UnknownHostException(); - FileNotFoundException fnfe = new FileNotFoundException(); - if (e != null) { - if (e.getClass() == uhe.getClass()) { - throw new CatalogException(CatalogException.PARSE_FAILED, - e.toString()); - } else if (e.getClass() == fnfe.getClass()) { - throw new CatalogException(CatalogException.PARSE_FAILED, - e.toString()); + + debug = catalog.getCatalogManager().debug; + EntityResolver bResolver = catalog.getCatalogManager().getBootstrapResolver(); + + this.catalog = catalog; + + try { + if (parserFactory != null) { + SAXParser parser = parserFactory.newSAXParser(); + SAXParserHandler spHandler = new SAXParserHandler(); + spHandler.setContentHandler(this); + if (bResolver != null) { + spHandler.setEntityResolver(bResolver); + } + parser.parse(new InputSource(is), spHandler); + } else { + Parser parser = (Parser) ReflectUtil.forName(parserClass).newInstance(); + parser.setDocumentHandler(this); + if (bResolver != null) { + parser.setEntityResolver(bResolver); + } + parser.parse(new InputSource(is)); + } + } catch (ClassNotFoundException cnfe) { + throw new CatalogException(CatalogException.UNPARSEABLE); + } catch (IllegalAccessException iae) { + throw new CatalogException(CatalogException.UNPARSEABLE); + } catch (InstantiationException ie) { + throw new CatalogException(CatalogException.UNPARSEABLE); + } catch (ParserConfigurationException pce) { + throw new CatalogException(CatalogException.UNKNOWN_FORMAT); + } catch (SAXException se) { + Exception e = se.getException(); + // FIXME: there must be a better way + UnknownHostException uhe = new UnknownHostException(); + FileNotFoundException fnfe = new FileNotFoundException(); + if (e != null) { + if (e.getClass() == uhe.getClass()) { + throw new CatalogException(CatalogException.PARSE_FAILED, + e.toString()); + } else if (e.getClass() == fnfe.getClass()) { + throw new CatalogException(CatalogException.PARSE_FAILED, + e.toString()); + } + } + throw new CatalogException(se); } - } - throw new CatalogException(se); - } - } - - // ---------------------------------------------------------------------- - // Implement the SAX ContentHandler interface - - /** The SAX setDocumentLocator method. Does nothing. */ - public void setDocumentLocator (Locator locator) { - if (saxParser != null) { - saxParser.setDocumentLocator(locator); - } - } - - /** The SAX startDocument method. Does nothing. */ - public void startDocument () throws SAXException { - saxParser = null; - abandonHope = false; - return; - } - - /** The SAX endDocument method. Does nothing. */ - public void endDocument ()throws SAXException { - if (saxParser != null) { - saxParser.endDocument(); - } - } - - /** - * The SAX startElement method. - * - *

The catalog parser is selected based on the namespace of the - * first element encountered in the catalog.

- */ - public void startElement (String name, - AttributeList atts) - throws SAXException { - - if (abandonHope) { - return; } - if (saxParser == null) { - String prefix = ""; - if (name.indexOf(':') > 0) { - prefix = name.substring(0, name.indexOf(':')); - } + // ---------------------------------------------------------------------- + // Implement the SAX ContentHandler interface - String localName = name; - if (localName.indexOf(':') > 0) { - localName = localName.substring(localName.indexOf(':')+1); - } - - String namespaceURI = null; - if (prefix.equals("")) { - namespaceURI = atts.getValue("xmlns"); - } else { - namespaceURI = atts.getValue("xmlns:" + prefix); - } - - String saxParserClass = getCatalogParser(namespaceURI, - localName); - - if (saxParserClass == null) { - abandonHope = true; - if (namespaceURI == null) { - debug.message(2, "No Catalog parser for " + name); - } else { - debug.message(2, "No Catalog parser for " - + "{" + namespaceURI + "}" - + name); + /** The SAX setDocumentLocator method. Does nothing. */ + public void setDocumentLocator (Locator locator) { + if (saxParser != null) { + saxParser.setDocumentLocator(locator); } + } + + /** The SAX startDocument method. Does nothing. */ + public void startDocument () throws SAXException { + saxParser = null; + abandonHope = false; return; - } - - try { - saxParser = (SAXCatalogParser) - ReflectUtil.forName(saxParserClass).newInstance(); - - saxParser.setCatalog(catalog); - saxParser.startDocument(); - saxParser.startElement(name, atts); - } catch (ClassNotFoundException cnfe) { - saxParser = null; - abandonHope = true; - debug.message(2, cnfe.toString()); - } catch (InstantiationException ie) { - saxParser = null; - abandonHope = true; - debug.message(2, ie.toString()); - } catch (IllegalAccessException iae) { - saxParser = null; - abandonHope = true; - debug.message(2, iae.toString()); - } catch (ClassCastException cce ) { - saxParser = null; - abandonHope = true; - debug.message(2, cce.toString()); - } - } else { - saxParser.startElement(name, atts); - } - } - - /** - * The SAX2 startElement method. - * - *

The catalog parser is selected based on the namespace of the - * first element encountered in the catalog.

- */ - public void startElement (String namespaceURI, - String localName, - String qName, - Attributes atts) - throws SAXException { - - if (abandonHope) { - return; } - if (saxParser == null) { - String saxParserClass = getCatalogParser(namespaceURI, - localName); - - if (saxParserClass == null) { - abandonHope = true; - if (namespaceURI == null) { - debug.message(2, "No Catalog parser for " + localName); - } else { - debug.message(2, "No Catalog parser for " - + "{" + namespaceURI + "}" - + localName); + /** The SAX endDocument method. Does nothing. */ + public void endDocument ()throws SAXException { + if (saxParser != null) { + saxParser.endDocument(); } - return; - } - - try { - saxParser = (SAXCatalogParser) - ReflectUtil.forName(saxParserClass).newInstance(); - - saxParser.setCatalog(catalog); - saxParser.startDocument(); - saxParser.startElement(namespaceURI, localName, qName, atts); - } catch (ClassNotFoundException cnfe) { - saxParser = null; - abandonHope = true; - debug.message(2, cnfe.toString()); - } catch (InstantiationException ie) { - saxParser = null; - abandonHope = true; - debug.message(2, ie.toString()); - } catch (IllegalAccessException iae) { - saxParser = null; - abandonHope = true; - debug.message(2, iae.toString()); - } catch (ClassCastException cce ) { - saxParser = null; - abandonHope = true; - debug.message(2, cce.toString()); - } - } else { - saxParser.startElement(namespaceURI, localName, qName, atts); } - } - /** The SAX endElement method. Does nothing. */ - public void endElement (String name) throws SAXException { - if (saxParser != null) { - saxParser.endElement(name); - } - } + /** + * The SAX startElement method. + * + *

The catalog parser is selected based on the namespace of the + * first element encountered in the catalog.

+ */ + public void startElement (String name, + AttributeList atts) + throws SAXException { - /** The SAX2 endElement method. Does nothing. */ - public void endElement (String namespaceURI, - String localName, - String qName) throws SAXException { - if (saxParser != null) { - saxParser.endElement(namespaceURI, localName, qName); - } - } + if (abandonHope) { + return; + } - /** The SAX characters method. Does nothing. */ - public void characters (char ch[], int start, int length) - throws SAXException { - if (saxParser != null) { - saxParser.characters(ch, start, length); - } - } + if (saxParser == null) { + String prefix = ""; + if (name.indexOf(':') > 0) { + prefix = name.substring(0, name.indexOf(':')); + } - /** The SAX ignorableWhitespace method. Does nothing. */ - public void ignorableWhitespace (char ch[], int start, int length) - throws SAXException { - if (saxParser != null) { - saxParser.ignorableWhitespace(ch, start, length); - } - } + String localName = name; + if (localName.indexOf(':') > 0) { + localName = localName.substring(localName.indexOf(':')+1); + } - /** The SAX processingInstruction method. Does nothing. */ - public void processingInstruction (String target, String data) - throws SAXException { - if (saxParser != null) { - saxParser.processingInstruction(target, data); - } - } + String namespaceURI = null; + if (prefix.length() == 0) { + namespaceURI = atts.getValue("xmlns"); + } else { + namespaceURI = atts.getValue("xmlns:" + prefix); + } - /** The SAX startPrefixMapping method. Does nothing. */ - public void startPrefixMapping (String prefix, String uri) - throws SAXException { - if (saxParser != null) { - saxParser.startPrefixMapping (prefix, uri); - } - } + String saxParserClass = getCatalogParser(namespaceURI, + localName); - /** The SAX endPrefixMapping method. Does nothing. */ - public void endPrefixMapping (String prefix) - throws SAXException { - if (saxParser != null) { - saxParser.endPrefixMapping (prefix); - } - } + if (saxParserClass == null) { + abandonHope = true; + if (namespaceURI == null) { + debug.message(2, "No Catalog parser for " + name); + } else { + debug.message(2, "No Catalog parser for " + + "{" + namespaceURI + "}" + + name); + } + return; + } - /** The SAX skippedentity method. Does nothing. */ - public void skippedEntity (String name) - throws SAXException { - if (saxParser != null) { - saxParser.skippedEntity(name); + try { + saxParser = (SAXCatalogParser) + ReflectUtil.forName(saxParserClass).newInstance(); + + saxParser.setCatalog(catalog); + saxParser.startDocument(); + saxParser.startElement(name, atts); + } catch (ClassNotFoundException cnfe) { + saxParser = null; + abandonHope = true; + debug.message(2, cnfe.toString()); + } catch (InstantiationException ie) { + saxParser = null; + abandonHope = true; + debug.message(2, ie.toString()); + } catch (IllegalAccessException iae) { + saxParser = null; + abandonHope = true; + debug.message(2, iae.toString()); + } catch (ClassCastException cce ) { + saxParser = null; + abandonHope = true; + debug.message(2, cce.toString()); + } + } else { + saxParser.startElement(name, atts); + } + } + + /** + * The SAX2 startElement method. + * + *

The catalog parser is selected based on the namespace of the + * first element encountered in the catalog.

+ */ + public void startElement (String namespaceURI, + String localName, + String qName, + Attributes atts) + throws SAXException { + + if (abandonHope) { + return; + } + + if (saxParser == null) { + String saxParserClass = getCatalogParser(namespaceURI, + localName); + + if (saxParserClass == null) { + abandonHope = true; + if (namespaceURI == null) { + debug.message(2, "No Catalog parser for " + localName); + } else { + debug.message(2, "No Catalog parser for " + + "{" + namespaceURI + "}" + + localName); + } + return; + } + + try { + saxParser = (SAXCatalogParser) + ReflectUtil.forName(saxParserClass).newInstance(); + + saxParser.setCatalog(catalog); + saxParser.startDocument(); + saxParser.startElement(namespaceURI, localName, qName, atts); + } catch (ClassNotFoundException cnfe) { + saxParser = null; + abandonHope = true; + debug.message(2, cnfe.toString()); + } catch (InstantiationException ie) { + saxParser = null; + abandonHope = true; + debug.message(2, ie.toString()); + } catch (IllegalAccessException iae) { + saxParser = null; + abandonHope = true; + debug.message(2, iae.toString()); + } catch (ClassCastException cce ) { + saxParser = null; + abandonHope = true; + debug.message(2, cce.toString()); + } + } else { + saxParser.startElement(namespaceURI, localName, qName, atts); + } + } + + /** The SAX endElement method. Does nothing. */ + public void endElement (String name) throws SAXException { + if (saxParser != null) { + saxParser.endElement(name); + } + } + + /** The SAX2 endElement method. Does nothing. */ + public void endElement (String namespaceURI, + String localName, + String qName) throws SAXException { + if (saxParser != null) { + saxParser.endElement(namespaceURI, localName, qName); + } + } + + /** The SAX characters method. Does nothing. */ + public void characters (char ch[], int start, int length) + throws SAXException { + if (saxParser != null) { + saxParser.characters(ch, start, length); + } + } + + /** The SAX ignorableWhitespace method. Does nothing. */ + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException { + if (saxParser != null) { + saxParser.ignorableWhitespace(ch, start, length); + } + } + + /** The SAX processingInstruction method. Does nothing. */ + public void processingInstruction (String target, String data) + throws SAXException { + if (saxParser != null) { + saxParser.processingInstruction(target, data); + } + } + + /** The SAX startPrefixMapping method. Does nothing. */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException { + if (saxParser != null) { + saxParser.startPrefixMapping (prefix, uri); + } + } + + /** The SAX endPrefixMapping method. Does nothing. */ + public void endPrefixMapping (String prefix) + throws SAXException { + if (saxParser != null) { + saxParser.endPrefixMapping (prefix); + } + } + + /** The SAX skippedentity method. Does nothing. */ + public void skippedEntity (String name) + throws SAXException { + if (saxParser != null) { + saxParser.skippedEntity(name); + } } - } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXParserHandler.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXParserHandler.java index 0d07510aafb..efcf32950df 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXParserHandler.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXParserHandler.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// SAXParserHandler.java - An entity-resolving DefaultHandler - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TR9401CatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TR9401CatalogReader.java index b27481049f6..fb39a433063 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TR9401CatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TR9401CatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// TR9401CatalogReader.java - Read OASIS Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -23,13 +17,14 @@ package com.sun.org.apache.xml.internal.resolver.readers; -import java.io.InputStream; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.Vector; import com.sun.org.apache.xml.internal.resolver.Catalog; import com.sun.org.apache.xml.internal.resolver.CatalogEntry; import com.sun.org.apache.xml.internal.resolver.CatalogException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.util.Locale; +import java.util.Vector; /** * Parses OASIS Open Catalog files. @@ -97,7 +92,7 @@ public class TR9401CatalogReader extends TextCatalogReader { if (caseSensitive) { entryToken = token; } else { - entryToken = token.toUpperCase(); + entryToken = token.toUpperCase(Locale.ENGLISH); } if (entryToken.equals("DELEGATE")) { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TextCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TextCatalogReader.java index 3493e48f91b..9440e3370cb 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TextCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/TextCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// TextCatalogReader.java - Read text/plain Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -23,18 +17,19 @@ package com.sun.org.apache.xml.internal.resolver.readers; -import java.io.InputStream; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.net.URL; -import java.net.URLConnection; -import java.net.MalformedURLException; -import java.util.Vector; -import java.util.Stack; import com.sun.org.apache.xml.internal.resolver.Catalog; import com.sun.org.apache.xml.internal.resolver.CatalogEntry; import com.sun.org.apache.xml.internal.resolver.CatalogException; import com.sun.org.apache.xml.internal.resolver.readers.CatalogReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Locale; +import java.util.Stack; +import java.util.Vector; /** * Parses plain text Catalog files. @@ -140,7 +135,7 @@ public class TextCatalogReader implements CatalogReader { if (caseSensitive) { entryToken = token; } else { - entryToken = token.toUpperCase(); + entryToken = token.toUpperCase(Locale.ENGLISH); } try { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/XCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/XCatalogReader.java index 3d94545ae23..ce8cc40d6a8 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/XCatalogReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/XCatalogReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// XCatalogReader.java - Read XML Catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -34,7 +28,7 @@ import org.xml.sax.*; import javax.xml.parsers.*; /** - * Parse "xcatalog" XML Catalog files, this is the XML Catalog format + * Parse "XCatalog" XML Catalog files, this is the XML Catalog format * developed by John Cowan and supported by Apache. * * @see Catalog @@ -52,6 +46,7 @@ public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser /** Set the current catalog. */ public void setCatalog (Catalog catalog) { this.catalog = catalog; + debug = catalog.getCatalogManager().debug; } /** Get the current catalog. */ @@ -59,13 +54,19 @@ public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser return catalog; } - /** The constructor */ - public XCatalogReader(SAXParserFactory parserFactory) { + /** Default constructor */ + public XCatalogReader() { + super(); + } + + /** Constructor allowing for providing custom SAX parser factory */ + public XCatalogReader(SAXParserFactory parserFactory, Catalog catalog) { super(parserFactory); + setCatalog(catalog); } // ---------------------------------------------------------------------- - // Implement the SAX DocumentHandler interface + // Implement the SAX ContentHandler interface /** The SAX setDocumentLocator method does nothing. */ public void setDocumentLocator (Locator locator) { @@ -106,44 +107,44 @@ public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser Vector entryArgs = new Vector(); if (localName.equals("Base")) { - entryType = catalog.BASE; + entryType = Catalog.BASE; entryArgs.add(atts.getValue("HRef")); - catalog.getCatalogManager().debug.message(4, "Base", atts.getValue("HRef")); + debug.message(4, "Base", atts.getValue("HRef")); } else if (localName.equals("Delegate")) { - entryType = catalog.DELEGATE_PUBLIC; - entryArgs.add(atts.getValue("PublicId")); + entryType = Catalog.DELEGATE_PUBLIC; + entryArgs.add(atts.getValue("PublicID")); entryArgs.add(atts.getValue("HRef")); - catalog.getCatalogManager().debug.message(4, "Delegate", - PublicId.normalize(atts.getValue("PublicId")), + debug.message(4, "Delegate", + PublicId.normalize(atts.getValue("PublicID")), atts.getValue("HRef")); } else if (localName.equals("Extend")) { - entryType = catalog.CATALOG; + entryType = Catalog.CATALOG; entryArgs.add(atts.getValue("HRef")); - catalog.getCatalogManager().debug.message(4, "Extend", atts.getValue("HRef")); + debug.message(4, "Extend", atts.getValue("HRef")); } else if (localName.equals("Map")) { - entryType = catalog.PUBLIC; - entryArgs.add(atts.getValue("PublicId")); + entryType = Catalog.PUBLIC; + entryArgs.add(atts.getValue("PublicID")); entryArgs.add(atts.getValue("HRef")); - catalog.getCatalogManager().debug.message(4, "Map", - PublicId.normalize(atts.getValue("PublicId")), + debug.message(4, "Map", + PublicId.normalize(atts.getValue("PublicID")), atts.getValue("HRef")); } else if (localName.equals("Remap")) { - entryType = catalog.SYSTEM; - entryArgs.add(atts.getValue("SystemId")); + entryType = Catalog.SYSTEM; + entryArgs.add(atts.getValue("SystemID")); entryArgs.add(atts.getValue("HRef")); - catalog.getCatalogManager().debug.message(4, "Remap", - atts.getValue("SystemId"), + debug.message(4, "Remap", + atts.getValue("SystemID"), atts.getValue("HRef")); - } else if (localName.equals("XMLCatalog")) { + } else if (localName.equals("XCatalog")) { // nop, start of catalog } else { // This is equivalent to an invalid catalog entry type - catalog.getCatalogManager().debug.message(1, "Invalid catalog entry type", localName); + debug.message(1, "Invalid catalog entry type", localName); } if (entryType >= 0) { @@ -152,21 +153,21 @@ public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser catalog.addEntry(ce); } catch (CatalogException cex) { if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) { - catalog.getCatalogManager().debug.message(1, "Invalid catalog entry type", localName); + debug.message(1, "Invalid catalog entry type", localName); } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) { - catalog.getCatalogManager().debug.message(1, "Invalid catalog entry", localName); + debug.message(1, "Invalid catalog entry", localName); } } } - } + } - /** The SAX endElement method does nothing. */ - public void endElement (String namespaceURI, - String localName, - String qName) - throws SAXException { - return; - } + /** The SAX endElement method does nothing. */ + public void endElement (String namespaceURI, + String localName, + String qName) + throws SAXException { + return; + } /** The SAX characters method does nothing. */ public void characters (char ch[], int start, int length) @@ -185,4 +186,23 @@ public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser throws SAXException { return; } + + /** The SAX skippedEntity method does nothing. */ + public void skippedEntity (String name) + throws SAXException { + return; + } + + /** The SAX startPrefixMapping method does nothing. */ + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + return; + } + + /** The SAX endPrefixMapping method does nothing. */ + public void endPrefixMapping(String prefix) + throws SAXException { + return; + } + } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/CatalogResolver.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/CatalogResolver.java index 25951aa490b..bf82547188b 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/CatalogResolver.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/CatalogResolver.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// CatalogResolver.java - A SAX EntityResolver/JAXP URI Resolver - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -218,7 +212,10 @@ public class CatalogResolver implements EntityResolver, URIResolver { return iSource; } catch (Exception e) { - catalogManager.debug.message(1, "Failed to create InputSource", resolved); + catalogManager.debug.message(1, + "Failed to create InputSource (" + + e.toString() + + ")", resolved); return null; } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingParser.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingParser.java index 0d90d573a39..354ac1e60c0 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingParser.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingParser.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// ResolvingParser.java - An interface for reading catalog files - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -67,17 +61,12 @@ import com.sun.org.apache.xml.internal.resolver.helpers.FileURL; */ public class ResolvingParser implements Parser, DTDHandler, DocumentHandler, EntityResolver { - /** Make the parser Namespace aware? */ - public static boolean namespaceAware = true; - - /** Make the parser validating? */ - public static boolean validating = false; /** Suppress explanatory message? * * @see #parse(InputSource) */ - public static boolean suppressExplanation = false; + private static final boolean suppressExplanation = false; /** The underlying parser. */ private SAXParser saxParser = null; @@ -103,9 +92,6 @@ public class ResolvingParser /** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */ private boolean allowXMLCatalogPI = false; - /** Has an oasis-xml-catalog PI been seen? */ - private boolean oasisXMLCatalogPI = false; - /** The base URI of the input document, if known. */ private URL baseURL = null; @@ -125,8 +111,8 @@ public class ResolvingParser catalogResolver = new CatalogResolver(catalogManager); SAXParserFactory spf = catalogManager.useServicesMechanism() ? SAXParserFactory.newInstance() : new SAXParserFactoryImpl(); - spf.setNamespaceAware(namespaceAware); - spf.setValidating(validating); + spf.setNamespaceAware(true); + spf.setValidating(false); try { saxParser = spf.newSAXParser(); @@ -289,7 +275,6 @@ public class ResolvingParser if (catalog != null) { try { catalogManager.debug.message(4,"oasis-xml-catalog", catalog.toString()); - oasisXMLCatalogPI = true; if (piCatalogResolver == null) { piCatalogResolver = new CatalogResolver(true); @@ -396,7 +381,10 @@ public class ResolvingParser return iSource; } catch (Exception e) { - catalogManager.debug.message(1, "Failed to create InputSource", resolved); + catalogManager.debug.message(1, + "Failed to create InputSource (" + + e.toString() + + ")", resolved); return null; } } else { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLFilter.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLFilter.java index 660e4af6a13..f196e3726fe 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLFilter.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLFilter.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// ResolvingXMLFilter.java - An XMLFilter that performs catalog resolution - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -61,7 +55,7 @@ public class ResolvingXMLFilter extends XMLFilterImpl { * * @see #parse(InputSource) */ - public static boolean suppressExplanation = false; + private static boolean suppressExplanation = false; /** The manager for the underlying resolver. */ CatalogManager catalogManager = CatalogManager.getStaticManager(); @@ -75,9 +69,6 @@ public class ResolvingXMLFilter extends XMLFilterImpl { /** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */ private boolean allowXMLCatalogPI = false; - /** Has an oasis-xml-catalog PI been seen? */ - private boolean oasisXMLCatalogPI = false; - /** The base URI of the input document, if known. */ private URL baseURL = null; @@ -202,7 +193,10 @@ public class ResolvingXMLFilter extends XMLFilterImpl { return iSource; } catch (Exception e) { - catalogManager.debug.message(1, "Failed to create InputSource", resolved); + catalogManager.debug.message(1, + "Failed to create InputSource (" + + e.toString() + + ")", resolved); return null; } } else { @@ -289,7 +283,6 @@ public class ResolvingXMLFilter extends XMLFilterImpl { if (catalog != null) { try { catalogManager.debug.message(4,"oasis-xml-catalog", catalog.toString()); - oasisXMLCatalogPI = true; if (piCatalogResolver == null) { piCatalogResolver = new CatalogResolver(true); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLReader.java index 0a98cd8dbe6..ad9bd7c6e19 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLReader.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/tools/ResolvingXMLReader.java @@ -1,16 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -// ResolvingXMLReader.java - An XMLReader that performs catalog resolution - -/* - * Copyright 2001-2004 The Apache Software Foundation or its licensors, - * as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -23,7 +17,6 @@ package com.sun.org.apache.xml.internal.resolver.tools; -import org.xml.sax.*; import javax.xml.parsers.*; @@ -48,10 +41,10 @@ import com.sun.org.apache.xml.internal.resolver.*; */ public class ResolvingXMLReader extends ResolvingXMLFilter { /** Make the parser Namespace aware? */ - public static boolean namespaceAware = true; + private static final boolean namespaceAware = true; /** Make the parser validating? */ - public static boolean validating = false; + private static final boolean validating = false; /** * Construct a new reader from the JAXP factory. diff --git a/jdk/.hgignore b/jdk/.hgignore index d8754b13e1f..1ed4344d03f 100644 --- a/jdk/.hgignore +++ b/jdk/.hgignore @@ -1,5 +1,6 @@ ^build/ ^dist/ +^webrev ^testoutput/ /nbproject/private/ ^make/netbeans/.*/build/ diff --git a/jdk/.hgtags b/jdk/.hgtags index 987e541796d..bea594c1bfc 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -272,3 +272,4 @@ dde9f5cfde5f46e62ceb5fab81151578e5277aef jdk9-b26 f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27 1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28 2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29 +8d24fb4493f13d380a2adf62d444e1e5a4451f37 jdk9-b30 diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index c624ff80874..97fc8193ef7 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -208,20 +208,6 @@ BASE_CONF_FILES += $(CACERTS_DST) ################################################################################ -ifeq ($(OPENJDK_TARGET_OS), solaris) - - SUNPKCS11_CFG_SRC := $(JDK_TOPDIR)/src/java.base/share/conf/security/sunpkcs11-solaris.cfg - SUNPKCS11_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/sunpkcs11-solaris.cfg - - $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC) - $(call install-file) - - BASE_CONF_FILES += $(SUNPKCS11_CFG_DST) - -endif - -################################################################################ - $(JDK_OUTPUTDIR)/lib/net.properties: $(JDK_TOPDIR)/src/java.base/share/conf/net.properties $(ECHO) $(LOG_INFO) Copying $(@F) $(call install-file) diff --git a/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk b/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk new file mode 100644 index 00000000000..6db3dc97a8e --- /dev/null +++ b/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk @@ -0,0 +1,50 @@ +# +# Copyright (c) 2014, 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 CopyCommon.gmk + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), solaris) + + SUNPKCS11_CFG_SRC := \ + $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg + SUNPKCS11_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/sunpkcs11-solaris.cfg + + $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC) + $(call install-file) + + SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST) + +endif + +################################################################################ + +jdk.crypto.pkcs11: $(SECURITY_PKCS11_CONF_FILES) + +all: jdk.crypto.pkcs11 + +.PHONY: all jdk.crypto.pkcs11 + diff --git a/jdk/make/data/tzdata/VERSION b/jdk/make/data/tzdata/VERSION index c735be51ca1..5e925ada8df 100644 --- a/jdk/make/data/tzdata/VERSION +++ b/jdk/make/data/tzdata/VERSION @@ -1,24 +1,24 @@ # # 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. # -tzdata2014c +tzdata2014g diff --git a/jdk/make/data/tzdata/africa b/jdk/make/data/tzdata/africa index 6f1a1471e0c..aa91f365ce1 100644 --- a/jdk/make/data/tzdata/africa +++ b/jdk/make/data/tzdata/africa @@ -21,13 +21,13 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -#
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
 # From Paul Eggert (2013-02-21):
 #
@@ -49,8 +49,8 @@
 # I found in the UCLA library.
 #
 # For data circa 1899, a common source is:
-# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
-# .
+# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
+# http://www.jstor.org/stable/1774359
 #
 # A reliable and entertaining source about time zones is
 # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
@@ -58,13 +58,13 @@
 # Previous editions of this database used WAT, CAT, SAT, and EAT
 # for +0:00 through +3:00, respectively,
 # but Mark R V Murray reports that
-# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
-# `CAT' is commonly used for +2:00 in countries north of South Africa, and
-# `WAT' is probably the best name for +1:00, as the common phrase for
-# the area that includes Nigeria is ``West Africa''.
-# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
+# 'SAST' is the official abbreviation for +2:00 in the country of South Africa,
+# 'CAT' is commonly used for +2:00 in countries north of South Africa, and
+# 'WAT' is probably the best name for +1:00, as the common phrase for
+# the area that includes Nigeria is "West Africa".
+# He has heard of "Western Sahara Time" for +0:00 but can find no reference.
 #
-# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
+# To make things confusing, 'WAT' seems to have been used for -1:00 long ago;
 # I'd guess that this was because people needed _some_ name for -1:00,
 # and at the time, far west Africa was the only major land area in -1:00.
 # This usage is now obsolete, as the last use of -1:00 on the African
@@ -77,7 +77,7 @@
 #	 2:00	SAST	South Africa Standard Time
 # and Murray suggests the following abbreviation:
 #	 1:00	WAT	West Africa Time
-# I realize that this leads to `WAT' being used for both -1:00 and 1:00
+# I realize that this leads to 'WAT' being used for both -1:00 and 1:00
 # for times before 1976, but this is the best I can think of
 # until we get more information.
 #
@@ -117,9 +117,9 @@ Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
 # Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
 # more precise 0:09:21.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
-			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
-			0:00	Algeria	WE%sT	1940 Feb 25 2:00
+Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15  0:01
+			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
+			0:00	Algeria	WE%sT	1940 Feb 25  2:00
 			1:00	Algeria	CE%sT	1946 Oct  7
 			0:00	-	WET	1956 Jan 29
 			1:00	-	CET	1963 Apr 14
@@ -129,18 +129,8 @@ Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
 			1:00	-	CET
 
 # Angola
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Luanda	0:52:56	-	LMT	1892
-			0:52:04	-	AOT	1911 May 26 # Angola Time
-			1:00	-	WAT
-
 # Benin
-# Whitman says they switched to 1:00 in 1946, not 1934;
-# go with Shanks & Pottenger.
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
-			0:00	-	GMT	1934 Feb 26
-			1:00	-	WAT
+# See Africa/Lagos.
 
 # Botswana
 # From Paul Eggert (2013-02-21):
@@ -149,14 +139,12 @@ Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Gaborone	1:43:40 -	LMT	1885
 			1:30	-	SAST	1903 Mar
-			2:00	-	CAT	1943 Sep 19 2:00
-			2:00	1:00	CAST	1944 Mar 19 2:00
+			2:00	-	CAT	1943 Sep 19  2:00
+			2:00	1:00	CAST	1944 Mar 19  2:00
 			2:00	-	CAT
 
 # Burkina Faso
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Ouagadougou	-0:06:04 -	LMT	1912
-			 0:00	-	GMT
+# See Africa/Abidjan.
 
 # Burundi
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -164,52 +152,60 @@ Zone Africa/Bujumbura	1:57:28	-	LMT	1890
 			2:00	-	CAT
 
 # Cameroon
-# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Douala	0:38:48	-	LMT	1912
-			1:00	-	WAT
+# See Africa/Lagos.
 
 # Cape Verde
+#
+# Shanks gives 1907 for the transition to CVT.
+# Perhaps the 1911-05-26 Portuguese decree
+# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
+# merely made it official?
+#
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907			# Praia
+Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907        # Praia
 			-2:00	-	CVT	1942 Sep
 			-2:00	1:00	CVST	1945 Oct 15
-			-2:00	-	CVT	1975 Nov 25 2:00
+			-2:00	-	CVT	1975 Nov 25  2:00
 			-1:00	-	CVT
 
 # Central African Republic
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Bangui	1:14:20	-	LMT	1912
-			1:00	-	WAT
+# See Africa/Lagos.
 
 # Chad
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Ndjamena	1:00:12 -	LMT	1912
+Zone	Africa/Ndjamena	1:00:12 -	LMT	1912        # N'Djamena
 			1:00	-	WAT	1979 Oct 14
 			1:00	1:00	WAST	1980 Mar  8
 			1:00	-	WAT
 
 # Comoros
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul   # Moroni, Gran Comoro
+Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul # Moroni, Gran Comoro
 			3:00	-	EAT
 
-# Democratic Republic of Congo
+# Democratic Republic of the Congo
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Kinshasa	1:01:12 -	LMT	1897 Nov 9
-			1:00	-	WAT
 Zone Africa/Lubumbashi	1:49:52 -	LMT	1897 Nov 9
 			2:00	-	CAT
+# The above is for the eastern part; see Africa/Lagos for the western part.
 
 # Republic of the Congo
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Brazzaville	1:01:08 -	LMT	1912
-			1:00	-	WAT
+# See Africa/Lagos.
 
-# Cote D'Ivoire
+# Côte d'Ivoire / Ivory Coast
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Abidjan	-0:16:08 -	LMT	1912
 			 0:00	-	GMT
+Link Africa/Abidjan Africa/Bamako	# Mali
+Link Africa/Abidjan Africa/Banjul	# Gambia
+Link Africa/Abidjan Africa/Conakry	# Guinea
+Link Africa/Abidjan Africa/Dakar	# Senegal
+Link Africa/Abidjan Africa/Freetown	# Sierra Leone
+Link Africa/Abidjan Africa/Lome		# Togo
+Link Africa/Abidjan Africa/Nouakchott	# Mauritania
+Link Africa/Abidjan Africa/Ouagadougou	# Burkina Faso
+Link Africa/Abidjan Africa/Sao_Tome	# São Tomé and Príncipe
+Link Africa/Abidjan Atlantic/St_Helena	# St Helena
 
 # Djibouti
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -254,30 +250,26 @@ Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
 # Egyptians would approve the cancellation."
 #
 # Egypt to cancel daylight saving time
-# 
 # http://www.almasryalyoum.com/en/node/407168
-# 
 # or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_egypt04.html
-# 
 Rule	Egypt	1995	2010	-	Apr	lastFri	 0:00s	1:00	S
-Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
+Rule	Egypt	1995	2005	-	Sep	lastThu	24:00	0	-
 # From Steffen Thorsen (2006-09-19):
 # The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
 # Egypt will turn back clocks by one hour at the midnight of Thursday
 # after observing the daylight saving time since May.
 # http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
-Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
+Rule	Egypt	2006	only	-	Sep	21	24:00	0	-
 # From Dirk Losch (2007-08-14):
 # I received a mail from an airline which says that the daylight
 # saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
-# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
+# From Jesper Nørgaard Welen (2007-08-15): [The following agree:]
 # http://www.nentjes.info/Bill/bill5.htm
 # http://www.timeanddate.com/worldclock/city.html?n=53
 # From Steffen Thorsen (2007-09-04): The official information...:
 # http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
-Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
+Rule	Egypt	2007	only	-	Sep	Thu>=1	24:00	0	-
 # From Abdelrahman Hassan (2007-09-06):
 # Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
 # than the year of the Gregorian calendar, Ramadan shifts earlier each
@@ -311,15 +303,9 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
 #
 # timeanddate[2] and another site I've found[3] also support that.
 #
-# [1] 
-# https://bugzilla.redhat.com/show_bug.cgi?id=492263
-# 
-# [2] 
-# http://www.timeanddate.com/worldclock/clockchange.html?n=53
-# 
-# [3] 
-# http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
-# 
+# [1] https://bugzilla.redhat.com/show_bug.cgi?id=492263
+# [2] http://www.timeanddate.com/worldclock/clockchange.html?n=53
+# [3] http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
 
 # From Arthur David Olson (2009-04-20):
 # In 2009 (and for the next several years), Ramadan ends before the fourth
@@ -329,14 +315,10 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
 # From Steffen Thorsen (2009-08-11):
 # We have been able to confirm the August change with the Egyptian Cabinet
 # Information and Decision Support Center:
-# 
 # http://www.timeanddate.com/news/time/egypt-dst-ends-2009.html
-# 
 #
 # The Middle East News Agency
-# 
 # http://www.mena.org.eg/index.aspx
-# 
 # also reports "Egypt starts winter time on August 21"
 # today in article numbered "71, 11/08/2009 12:25 GMT."
 # Only the title above is available without a subscription to their service,
@@ -344,19 +326,14 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
 # (at least today).
 
 # From Alexander Krivenyshev (2010-07-20):
-# According to News from Egypt -  Al-Masry Al-Youm Egypt's cabinet has
+# According to News from Egypt - Al-Masry Al-Youm Egypt's cabinet has
 # decided that Daylight Saving Time will not be used in Egypt during
 # Ramadan.
 #
 # Arabic translation:
-# "Clocks to go back during Ramadan--and then forward again"
-# 
+# "Clocks to go back during Ramadan - and then forward again"
 # http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
-# 
 
 # From Ahmad El-Dardiry (2014-05-07):
 # Egypt is to change back to Daylight system on May 15
@@ -365,46 +342,77 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
 # From Gunther Vermier (2015-05-13):
 # our Egypt office confirms that the change will be at 15 May "midnight" (24:00)
 
-# From Paul Eggert (2014-05-13):
+# From Imed Chihi (2014-06-04):
+# We have finally "located" a precise official reference about the DST changes
+# in Egypt.  The Ministers Cabinet decision is explained at
+# http://www.cabinet.gov.eg/Media/CabinetMeetingsDetails.aspx?id=347 ...
+# [T]his (Arabic) site is not accessible outside Egypt, but the page ...
+# translates into: "With regard to daylight saving time, it is scheduled to
+# take effect at exactly twelve o'clock this evening, Thursday, 15 MAY 2014,
+# to be suspended by twelve o'clock on the evening of Thursday, 26 JUN 2014,
+# and re-established again at the end of the month of Ramadan, at twelve
+# o'clock on the evening of Thursday, 31 JUL 2014."  This statement has been
+# reproduced by other (more accessible) sites[, e.g.,]...
+# http://elgornal.net/news/news.aspx?id=4699258
+
+# From Paul Eggert (2014-06-04):
 # Sarah El Deeb and Lee Keath of AP report that the Egyptian government says
 # the change is because of blackouts in Cairo, even though Ahram Online (cited
-# above) says DST had no affect on electricity consumption.  The AP story says
-# DST will not be observed during Ramadan.  There is no information about when
-# DST will end.  See:
+# above) says DST had no affect on electricity consumption.  There is
+# no information about when DST will end this fall.  See:
 # http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833
 #
-# For now, guess that later transitions will use 2010's rules, and that
-# Egypt will agree with Morocco (see below) about the date Ramadan starts and
-# ends, though (unlike Morocco) it will switch at 00:00 standard time.  In
-# Egypt the spring-forward transitions are removed for 2020-2022, when the
-# guessed spring-forward date falls during the estimated Ramadan, and all
-# transitions removed for 2023-2038, where the estimated Ramadan falls entirely
-# outside the guessed daylight-saving time.  Ramadan intrudes on the guessed
-# DST starting in 2039, but that's beyond our somewhat-arbitrary cutoff.
-
-Rule	Egypt	2008	only	-	Aug	lastThu	23:00s	0	-
-Rule	Egypt	2009	only	-	Aug	20	23:00s	0	-
-Rule	Egypt	2010	only	-	Aug	11	0:00	0	-
-Rule	Egypt	2010	only	-	Sep	10	0:00	1:00	S
-Rule	Egypt	2010	only	-	Sep	lastThu	23:00s	0	-
+# For now, guess that later spring and fall transitions will use
+# 2010's rules, and guess that Egypt will switch to standard time at
+# 24:00 the last Thursday before Ramadan, and back to DST at 00:00 the
+# first Friday after Ramadan.  To implement this,
+# transition dates for 2015 through 2037 were determined by running
+# the following program under GNU Emacs 24.3, with the results integrated
+# by hand into the table below.  Ramadan again intrudes on the guessed
+# DST starting in 2038, but that's beyond our somewhat-arbitrary cutoff.
+# (let ((islamic-year 1436))
+#   (while (< islamic-year 1460)
+#     (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year)))
+#           (b (calendar-islamic-to-absolute (list 10 1 islamic-year)))
+#           (friday 5))
+#       (while (/= friday (mod a 7))
+#         (setq a (1- a)))
+#       (while (/= friday (mod b 7))
+#         (setq b (1+ b)))
+#       (setq a (1- a))
+#       (setq b (1- b))
+#       (setq a (calendar-gregorian-from-absolute a))
+#       (setq b (calendar-gregorian-from-absolute b))
+#       (insert
+#        (format
+#         (concat "Rule\tEgypt\t%d\tonly\t-\t%s\t%2d\t24:00\t0\t-\n"
+#                 "Rule\tEgypt\t%d\tonly\t-\t%s\t%2d\t24:00\t1:00\tS\n")
+#         (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
+#         (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
+#     (setq islamic-year (+ 1 islamic-year))))
+Rule	Egypt	2008	only	-	Aug	lastThu	24:00	0	-
+Rule	Egypt	2009	only	-	Aug	20	24:00	0	-
+Rule	Egypt	2010	only	-	Aug	10	24:00	0	-
+Rule	Egypt	2010	only	-	Sep	 9	24:00	1:00	S
+Rule	Egypt	2010	only	-	Sep	lastThu	24:00	0	-
 Rule	Egypt	2014	only	-	May	15	24:00	1:00	S
-Rule	Egypt	2014	only	-	Jun	29	 0:00s	0	-
-Rule	Egypt	2014	only	-	Jul	29	 0:00s	1:00	S
-Rule	Egypt	2014	max	-	Sep	lastThu	23:00s	0	-
+Rule	Egypt	2014	only	-	Jun	26	24:00	0	-
+Rule	Egypt	2014	only	-	Jul	31	24:00	1:00	S
+Rule	Egypt	2014	max	-	Sep	lastThu	24:00	0	-
 Rule	Egypt	2015	2019	-	Apr	lastFri	 0:00s	1:00	S
-Rule	Egypt	2015	only	-	Jun	18	 0:00s	0	-
-Rule	Egypt	2015	only	-	Jul	18	 0:00s	1:00	S
-Rule	Egypt	2016	only	-	Jun	 7	 0:00s	0	-
-Rule	Egypt	2016	only	-	Jul	 7	 0:00s	1:00	S
-Rule	Egypt	2017	only	-	May	27	 0:00s	0	-
-Rule	Egypt	2017	only	-	Jun	26	 0:00s	1:00	S
-Rule	Egypt	2018	only	-	May	16	 0:00s	0	-
-Rule	Egypt	2018	only	-	Jun	15	 0:00s	1:00	S
-Rule	Egypt	2019	only	-	May	 6	 0:00s	0	-
-Rule	Egypt	2019	only	-	Jun	 5	 0:00s	1:00	S
-Rule	Egypt	2020	only	-	May	24	 0:00s	1:00	S
-Rule	Egypt	2021	only	-	May	13	 0:00s	1:00	S
-Rule	Egypt	2022	only	-	May	 3	 0:00s	1:00	S
+Rule	Egypt	2015	only	-	Jun	11	24:00	0	-
+Rule	Egypt	2015	only	-	Jul	23	24:00	1:00	S
+Rule	Egypt	2016	only	-	Jun	 2	24:00	0	-
+Rule	Egypt	2016	only	-	Jul	 7	24:00	1:00	S
+Rule	Egypt	2017	only	-	May	25	24:00	0	-
+Rule	Egypt	2017	only	-	Jun	29	24:00	1:00	S
+Rule	Egypt	2018	only	-	May	10	24:00	0	-
+Rule	Egypt	2018	only	-	Jun	14	24:00	1:00	S
+Rule	Egypt	2019	only	-	May	 2	24:00	0	-
+Rule	Egypt	2019	only	-	Jun	 6	24:00	1:00	S
+Rule	Egypt	2020	only	-	May	28	24:00	1:00	S
+Rule	Egypt	2021	only	-	May	13	24:00	1:00	S
+Rule	Egypt	2022	only	-	May	 5	24:00	1:00	S
 Rule	Egypt	2023	max	-	Apr	lastFri	 0:00s	1:00	S
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -412,60 +420,63 @@ Zone	Africa/Cairo	2:05:09 -	LMT	1900 Oct
 			2:00	Egypt	EE%sT
 
 # Equatorial Guinea
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Malabo	0:35:08 -	LMT	1912
-			0:00	-	GMT	1963 Dec 15
-			1:00	-	WAT
+# See Africa/Lagos.
 
 # Eritrea
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Asmara	2:35:32 -	LMT	1870
-			2:35:32	-	AMT	1890	      # Asmara Mean Time
-			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
+			2:35:32	-	AMT	1890        # Asmara Mean Time
+			2:35:20	-	ADMT	1936 May  5 # Adis Dera MT
 			3:00	-	EAT
 
 # Ethiopia
-# From Paul Eggert (2006-03-22):
-# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
-# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
-# We'll guess that 38E50 is for Adis Dera.
+# From Paul Eggert (2014-07-31):
+# Like the Swahili of Kenya and Tanzania, many Ethiopians keep a
+# 12-hour clock starting at our 06:00, so their "8 o'clock" is our
+# 02:00 or 14:00.  Keep this in mind when you ask the time in Amharic.
+#
+# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time
+# zones between 1870 and 1890, that they merged to 38E50 (2:35:20) in
+# 1890, and that they switched to 3:00 on 1936-05-05.  Perhaps 38E50
+# was for Adis Dera.  Quite likely the Shanks data entries are wrong
+# anyway.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
-			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
+			2:35:20	-	ADMT	1936 May  5 # Adis Dera MT
 			3:00	-	EAT
 
 # Gabon
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Libreville	0:37:48 -	LMT	1912
-			1:00	-	WAT
+# See Africa/Lagos.
 
 # Gambia
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Banjul	-1:06:36 -	LMT	1912
-			-1:06:36 -	BMT	1935	# Banjul Mean Time
-			-1:00	-	WAT	1964
-			 0:00	-	GMT
+# See Africa/Abidjan.
 
 # Ghana
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-# Whitman says DST was observed from 1931 to ``the present'';
-# go with Shanks & Pottenger.
-Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
-Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
+# Whitman says DST was observed from 1931 to "the present";
+# Shanks & Pottenger say 1936 to 1942;
+# and September 1 to January 1 is given by:
+# Scott Keltie J, Epstein M (eds), The Statesman's Year-Book,
+# 57th ed. Macmillan, London (1920), OCLC 609408015, pp xxviii.
+# For lack of better info, assume DST was observed from 1920 to 1942.
+Rule	Ghana	1920	1942	-	Sep	 1	0:00	0:20	GHST
+Rule	Ghana	1920	1942	-	Dec	31	0:00	0	GMT
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Accra	-0:00:52 -	LMT	1918
 			 0:00	Ghana	%s
 
 # Guinea
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Conakry	-0:54:52 -	LMT	1912
-			 0:00	-	GMT	1934 Feb 26
-			-1:00	-	WAT	1960
-			 0:00	-	GMT
+# See Africa/Abidjan.
 
 # Guinea-Bissau
+#
+# Shanks gives 1911-05-26 for the transition to WAT,
+# evidently confusing the date of the Portuguese decree
+# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
+# with the date that it took effect, namely 1912-01-01.
+#
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Bissau	-1:02:20 -	LMT	1911 May 26
+Zone	Africa/Bissau	-1:02:20 -	LMT	1912 Jan  1
 			-1:00	-	WAT	1975
 			 0:00	-	GMT
 
@@ -480,8 +491,8 @@ Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
 # Lesotho
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Maseru	1:50:00 -	LMT	1903 Mar
-			2:00	-	SAST	1943 Sep 19 2:00
-			2:00	1:00	SAST	1944 Mar 19 2:00
+			2:00	-	SAST	1943 Sep 19  2:00
+			2:00	1:00	SAST	1944 Mar 19  2:00
 			2:00	-	SAST
 
 # Liberia
@@ -549,11 +560,11 @@ Zone	Africa/Tripoli	0:52:44 -	LMT	1920
 			2:00	-	EET	1982
 			1:00	Libya	CE%sT	1990 May  4
 # The 1996 and 1997 entries are from Shanks & Pottenger;
-# the IATA SSIM data contain some obvious errors.
+# the IATA SSIM data entries contain some obvious errors.
 			2:00	-	EET	1996 Sep 30
 			1:00	Libya	CE%sT	1997 Oct  4
-			2:00	-	EET	2012 Nov 10 2:00
-			1:00	Libya	CE%sT	2013 Oct 25 2:00
+			2:00	-	EET	2012 Nov 10  2:00
+			1:00	Libya	CE%sT	2013 Oct 25  2:00
 			2:00	-	EET
 
 # Madagascar
@@ -569,18 +580,8 @@ Zone	Africa/Blantyre	2:20:00 -	LMT	1903 Mar
 			2:00	-	CAT
 
 # Mali
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Bamako	-0:32:00 -	LMT	1912
-			 0:00	-	GMT	1934 Feb 26
-			-1:00	-	WAT	1960 Jun 20
-			 0:00	-	GMT
-
 # Mauritania
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
-			 0:00	-	GMT	1934 Feb 26
-			-1:00	-	WAT	1960 Nov 28
-			 0:00	-	GMT
+# See Africa/Abidjan.
 
 # Mauritius
 
@@ -604,9 +605,7 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
 
 # From Steffen Thorsen (2008-07-10):
 # According to
-# 
 # http://www.lexpress.mu/display_article.php?news_id=111216
-# 
 # (in French), Mauritius will start and end their DST a few days earlier
 # than previously announced (2008-11-01 to 2009-03-31).  The new start
 # date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
@@ -621,22 +620,17 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
 
 # From Alex Krivenyshev (2008-07-11):
 # Seems that English language article "The revival of daylight saving
-# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
+# time: Energy conservation?"-# No. 16578 (07/11/2008) was originally
 # published on Monday, June 30, 2008...
 #
 # I guess that article in French "Le gouvernement avance l'introduction
-# de l'heure d'ete" stating that DST in Mauritius starting on October 26
-# and ending on March 27, 2009 is the most recent one.
-# ...
-# 
+# de l'heure d'été" stating that DST in Mauritius starting on October 26
+# and ending on March 27, 2009 is the most recent one....
 # http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
-# 
 
 # From Riad M. Hossen Ally (2008-08-03):
 # The Government of Mauritius weblink
-# 
 # http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
-# 
 # Cabinet Decision of July 18th, 2008 states as follows:
 #
 # 4. ...Cabinet has agreed to the introduction into the National Assembly
@@ -646,33 +640,25 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
 # States of America. It will start at two o'clock in the morning on the
 # last Sunday of October and will end at two o'clock in the morning on
 # the last Sunday of March the following year. The summer time for the
-# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
+# year 2008-2009 will, therefore, be effective as from 26 October 2008
 # and end on 29 March 2009.
 
 # From Ed Maste (2008-10-07):
 # THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
 # beginning / ending of summer time is 2 o'clock standard time in the
 # morning of the last Sunday of October / last Sunday of March.
-# 
 # http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
-# 
 
 # From Steffen Thorsen (2009-06-05):
 # According to several sources, Mauritius will not continue to observe
 # DST the coming summer...
 #
 # Some sources, in French:
-# 
 # http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB
-# 
-# 
 # http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints-
-# 
 #
 # Our wrap-up:
-# 
 # http://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html
-# 
 
 # From Arthur David Olson (2009-07-11):
 # The "mauritius-dst-will-not-repeat" wrapup includes this:
@@ -685,18 +671,18 @@ Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
 Rule Mauritius	2008	only	-	Oct	lastSun	2:00	1:00	S
 Rule Mauritius	2009	only	-	Mar	lastSun	2:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
+Zone Indian/Mauritius	3:50:00 -	LMT	1907 # Port Louis
 			4:00 Mauritius	MU%sT	# Mauritius Time
 # Agalega Is, Rodriguez
 # no information; probably like Indian/Mauritius
 
 # Mayotte
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
+Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul # Mamoutzou
 			3:00	-	EAT
 
 # Morocco
-# See the `europe' file for Spanish Morocco (Africa/Ceuta).
+# See the 'europe' file for Spanish Morocco (Africa/Ceuta).
 
 # From Alex Krivenyshev (2008-05-09):
 # Here is an article that Morocco plan to introduce Daylight Saving Time between
@@ -704,60 +690,44 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 #
 # "... Morocco is to save energy by adjusting its clock during summer so it will
 # be one hour ahead of GMT between 1 June and 27 September, according to
-# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
+# Communication Minister and Government Spokesman, Khalid Naciri...."
 #
-# 
 # http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
-# 
-# OR
-# 
 # http://en.afrik.com/news11892.html
-# 
 
 # From Alex Krivenyshev (2008-05-09):
-# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
-# 
+# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe
+# Presse:
 # http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
-# 
 #
 # Morocco shifts to daylight time on June 1st through September 27, Govt.
 # spokesman.
 
 # From Patrice Scattolin (2008-05-09):
 # According to this article:
-# 
 # http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
-# 
-# (and republished here:
-# 
-# http://www.actu.ma/heure-dete-comment_i127896_0.html
-# 
-# )
-# the changes occurs at midnight:
+# (and republished here: )
+# the changes occur at midnight:
 #
-# saturday night may 31st at midnight (which in french is to be
-# intrepreted as the night between saturday and sunday)
-# sunday night the 28th  at midnight
+# Saturday night May 31st at midnight (which in French is to be
+# interpreted as the night between Saturday and Sunday)
+# Sunday night the 28th at midnight
 #
-# Seeing that the 28th is monday, I am guessing that she intends to say
-# the midnight of the 28th which is the midnight between sunday and
-# monday, which jives with other sources that say that it's inclusive
-# june1st to sept 27th.
+# Seeing that the 28th is Monday, I am guessing that she intends to say
+# the midnight of the 28th which is the midnight between Sunday and
+# Monday, which jives with other sources that say that it's inclusive
+# June 1st to Sept 27th.
 #
 # The decision was taken by decree *2-08-224 *but I can't find the decree
 # published on the web.
 #
 # It's also confirmed here:
-# 
 # http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
-# 
-# on a government portal as being  between june 1st and sept 27th (not yet
-# posted in english).
+# on a government portal as being between June 1st and Sept 27th (not yet
+# posted in English).
 #
-# The following google query will generate many relevant hits:
-# 
+# The following Google query will generate many relevant hits:
 # http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
-# 
 
 # From Steffen Thorsen (2008-08-27):
 # Morocco will change the clocks back on the midnight between August 31
@@ -765,47 +735,32 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 # of September:
 #
 # One article about it (in French):
-# 
 # http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
-# 
 #
 # We have some further details posted here:
-# 
 # http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
-# 
 
 # From Steffen Thorsen (2009-03-17):
 # Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
 # to many sources, such as
-# 
 # http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
-# 
-# 
 # http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
-# 
 # (French)
 #
 # Our summary:
-# 
 # http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
-# 
 
 # From Alexander Krivenyshev (2009-03-17):
 # Here is a link to official document from Royaume du Maroc Premier Ministre,
-# Ministere de la Modernisation des Secteurs Publics
+# Ministère de la Modernisation des Secteurs Publics
 #
 # Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
 # concerning the amendment of the legal time, the Ministry of Modernization of
 # Public Sectors announced that the official time in the Kingdom will be
 # advanced 60 minutes from Sunday 31 May 2009 at midnight.
 #
-# 
 # http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
-# 
-#
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
-# 
 
 # From Steffen Thorsen (2010-04-13):
 # Several news media in Morocco report that the Ministry of Modernization
@@ -813,51 +768,33 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 # 2010-05-02 to 2010-08-08.
 #
 # Example:
-# 
 # http://www.lavieeco.com/actualites/4099-le-maroc-passera-a-l-heure-d-ete-gmt1-le-2-mai.html
-# 
 # (French)
 # Our page:
-# 
 # http://www.timeanddate.com/news/time/morocco-starts-dst-2010.html
-# 
 
 # From Dan Abitol (2011-03-30):
 # ...Rules for Africa/Casablanca are the following (24h format)
-# The 3rd april 2011 at 00:00:00, [it] will be 3rd april 1:00:00
-# The 31th july 2011 at 00:59:59,  [it] will be 31th July 00:00:00
+# The 3rd April 2011 at 00:00:00, [it] will be 3rd April 01:00:00
+# The 31st July 2011 at 00:59:59, [it] will be 31st July 00:00:00
 # ...Official links of change in morocco
 # The change was broadcast on the FM Radio
 # I ve called ANRT (telecom regulations in Morocco) at
 # +212.537.71.84.00
-# 
 # http://www.anrt.net.ma/fr/
-# 
 # They said that
-# 
 # http://www.map.ma/fr/sections/accueil/l_heure_legale_au_ma/view
-# 
 # is the official publication to look at.
 # They said that the decision was already taken.
 #
 # More articles in the press
-# 
-# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-lev
-# 
-# e.html
-# 
+# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-leve.html
 # http://www.lematin.ma/Actualite/Express/Article.asp?id=148923
-# 
-# 
 # http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim
-# anche-prochain-5538.html
-# 
 
 # From Petr Machata (2011-03-30):
 # They have it written in English here:
-# 
 # http://www.map.ma/eng/sections/home/morocco_to_spring_fo/view
-# 
 #
 # It says there that "Morocco will resume its standard time on July 31,
 # 2011 at midnight." Now they don't say whether they mean midnight of
@@ -865,20 +802,16 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 # also been like that in the past.
 
 # From Alexander Krivenyshev (2012-03-09):
-# According to Infomédiaire web site from Morocco (infomediaire.ma),
-# on March 9, 2012, (in French) Heure légale:
-# Le Maroc adopte officiellement l'heure d'été
-# 
+# According to Infomédiaire web site from Morocco (infomediaire.ma),
+# on March 9, 2012, (in French) Heure légale:
+# Le Maroc adopte officiellement l'heure d'été
 # http://www.infomediaire.ma/news/maroc/heure-l%C3%A9gale-le-maroc-adopte-officiellement-lheure-d%C3%A9t%C3%A9
-# 
 # Governing Council adopted draft decree, that Morocco DST starts on
 # the last Sunday of March (March 25, 2012) and ends on
 # last Sunday of September (September 30, 2012)
 # except the month of Ramadan.
 # or (brief)
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_morocco06.html
-# 
 
 # From Arthur David Olson (2012-03-10):
 # The infomediaire.ma source indicates that the system is to be in
@@ -889,17 +822,13 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 
 # From Christophe Tropamer (2012-03-16):
 # Seen Morocco change again:
-# 
 # http://www.le2uminutes.com/actualite.php
-# 
-# "...à partir du dernier dimance d'avril et non fins mars,
-# comme annoncé précédemment."
+# "...à partir du dernier dimanche d'avril et non fins mars,
+# comme annoncé précédemment."
 
 # From Milamber Space Network (2012-07-17):
 # The official return to GMT is announced by the Moroccan government:
-# 
 # http://www.mmsp.gov.ma/fr/actualites.aspx?id=288 [in French]
-# 
 #
 # Google translation, lightly edited:
 # Back to the standard time of the Kingdom (GMT)
@@ -917,7 +846,7 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 # announced a bit in advance.  On 2012-07-11 the Moroccan government
 # announced that year's Ramadan daylight-saving transitions would be
 # 2012-07-20 and 2012-08-20; see
-# .
+# http://www.mmsp.gov.ma/fr/actualites.aspx?id=288
 
 # From Andrew Paprocki (2013-07-02):
 # Morocco announced that the year's Ramadan daylight-savings
@@ -937,39 +866,36 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
 # From Sebastien Willemijns (2014-03-18):
 # http://www.afriquinfos.com/articles/2014/3/18/maroc-heure-dete-avancez-tous-horloges-247891.asp
 
-# From Paul Eggert (2014-03-19):
-# To estimate what the Moroccan government will do in future years,
-# transition dates for 2014 through 2038 were determined by running
-# the following program under GNU Emacs 24.3:
-#
-# (let ((islamic-year 1435))
-#   (while (< islamic-year 1461)
-#     (let ((a
-#	     (calendar-gregorian-from-absolute
-#	      (calendar-islamic-to-absolute (list 9 1 islamic-year))))
-#	    (b
-#	     (calendar-gregorian-from-absolute
-#	      (calendar-islamic-to-absolute (list 10 1 islamic-year)))))
-#	(insert
-#	 (format
-#	  (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 3:00\t0\t-\n"
-#		  "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 2:00\t1:00\tS\n")
-#	  (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
-#	  (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
+# From Milamber Space Network (2014-06-05):
+# The Moroccan government has recently announced that the country will return
+# to standard time at 03:00 on Saturday, June 28, 2014 local time....  DST
+# will resume again at 02:00 on Saturday, August 2, 2014....
+# http://www.mmsp.gov.ma/fr/actualites.aspx?id=586
+
+# From Paul Eggert (2014-06-05):
+# For now, guess that later spring and fall transitions will use 2014's rules,
+# and guess that Morocco will switch to standard time at 03:00 the last
+# Saturday before Ramadan, and back to DST at 02:00 the first Saturday after
+# Ramadan.  To implement this, transition dates for 2015 through 2037 were
+# determined by running the following program under GNU Emacs 24.3, with the
+# results integrated by hand into the table below.
+# (let ((islamic-year 1436))
+#   (while (< islamic-year 1460)
+#     (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year)))
+#           (b (calendar-islamic-to-absolute (list 10 1 islamic-year)))
+#           (saturday 6))
+#       (while (/= saturday (mod (setq a (1- a)) 7)))
+#       (while (/= saturday (mod b 7))
+#         (setq b (1+ b)))
+#       (setq a (calendar-gregorian-from-absolute a))
+#       (setq b (calendar-gregorian-from-absolute b))
+#       (insert
+#        (format
+#         (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 3:00\t0\t-\n"
+#                 "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 2:00\t1:00\tS\n")
+#         (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
+#         (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
 #     (setq islamic-year (+ 1 islamic-year))))
-#
-# with spring-forward transitions removed for 2023-2025, when the
-# normal spring-forward date falls during the estimated Ramadan; with
-# all transitions removed for 2026-2035, where the estimated Ramadan
-# falls entirely outside daylight-saving time; and with fall-back
-# transitions removed for 2036-2037, where the normal fall-back
-# date falls during the estimated Ramadan.  Normally, the table would
-# stop after 2037 because 32-bit time_t values roll around early in 2038,
-# but that would imply a prediction of perpetual DST after March 2038
-# due to the year-2037 glitches.  So, this table instead stops after
-# 2038, the first non-glitchy year after the 32-bit rollover.
-# An advantage of stopping after 2038 is that it lets zic guess
-# TZ='WET0WEST,M3.5.0,M10.5.0/3' for time stamps far in the future.
 
 # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 
@@ -991,46 +917,44 @@ Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
 Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
 Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
 Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
-Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
+Rule	Morocco	2009	only	-	Aug	21	 0:00	0	-
 Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
 Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
 Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
-Rule	Morocco	2011	only	-	Jul	 31	 0	0	-
-Rule	Morocco	2012	2013	-	Apr	 lastSun 2:00	1:00	S
-Rule	Morocco	2012	only	-	Sep	 30	 3:00	0	-
-Rule	Morocco	2012	only	-	Jul	 20	 3:00	0	-
-Rule	Morocco	2012	only	-	Aug	 20	 2:00	1:00	S
-Rule	Morocco	2013	only	-	Jul	  7	 3:00	0	-
-Rule	Morocco	2013	only	-	Aug	 10	 2:00	1:00	S
-Rule	Morocco	2013	2035	-	Oct	 lastSun 3:00	0	-
-Rule	Morocco	2014	2022	-	Mar	 lastSun 2:00	1:00	S
-Rule	Morocco	2014	only	-	Jun	 29	 3:00	0	-
-Rule	Morocco	2014	only	-	Jul	 29	 2:00	1:00	S
-Rule	Morocco	2015	only	-	Jun	 18	 3:00	0	-
-Rule	Morocco	2015	only	-	Jul	 18	 2:00	1:00	S
-Rule	Morocco	2016	only	-	Jun	  7	 3:00	0	-
-Rule	Morocco	2016	only	-	Jul	  7	 2:00	1:00	S
-Rule	Morocco	2017	only	-	May	 27	 3:00	0	-
-Rule	Morocco	2017	only	-	Jun	 26	 2:00	1:00	S
-Rule	Morocco	2018	only	-	May	 16	 3:00	0	-
-Rule	Morocco	2018	only	-	Jun	 15	 2:00	1:00	S
-Rule	Morocco	2019	only	-	May	  6	 3:00	0	-
-Rule	Morocco	2019	only	-	Jun	  5	 2:00	1:00	S
-Rule	Morocco	2020	only	-	Apr	 24	 3:00	0	-
-Rule	Morocco	2020	only	-	May	 24	 2:00	1:00	S
-Rule	Morocco	2021	only	-	Apr	 13	 3:00	0	-
-Rule	Morocco	2021	only	-	May	 13	 2:00	1:00	S
-Rule	Morocco	2022	only	-	Apr	  3	 3:00	0	-
-Rule	Morocco	2022	only	-	May	  3	 2:00	1:00	S
-Rule	Morocco	2023	only	-	Apr	 22	 2:00	1:00	S
-Rule	Morocco	2024	only	-	Apr	 10	 2:00	1:00	S
-Rule	Morocco	2025	only	-	Mar	 31	 2:00	1:00	S
-Rule	Morocco	2026	max	-	Mar	 lastSun 2:00	1:00	S
-Rule	Morocco	2036	only	-	Oct	 21	 3:00	0	-
-Rule	Morocco	2037	only	-	Oct	 11	 3:00	0	-
-Rule	Morocco	2038	only	-	Sep	 30	 3:00	0	-
-Rule	Morocco	2038	only	-	Oct	 30	 2:00	1:00	S
-Rule	Morocco	2038	max	-	Oct	 lastSun 3:00	0	-
+Rule	Morocco	2011	only	-	Jul	31	 0	0	-
+Rule	Morocco	2012	2013	-	Apr	lastSun	 2:00	1:00	S
+Rule	Morocco	2012	only	-	Sep	30	 3:00	0	-
+Rule	Morocco	2012	only	-	Jul	20	 3:00	0	-
+Rule	Morocco	2012	only	-	Aug	20	 2:00	1:00	S
+Rule	Morocco	2013	only	-	Jul	 7	 3:00	0	-
+Rule	Morocco	2013	only	-	Aug	10	 2:00	1:00	S
+Rule	Morocco	2013	max	-	Oct	lastSun	 3:00	0	-
+Rule	Morocco	2014	2022	-	Mar	lastSun	 2:00	1:00	S
+Rule	Morocco	2014	only	-	Jun	28	 3:00	0	-
+Rule	Morocco	2014	only	-	Aug	 2	 2:00	1:00	S
+Rule	Morocco	2015	only	-	Jun	13	 3:00	0	-
+Rule	Morocco	2015	only	-	Jul	18	 2:00	1:00	S
+Rule	Morocco	2016	only	-	Jun	 4	 3:00	0	-
+Rule	Morocco	2016	only	-	Jul	 9	 2:00	1:00	S
+Rule	Morocco	2017	only	-	May	20	 3:00	0	-
+Rule	Morocco	2017	only	-	Jul	 1	 2:00	1:00	S
+Rule	Morocco	2018	only	-	May	12	 3:00	0	-
+Rule	Morocco	2018	only	-	Jun	16	 2:00	1:00	S
+Rule	Morocco	2019	only	-	May	 4	 3:00	0	-
+Rule	Morocco	2019	only	-	Jun	 8	 2:00	1:00	S
+Rule	Morocco	2020	only	-	Apr	18	 3:00	0	-
+Rule	Morocco	2020	only	-	May	30	 2:00	1:00	S
+Rule	Morocco	2021	only	-	Apr	10	 3:00	0	-
+Rule	Morocco	2021	only	-	May	15	 2:00	1:00	S
+Rule	Morocco	2022	only	-	Apr	 2	 3:00	0	-
+Rule	Morocco	2022	only	-	May	 7	 2:00	1:00	S
+Rule	Morocco	2023	only	-	Apr	22	 2:00	1:00	S
+Rule	Morocco	2024	only	-	Apr	13	 2:00	1:00	S
+Rule	Morocco	2025	only	-	Apr	 5	 2:00	1:00	S
+Rule	Morocco	2026	max	-	Mar	lastSun	 2:00	1:00	S
+Rule	Morocco	2035	only	-	Oct	27	 3:00	0	-
+Rule	Morocco	2036	only	-	Oct	18	 3:00	0	-
+Rule	Morocco	2037	only	-	Oct	10	 3:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
@@ -1049,11 +973,17 @@ Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
 # Assume that this has been true since Western Sahara switched to GMT,
 # since most of it was then controlled by Morocco.
 
-Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
+Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan # El Aaiún
 			-1:00	-	WAT	1976 Apr 14
 			 0:00	Morocco	WE%sT
 
 # Mozambique
+#
+# Shanks gives 1903-03-01 for the transition to CAT.
+# Perhaps the 1911-05-26 Portuguese decree
+# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
+# merely made it official?
+#
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
 			2:00	-	CAT
@@ -1062,8 +992,8 @@ Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
 # The 1994-04-03 transition is from Shanks & Pottenger.
 # Shanks & Pottenger report no DST after 1998-04; go with IATA.
 
-# From Petronella Sibeene (2007-03-30) in
-# :
+# From Petronella Sibeene (2007-03-30):
+# http://allafrica.com/stories/200703300178.html
 # While the entire country changes its time, Katima Mulilo and other
 # settlements in Caprivi unofficially will not because the sun there
 # rises and sets earlier compared to other regions.  Chief of
@@ -1080,34 +1010,41 @@ Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
 Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Windhoek	1:08:24 -	LMT	1892 Feb 8
-			1:30	-	SWAT	1903 Mar	# SW Africa Time
-			2:00	-	SAST	1942 Sep 20 2:00
-			2:00	1:00	SAST	1943 Mar 21 2:00
+			1:30	-	SWAT	1903 Mar    # SW Africa Time
+			2:00	-	SAST	1942 Sep 20  2:00
+			2:00	1:00	SAST	1943 Mar 21  2:00
 			2:00	-	SAST	1990 Mar 21 # independence
 			2:00	-	CAT	1994 Apr  3
 			1:00	Namibia	WA%sT
 
 # Niger
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Niamey	 0:08:28 -	LMT	1912
-			-1:00	-	WAT	1934 Feb 26
-			 0:00	-	GMT	1960
-			 1:00	-	WAT
+# See Africa/Lagos.
 
 # Nigeria
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Lagos	0:13:36 -	LMT	1919 Sep
 			1:00	-	WAT
+Link Africa/Lagos Africa/Bangui	     # Central African Republic
+Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo
+Link Africa/Lagos Africa/Douala	     # Cameroon
+Link Africa/Lagos Africa/Kinshasa    # Dem. Rep. of the Congo (west)
+Link Africa/Lagos Africa/Libreville  # Gabon
+Link Africa/Lagos Africa/Luanda	     # Angola
+Link Africa/Lagos Africa/Malabo	     # Equatorial Guinea
+Link Africa/Lagos Africa/Niamey	     # Niger
+Link Africa/Lagos Africa/Porto-Novo  # Benin
 
-# Reunion
+# Réunion
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun	# Saint-Denis
-			4:00	-	RET	# Reunion Time
+Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun # Saint-Denis
+			4:00	-	RET	# Réunion Time
 #
-# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
+# Crozet Islands also observes Réunion time; see the 'antarctica' file.
+#
+# Scattered Islands (Îles Éparses) administered from Réunion are as follows.
 # The following information about them is taken from
-# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
-# no longer available as of 1999-08-17).
+# Îles Éparses (, 1997-07-22,
+# in French; no longer available as of 1999-08-17).
 # We have no info about their time zone histories.
 #
 # Bassas da India - uninhabited
@@ -1122,32 +1059,21 @@ Zone	Africa/Kigali	2:00:16 -	LMT	1935 Jun
 			2:00	-	CAT
 
 # St Helena
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Atlantic/St_Helena	-0:22:48 -	LMT	1890		# Jamestown
-			-0:22:48 -	JMT	1951	# Jamestown Mean Time
-			 0:00	-	GMT
+# See Africa/Abidjan.
 # The other parts of the St Helena territory are similar:
 #	Tristan da Cunha: on GMT, say Whitman and the CIA
-#	Ascension: on GMT, says usno1995 and the CIA
+#	Ascension: on GMT, say the USNO (1995-12-21) and the CIA
 #	Gough (scientific station since 1955; sealers wintered previously):
 #		on GMT, says the CIA
-#	Inaccessible, Nightingale: no information, but probably GMT
-
-# Sao Tome and Principe
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Sao_Tome	 0:26:56 -	LMT	1884
-			-0:36:32 -	LMT	1912	# Lisbon Mean Time
-			 0:00	-	GMT
+#	Inaccessible, Nightingale: uninhabited
 
+# São Tomé and Príncipe
 # Senegal
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Dakar	-1:09:44 -	LMT	1912
-			-1:00	-	WAT	1941 Jun
-			 0:00	-	GMT
+# See Africa/Abidjan.
 
 # Seychelles
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
+Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun # Victoria
 			4:00	-	SCT	# Seychelles Time
 # From Paul Eggert (2001-05-30):
 # Aldabra, Farquhar, and Desroches, originally dependencies of the
@@ -1157,17 +1083,7 @@ Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
 # Possibly the islands were uninhabited.
 
 # Sierra Leone
-# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
-Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
-Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
-Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
-Rule	SL	1957	1962	-	Sep	 1	0:00	0	GMT
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Freetown	-0:53:00 -	LMT	1882
-			-0:53:00 -	FMT	1913 Jun # Freetown Mean Time
-			-1:00	SL	%s	1957
-			 0:00	SL	%s
+# See Africa/Abidjan.
 
 # Somalia
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -1190,9 +1106,9 @@ Zone Africa/Johannesburg 1:52:00 -	LMT	1892 Feb 8
 
 # Sudan
 #
-# From 
-# Sudan News Agency (2000-01-13)
-# , also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
+# From 
+# Sudan News Agency (2000-01-13),
+# also reported by Michaël De Beukelaer-Dossche via Steffen Thorsen:
 # Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
 # Saturday....  This was announced Thursday by Caretaker State Minister for
 # Manpower Abdul-Rahman Nur-Eddin.
@@ -1223,14 +1139,12 @@ Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
 			3:00	-	EAT
 
 # Togo
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Africa/Lome	0:04:52 -	LMT	1893
-			0:00	-	GMT
+# See Africa/Abidjan.
 
 # Tunisia
 
 # From Gwillim Law (2005-04-30):
-# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
+# My correspondent, Risto Nykänen, has alerted me to another adoption of DST,
 # this time in Tunisia.  According to Yahoo France News
 # , in a story attributed to AP
 # and dated 2005-04-26, "Tunisia has decided to advance its official time by
@@ -1239,8 +1153,8 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
 # Saturday."  (My translation)
 #
 # From Oscar van Vlijmen (2005-05-02):
-# LaPresse, the first national daily newspaper ...
-# 
+# La Presse, the first national daily newspaper ...
+# http://www.lapresse.tn/archives/archives280405/actualites/lheure.html
 # ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
 # 1h standard time.
 #
@@ -1253,18 +1167,12 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
 # From Steffen Thorsen (2009-03-16):
 # According to several news sources, Tunisia will not observe DST this year.
 # (Arabic)
-# 
 # http://www.elbashayer.com/?page=viewn&nid=42546
-# 
-# 
 # http://www.babnet.net/kiwidetail-15295.asp
-# 
 #
 # We have also confirmed this with the US embassy in Tunisia.
 # We have a wrap-up about this on the following page:
-# 
 # http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
-# 
 
 # From Alexander Krivenyshev (2009-03-17):
 # Here is a link to Tunis Afrique Presse News Agency
@@ -1272,20 +1180,17 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
 # Standard time to be kept the whole year long (tap.info.tn):
 #
 # (in English)
-# 
 # http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
-# 
 #
 # (in Arabic)
-# 
 # http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
-# 
 
-# From Arthur David Olson (2009--3-18):
-# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
-# that the fasting month of ramadan coincides with the period concerned by summer time.
-# Therefore, the standard time will be kept unchanged the whole year long."
-# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
+# From Arthur David Olson (2009-03-18):
+# The Tunis Afrique Presse News Agency notice contains this: "This measure is
+# due to the fact that the fasting month of Ramadan coincides with the period
+# concerned by summer time.  Therefore, the standard time will be kept
+# unchanged the whole year long."  So foregoing DST seems to be an exception
+# (albeit one that may be repeated in the future).
 
 # From Alexander Krivenyshev (2010-03-27):
 # According to some news reports Tunis confirmed not to use DST in 2010
@@ -1297,12 +1202,8 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
 # coincided with the month of Ramadan..."
 #
 # (in Arabic)
-# 
 # http://www.moheet.com/show_news.aspx?nid=358861&pg=1
-# 
 # http://www.almadenahnews.com/newss/news.php?c=118&id=38036
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_tunis02.html
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
@@ -1337,7 +1238,7 @@ Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
 # Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
-			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
+			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
 			1:00	Tunisia	CE%sT
 
 # Uganda
diff --git a/jdk/make/data/tzdata/antarctica b/jdk/make/data/tzdata/antarctica
index e31bada94fb..0cdac270861 100644
--- a/jdk/make/data/tzdata/antarctica
+++ b/jdk/make/data/tzdata/antarctica
@@ -21,19 +21,16 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
 # From Paul Eggert (1999-11-15):
 # To keep things manageable, we list only locations occupied year-round; see
-# 
 # COMNAP - Stations and Bases
-# 
+# http://www.comnap.aq/comnap/comnap.nsf/P/Stations/
 # and
-# 
 # Summary of the Peri-Antarctic Islands (1998-07-23)
-# 
+# http://www.spri.cam.ac.uk/bob/periant.htm
 # for information.
 # Unless otherwise specified, we have no time zone information.
 #
@@ -78,19 +75,19 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
 
 # Argentina - year-round bases
 # Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
-# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
-# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
-# Marambio, Seymour I, -6414-05637, since 1969-10-29
+# Carlini, Potter Cove, King George Island, -6414-0602320, since 1982-01
+# Esperanza, Hope Bay, -6323-05659, since 1952-12-17
+# Marambio, -6414-05637, since 1969-10-29
 # Orcadas, Laurie I, -6016-04444, since 1904-02-22
-# San Martin, Debenham I, -6807-06708, since 1951-03-21
+# San Martín, Barry I, -6808-06706, since 1951-03-21
 #	(except 1960-03 / 1976-03-21)
 
 # Australia - territories
 # Heard Island, McDonald Islands (uninhabited)
 #	previously sealers and scientific personnel wintered
-#	
 #	Margaret Turner reports
-#	 (1999-09-30) that they're UTC+5, with no DST;
+#	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;
 #	presumably this is when they have visitors.
 #
 # year-round bases
@@ -107,14 +104,10 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
 # The changes occurred on 2009-10-18 at 02:00 (local times).
 #
 # Government source: (Australian Antarctic Division)
-# 
 # http://www.aad.gov.au/default.asp?casid=37079
-# 
 #
 # We have more background information here:
-# 
 # http://www.timeanddate.com/news/time/antarctica-new-times.html
-# 
 
 # From Steffen Thorsen (2010-03-10):
 # We got these changes from the Australian Antarctic Division: ...
@@ -129,50 +122,49 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
 # - Mawson station stays on UTC+5.
 #
 # Background:
-# 
 # http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
-# 
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Antarctica/Casey	0	-	zzz	1969
-			8:00	-	WST	2009 Oct 18 2:00
-						# Western (Aus) Standard Time
-			11:00	-	CAST	2010 Mar 5 2:00
-						# Casey Time
-			8:00	-	WST	2011 Oct 28 2:00
+			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	-	WST
+			8:00	-	AWST
 Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
-			7:00	-	DAVT	1964 Nov # Davis Time
+			7:00	-	DAVT	1964 Nov    # Davis Time
 			0	-	zzz	1969 Feb
-			7:00	-	DAVT	2009 Oct 18 2:00
+			7:00	-	DAVT	2009 Oct 18  2:00
 			5:00	-	DAVT	2010 Mar 10 20:00u
-			7:00	-	DAVT	2011 Oct 28 2:00
+			7:00	-	DAVT	2011 Oct 28  2:00
 			5:00	-	DAVT	2012 Feb 21 20:00u
 			7:00	-	DAVT
 Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
-			6:00	-	MAWT	2009 Oct 18 2:00
-						# Mawson Time
+			6:00	-	MAWT	2009 Oct 18  2:00 # Mawson Time
 			5:00	-	MAWT
 # References:
-# 
 # Casey Weather (1998-02-26)
-# 
-# 
+# http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html
 # Davis Station, Antarctica (1998-02-26)
-# 
-# 
+# http://www.antdiv.gov.au/aad/exop/sfo/davis/video.html
 # Mawson Station, Antarctica (1998-02-25)
-# 
+# http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html
+
+# Belgium - year-round base
+# Princess Elisabeth, Queen Maud Land, -713412+0231200, since 2007
 
 # Brazil - year-round base
-# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
+# Ferraz, King George Island, -6205+05824, since 1983/4
+
+# Bulgaria - year-round base
+# St. Kliment Ohridski, Livingston Island, -623829-0602153, since 1988
 
 # Chile - year-round bases and towns
 # Escudero, South Shetland Is, -621157-0585735, since 1994
-# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
-# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
-# Capitan Arturo Prat, -6230-05941
+# Frei Montalva, King George Island, -6214-05848, since 1969-03-07
+# O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
+# Prat, -6230-05941
 # Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
 # These locations have always used Santiago time; use TZ='America/Santiago'.
 
@@ -180,31 +172,35 @@ Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
 # Great Wall, King George Island, -6213-05858, since 1985-02-20
 # Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
 
-# France - year-round bases
+# France - year-round bases (also see "France & Italy")
 #
 # From Antoine Leca (1997-01-20):
-# Time data are from Nicole Pailleau at the IFRTP
+# Time data entries are from Nicole Pailleau at the IFRTP
 # (French Institute for Polar Research and Technology).
-# She confirms that French Southern Territories and Terre Adelie bases
-# don't observe daylight saving time, even if Terre Adelie supplies came
+# She confirms that French Southern Territories and Terre Adélie bases
+# don't observe daylight saving time, even if Terre Adélie supplies came
 # from Tasmania.
 #
 # French Southern Territories with year-round inhabitants
 #
-# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
-# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
-# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
+# Alfred Faure, Possession Island, Crozet Islands, -462551+0515152, since 1964;
+#	sealing & whaling stations operated variously 1802/1911+;
+#	see Indian/Reunion.
+#
+# Martin-de-Viviès, Amsterdam Island, -374105+0773155, since 1950
+# Port-aux-Français, Kerguelen Islands, -492110+0701303, since 1951;
 #	whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
 #
 # St Paul Island - near Amsterdam, uninhabited
 #	fishing stations operated variously 1819/1931
 #
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Indian/Kerguelen	0	-	zzz	1950	# Port-aux-Francais
+Zone Indian/Kerguelen	0	-	zzz	1950 # Port-aux-Français
 			5:00	-	TFT	# ISO code TF Time
 #
 # year-round base in the main continent
-# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
+# Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11
+#  (2005-12-05)
 #
 # Another base at Port-Martin, 50km east, began operation in 1947.
 # It was destroyed by fire on 1952-01-14.
@@ -214,20 +210,22 @@ Zone Antarctica/DumontDUrville 0 -	zzz	1947
 			10:00	-	PMT	1952 Jan 14 # Port-Martin Time
 			0	-	zzz	1956 Nov
 			10:00	-	DDUT	# Dumont-d'Urville Time
-# Reference:
-# 
-# Dumont d'Urville Station (2005-12-05)
-# 
+
+# France & Italy - year-round base
+# Concordia, -750600+1232000, since 2005
 
 # Germany - year-round base
-# Georg von Neumayer, -7039-00815
+# Neumayer III, -704080-0081602, since 2009
 
-# India - year-round base
-# Dakshin Gangotri, -7005+01200
+# India - year-round bases
+# Bharati, -692428+0761114, since 2012
+# Maitri, -704558+0114356, since 1989
+
+# Italy - year-round base (also see "France & Italy")
+# Zuchelli, Terra Nova Bay, -744140+1640647, since 1986
 
 # Japan - year-round bases
-# Dome Fuji, -7719+03942
-# Syowa, -690022+0393524
+# Syowa (also known as Showa), -690022+0393524, since 1957
 #
 # From Hideyuki Suzuki (1999-02-06):
 # In all Japanese stations, +0300 is used as the standard time.
@@ -239,11 +237,11 @@ Zone Antarctica/DumontDUrville 0 -	zzz	1947
 Zone Antarctica/Syowa	0	-	zzz	1957 Jan 29
 			3:00	-	SYOT	# Syowa Time
 # See:
-# 
 # NIPR Antarctic Research Activities (1999-08-17)
-# 
+# http://www.nipr.ac.jp/english/ara01.html
 
 # S Korea - year-round base
+# Jang Bogo, Terra Nova Bay, -743700+1641205 since 2014
 # King Sejong, King George Island, -6213-05847, since 1988
 
 # New Zealand - claims
@@ -287,11 +285,14 @@ Rule	Troll	2005	max	-	Mar	lastSun	1:00u	2:00	CEST
 Rule	Troll	2004	max	-	Oct	lastSun	1:00u	0:00	UTC
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
-     			0:00	Troll	%s
+			0:00	Troll	%s
 
 # Poland - year-round base
 # Arctowski, King George Island, -620945-0582745, since 1977
 
+# Romania - year-bound base
+# Law-Racoviță, Larsemann Hills, -692319+0762251, since 1986
+
 # Russia - year-round bases
 # Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
 # Mirny, Davis coast, -6633+09301, since 1956-02
@@ -301,8 +302,8 @@ Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
 #	year-round from 1960/61 to 1992
 
 # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
-# 
-# From Craig Mundell (1994-12-15):
+# From Craig Mundell (1994-12-15):
+# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP
 # Vostok, which is one of the Russian stations, is set on the same
 # time as Moscow, Russia.
 #
@@ -317,7 +318,7 @@ Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
 #
 # From Paul Eggert (2001-05-04):
 # This seems to be hopelessly confusing, so I asked Lee Hotz about it
-# in person.  He said that some Antartic locations set their local
+# in person.  He said that some Antarctic locations set their local
 # time so that noon is the warmest part of the day, and that this
 # changes during the year and does not necessarily correspond to mean
 # solar noon.  So the Vostok time might have been whatever the clocks
@@ -329,9 +330,12 @@ Zone Antarctica/Vostok	0	-	zzz	1957 Dec 16
 
 # S Africa - year-round bases
 # Marion Island, -4653+03752
-# Sanae, -7141-00250
+# SANAE IV, Vesleskarvet, Queen Maud Land, -714022-0025026, since 1997
 
-# UK
+# Ukraine - year-round base
+# Vernadsky (formerly Faraday), Galindez Island, -651445-0641526, since 1954
+
+# United Kingdom
 #
 # British Antarctic Territories (BAT) claims
 # South Orkney Islands
@@ -387,7 +391,7 @@ Zone Antarctica/Palmer	0	-	zzz	1965
 # but that he found it more convenient to keep GMT+12
 # as supplies for the station were coming from McMurdo Sound,
 # which was on GMT+12 because New Zealand was on GMT+12 all year
-# at that time (1957).  (Source: Siple's book 90 degrees SOUTH.)
+# at that time (1957).  (Source: Siple's book 90 Degrees South.)
 #
 # From Susan Smith
 # http://www.cybertours.com/whs/pole10.html
diff --git a/jdk/make/data/tzdata/asia b/jdk/make/data/tzdata/asia
index 595c8ed7245..906c0a97cda 100644
--- a/jdk/make/data/tzdata/asia
+++ b/jdk/make/data/tzdata/asia
@@ -21,13 +21,13 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
 # From Paul Eggert (2013-08-11):
 #
@@ -49,13 +49,17 @@
 # I found in the UCLA library.
 #
 # For data circa 1899, a common source is:
-# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
-# .
+# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
+# http://www.jstor.org/stable/1774359
+#
+# For Russian data circa 1919, a source is:
+# Byalokoz EL. New Counting of Time in Russia since July 1, 1919.
+# (See the 'europe' file for a fuller citation.)
 #
 # A reliable and entertaining source about time zones is
 # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
 #
-# I invented the abbreviations marked `*' in the following table;
+# I invented the abbreviations marked '*' in the following table;
 # the rest are from earlier versions of this file, or from other sources.
 # Corrections are welcome!
 #	     std  dst
@@ -70,13 +74,14 @@
 #	7:00 WIB	west Indonesia (Waktu Indonesia Barat)
 #	8:00 WITA	central Indonesia (Waktu Indonesia Tengah)
 #	8:00 CST	China
-#	9:00 CJT	Central Japanese Time (1896/1937)*
+#	8:00 JWST	Western Standard Time (Japan, 1896/1937)*
+#	9:00 JCST	Central Standard Time (Japan, 1896/1937)
 #	9:00 WIT	east Indonesia (Waktu Indonesia Timur)
 #	9:00 JST  JDT	Japan
 #	9:00 KST  KDT	Korea
-#	9:30 CST	(Australian) Central Standard Time
+#	9:30 ACST	Australian Central Standard Time
 #
-# See the `europe' file for Russia and Turkey in Asia.
+# See the 'europe' file for Russia and Turkey in Asia.
 
 # From Guy Harris:
 # Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
@@ -86,7 +91,7 @@
 
 ###############################################################################
 
-# These rules are stolen from the `europe' file.
+# These rules are stolen from the 'europe' file.
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
 Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
@@ -138,11 +143,11 @@ Zone	Asia/Kabul	4:36:48 -	LMT	1890
 # 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
+			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
+			3:00 RussiaAsia	AM%sT	1995 Sep 24  2:00s
 			4:00	-	AMT	1997
-			4:00 RussiaAsia	AM%sT	2012 Mar 25 2:00s
+			4:00 RussiaAsia	AM%sT	2012 Mar 25  2:00s
 			4:00	-	AMT
 
 # Azerbaijan
@@ -155,16 +160,16 @@ Rule	Azer	1997	max	-	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
+			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 lastSat 23:00
-			4:00	-	AZT	1996 # Azerbaijan time
+			4:00	-	AZT	1996     # Azerbaijan Time
 			4:00	EUAsia	AZ%sT	1997
 			4:00	Azer	AZ%sT
 
 # Bahrain
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
+Zone	Asia/Bahrain	3:22:20 -	LMT	1920     # Manamah
 			4:00	-	GST	1972 Jun
 			3:00	-	AST
 
@@ -174,13 +179,8 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 # Daylight Saving Time from June 16 to Sept 30
 #
 # Bangladesh to introduce daylight saving time likely from June 16
-# 
 # http://www.asiantribune.com/?q=node/17288
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_bangladesh02.html
-# 
 #
 # "... Bangladesh government has decided to switch daylight saving time from
 # June
@@ -195,17 +195,11 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 # the 19th and 20th, and they have not set the end date yet.
 #
 # Some sources:
-# 
 # http://in.reuters.com/article/southAsiaNews/idINIndia-40017620090601
-# 
-# 
 # http://bdnews24.com/details.php?id=85889&cid=2
-# 
 #
 # Our wrap-up:
-# 
 # http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
-# 
 
 # From A. N. M. Kamrus Saadat (2009-06-15):
 # Finally we've got the official mail regarding DST start time where DST start
@@ -220,13 +214,8 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 #
 # Following report by same newspaper-"The Daily Star Friday":
 # "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
-# 
 # http://www.thedailystar.net/newDesign/news-details.php?nid=107021
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
-# 
 
 # From Steffen Thorsen (2009-10-13):
 # IANS (Indo-Asian News Service) now reports:
@@ -235,22 +224,15 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 # "continue for an indefinite period."
 #
 # One of many places where it is published:
-# 
 # http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
-# 
 
 # From Alexander Krivenyshev (2009-12-24):
 # According to Bangladesh newspaper "The Daily Star,"
 # Bangladesh will change its clock back to Standard Time on Dec 31, 2009.
 #
 # Clock goes back 1-hr on Dec 31 night.
-# 
 # http://www.thedailystar.net/newDesign/news-details.php?nid=119228
-# 
-# and
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_bangladesh05.html
-# 
 #
 # "...The government yesterday decided to put the clock back by one hour
 # on December 31 midnight and the new time will continue until March 31,
@@ -260,17 +242,12 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 # From Alexander Krivenyshev (2010-03-22):
 # According to Bangladesh newspaper "The Daily Star,"
 # Cabinet cancels Daylight Saving Time
-# 
 # http://www.thedailystar.net/newDesign/latest_news.php?nid=22817
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_bangladesh06.html
-# 
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Dhaka	2009	only	-	Jun	19	23:00	1:00	S
-Rule	Dhaka	2009	only	-	Dec	31	23:59	0	-
+Rule	Dhaka	2009	only	-	Dec	31	24:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Dhaka	6:01:40 -	LMT	1890
@@ -301,7 +278,7 @@ Zone	Indian/Chagos	4:49:40	-	LMT	1907
 
 # Brunei
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
+Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar # Bandar Seri Begawan
 			7:30	-	BNT	1933
 			8:00	-	BNT
 
@@ -310,16 +287,16 @@ Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
 # 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
-			6:24:40	-	RMT	1920	   # Rangoon Mean Time?
-			6:30	-	BURT	1942 May   # Burma Time
-			9:00	-	JST	1945 May 3
-			6:30	-	MMT		   # Myanmar Time
+Zone	Asia/Rangoon	6:24:40 -	LMT	1880        # or Yangon
+			6:24:40	-	RMT	1920        # Rangoon Mean Time?
+			6:30	-	BURT	1942 May    # Burma Time
+			9:00	-	JST	1945 May  3
+			6:30	-	MMT	# Myanmar Time
 
 # Cambodia
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
-			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
 			7:00	-	ICT	1912 May
 			8:00	-	ICT	1931 May
 			7:00	-	ICT
@@ -332,12 +309,12 @@ Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
 # From Bob Devine (1988-01-28):
 # No they don't.  See TIME mag, 1986-02-17 p.52.  Even though
 # China is across 4 physical time zones, before Feb 1, 1986 only the
-# Peking (Bejing) time zone was recognized.  Since that date, China
-# has two of 'em -- Peking's and Urumqi (named after the capital of
+# Peking (Beijing) time zone was recognized.  Since that date, China
+# has two of 'em - Peking's and Ürümqi (named after the capital of
 # the Xinjiang Uyghur Autonomous Region).  I don't know about DST for it.
 #
 # . . .I just deleted the DST table and this editor makes it too
-# painful to suck in another copy..  So, here is what I have for
+# painful to suck in another copy.  So, here is what I have for
 # DST start/end dates for Peking's time zone (info from AP):
 #
 #     1986 May 4 - Sept 14
@@ -347,15 +324,16 @@ Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
 # CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
 # CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
 
-# From Paul Eggert (2006-03-22):
-# Shanks & Pottenger write that China (except for Hong Kong and Macau)
-# has had a single time zone since 1980 May 1, observing summer DST
-# from 1986 through 1991; this contradicts Devine's
-# note about Time magazine, though apparently _something_ happened in 1986.
-# Go with Shanks & Pottenger for now.  I made up names for the other
-# pre-1980 time zones.
+# From Paul Eggert (2008-02-11):
+# Jim Mann, "A clumsy embrace for another western custom: China on daylight
+# time - sort of", Los Angeles Times, 1986-05-05 ... [says] that China began
+# observing daylight saving time in 1986.
 
-# From Shanks & Pottenger:
+# From Paul Eggert (2014-06-30):
+# Shanks & Pottenger have China switching to a single time zone in 1980, but
+# this doesn't seem to be correct.  They also write that China observed summer
+# DST from 1986 through 1991, which seems to match the above commentary, so
+# go with them for DST rules as follows:
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
 Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
@@ -369,7 +347,7 @@ Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
 # historic timezones from some Taiwan websites.  And yes, there are official
 # Chinese names for these locales (before 1949).
 #
-# From Jesper Norgaard Welen (2006-07-14):
+# From Jesper Nørgaard Welen (2006-07-14):
 # I have investigated the timezones around 1970 on the
 # http://www.astro.com/atlas site [with provinces and county
 # boundaries summarized below]....  A few other exceptions were two
@@ -380,65 +358,97 @@ Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
 # (could be true), for the moment I am assuming that those two
 # counties are mistakes in the astro.com data.
 
-# From Paul Eggert (2008-02-11):
-# I just now checked Google News for western news sources that talk
-# about China's single time zone, and couldn't find anything before 1986
-# talking about China being in one time zone.  (That article was: Jim
-# Mann, "A clumsy embrace for another western custom: China on daylight
-# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
-# article confirms the tz database's data claiming that China began
-# observing daylight saving time in 1986.
+# From Paul Eggert (2014-06-30):
+# Alois Treindl kindly sent me translations of the following two sources:
 #
-# From Thomas S. Mullaney (2008-02-11):
-# I think you're combining two subjects that need to treated
-# separately: daylight savings (which, you're correct, wasn't
-# implemented until the 1980s) and the unified time zone centered near
-# Beijing (which was implemented in 1949). Briefly, there was also a
-# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was
-# ceased, and the second eventually recognized (again, in the 1980s).
+# (1)
+# Guo Qingsheng (National Time-Service Center, CAS, Xi'an 710600, China)
+# Beijing Time at the Beginning of the PRC
+# China Historical Materials of Science and Technology
+# (Zhongguo ke ji shi liao, 中国科技史料), Vol. 24, No. 1 (2003)
+# It gives evidence that at the beginning of the PRC, Beijing time was
+# officially apparent solar time!  However, Guo also says that the
+# evidence is dubious, as the relevant institute of astronomy had not
+# been taken over by the PRC yet.  It's plausible that apparent solar
+# time was announced but never implemented, and that people continued
+# to use UT+8.  As the Shanghai radio station (and I presume the
+# observatory) was still under control of French missionaries, it
+# could well have ignored any such mandate.
 #
-# From Paul Eggert (2008-06-30):
-# There seems to be a good chance China switched to a single time zone in 1949
-# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
-# reliable documentary source saying so yet, so for now we still go with
-# Shanks & Pottenger.
-
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-# Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
+# (2)
+# Guo Qing-sheng (Shaanxi Astronomical Observatory, CAS, Xi'an 710600, China)
+# A Study on the Standard Time Changes for the Past 100 Years in China
+# [undated and unknown publication location]
+# It says several things:
+#   * The Qing dynasty used local apparent solar time throughout China.
+#   * The Republic of China instituted Beijing mean solar time effective
+#     the official calendar book of 1914.
+#   * The French Concession in Shanghai set up signal stations in
+#     French docks in the 1890s, controlled by Xujiahui (Zikawei)
+#     Observatory and set to local mean time.
+#   * "From the end of the 19th century" it changed to UT+8.
+#   * Chinese Customs (by then reduced to a tool of foreign powers)
+#     eventually standardized on this time for all ports, and it
+#     became used by railways as well.
+#   * In 1918 the Central Observatory proposed dividing China into
+#     five time zones (see below for details).  This caught on
+#     at first only in coastal areas observing UT+8.
+#   * During WWII all of China was in theory was at UT+7.  In practice
+#     this was ignored in the west, and I presume was ignored in
+#     Japanese-occupied territory.
+#   * Japanese-occupied Manchuria was at UT+9, i.e., Japan time.
+#   * The five-zone plan was resurrected after WWII and officially put into
+#     place (with some modifications) in March 1948.  It's not clear
+#     how well it was observed in areas under Nationalist control.
+#   * The People's Liberation Army used UT+8 during the civil war.
+#
+# An AP article "Shanghai Internat'l Area Little Changed" in the
+# 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.
+#
+# 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.
+# This has now been simplified to the two entries Asia/Shanghai and
+# Asia/Urumqi, with the others being links for backward compatibility.
+# 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
+# Asia/Harbin (currently a link to Asia/Shanghai)
 # Heilongjiang (except Mohe county), Jilin
-Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
-			8:30	-	CHAT	1932 Mar # Changbai Time
-			8:00	-	CST	1940
-			9:00	-	CHAT	1966 May
-			8:30	-	CHAT	1980 May
-			8:00	PRC	C%sT
-# Zhongyuan Time ("Central plain Time")
+#
+# Zhongyuan Time ("Central plain Time") UT+8
+# Asia/Shanghai
 # most of China
-# Milne gives 8:05:56.7; round to nearest.
-Zone	Asia/Shanghai	8:05:57	-	LMT	1928
-			8:00	Shang	C%sT	1949
-			8:00	PRC	C%sT
-# Long-shu Time (probably due to Long and Shu being two names of that area)
+# 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".
+#
+# Long-shu Time (probably due to Long and Shu being two names of that area) UT+7
+# 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.
-Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
-			7:00	-	LONT	1980 May # Long-shu Time
-			8:00	PRC	C%sT
-# Xin-zang Time ("Xinjiang-Tibet Time")
+#
+# Xin-zang Time ("Xinjiang-Tibet Time") UT+6
+# Asia/Urumqi
+# This currently represents Kunlun Time as well,
+# as apparently the two regions have been the same since 1970.
 # The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
 # the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
 # Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
 # east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
-# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
+# east Xinjiang, including Ürümqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
 # Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
 # Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
 # Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
-Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
-			6:00	-	URUT	1980 May # Urumqi Time
-			8:00	PRC	C%sT
-# Kunlun Time
+#
+# Kunlun Time UT+5.5
+# 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,
 # Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
@@ -455,9 +465,9 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
 # population of Xinjiang, typically use "Xinjiang time" which is two
 # hours behind Beijing time, or UTC +0600. The government of the Xinjiang
 # Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as
-# local governments such as the Urumqi city government use both times in
+# local governments such as the Ürümqi city government use both times in
 # publications, referring to what is popularly called Xinjiang time as
-# "Urumqi time." When Uyghurs make an appointment in the Uyghur language
+# "Ürümqi time." When Uyghurs make an appointment in the Uyghur language
 # they almost invariably use Xinjiang time.
 #
 # (Their ethnic Han compatriots would typically have no clue of its
@@ -469,21 +479,6 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
 # the province not having dual times but four times in use at the same
 # time. Some areas remained on standard Xinjiang time or Beijing time and
 # others moving their clocks ahead.)
-#
-# ...an example of an official website using of Urumqi time.
-#
-# The first few lines of the Google translation of
-# 
-# http://www.fjysgl.gov.cn/show.aspx?id=2379&cid=39
-# 
-# (retrieved 2009-10-13)
-# > Urumqi fire seven people are missing the alleged losses of at least
-# > 500 million yuan
-# >
-# > (Reporter Dong Liu) the day before 20:20 or so (Urumqi Time 18:20),
-# > Urumqi City Department of International Plaza Luther Qiantang River
-# > burst fire. As of yesterday, 18:30, Urumqi City Fire officers and men
-# > have worked continuously for 22 hours...
 
 # From Luther Ma (2009-11-19):
 # With the risk of being redundant to previous answers these are the most common
@@ -494,7 +489,7 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
 # 3. Urumqi...
 # 4. Kashgar...
 # ...
-# 5. It seems that Uyghurs in Urumqi has been using Xinjiang since at least the
+# 5. It seems that Uyghurs in Ürümqi has been using Xinjiang since at least the
 # 1960's. I know of one Han, now over 50, who grew up in the surrounding
 # countryside and used Xinjiang time as a child.
 #
@@ -506,10 +501,55 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
 # Autonomous Region under the PRC. (Before that Uyghurs, of course, would also
 # not be using Beijing time, but some local time.)
 
-Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
-			5:30	-	KAST	1940	 # Kashgar Time
-			5:00	-	KAST	1980 May
+# From David Cochrane (2014-03-26):
+# Just a confirmation that Ürümqi time was implemented in Ürümqi on 1 Feb 1986:
+# http://content.time.com/time/magazine/article/0,9171,960684,00.html
+
+# From Luther Ma (2014-04-22):
+# I have interviewed numerous people of various nationalities and from
+# different localities in Xinjiang and can confirm the information in Guo's
+# report regarding Xinjiang, as well as the Time article reference by David
+# Cochrane.  Whether officially recognized or not (and both are officially
+# recognized), two separate times have been in use in Xinjiang since at least
+# the Cultural Revolution: Xinjiang Time (XJT), aka Ürümqi Time or local time;
+# and Beijing Time.  There is no confusion in Xinjiang as to which name refers
+# to which time. Both are widely used in the province, although in some
+# population groups might be use one to the exclusion of the other.  The only
+# problem is that computers and smart phones list Ürümqi (or Kashgar) as
+# 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,
+# 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.
+#
+# Xinjiang Time is well-documented as being officially recognized.  E.g., see
+# "The Working-Calendar for The Xinjiang Uygur Autonomous Region Government"
+#  (2014-04-22).
+# Unfortunately, we have no good records of time in Xinjiang before 1986.
+# During the 20th century parts of Xinjiang were ruled by the Qing dynasty,
+# the Republic of China, various warlords, the First and Second East Turkestan
+# 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,
+# 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
+# that the sort of users who prefer Asia/Urumqi now typically ignored the
+# UT+8 mandate back then.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Beijing time, used throughout China; represented by Shanghai.
+Zone	Asia/Shanghai	8:05:43	-	LMT	1901
+			8:00	Shang	C%sT	1949
 			8:00	PRC	C%sT
+# Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi
+# / Wulumuqi.  (Please use Asia/Shanghai if you prefer Beijing time.)
+Zone	Asia/Urumqi	5:50:20	-	LMT	1928
+			6:00	-	XJT
 
 
 # Hong Kong (Xianggang)
@@ -524,15 +564,11 @@ Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
 # and incorrect rules. Although the exact switch over time is missing, I
 # think 3:30 is correct. The official DST record for Hong Kong can be
 # obtained from
-# 
 # http://www.hko.gov.hk/gts/time/Summertime.htm
-# .
 
 # From Arthur David Olson (2009-10-28):
 # Here are the dates given at
-# 
 # http://www.hko.gov.hk/gts/time/Summertime.htm
-# 
 # as of 2009-10-28:
 # Year        Period
 # 1941        1 Apr to 30 Sep
@@ -612,35 +648,113 @@ Zone	Asia/Hong_Kong	7:36:42 -	LMT	1904 Oct 30
 
 # Taiwan
 
-# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
-# was still controlled by Japan.  This is hard to believe, but we don't
-# have any other information.
-
 # From smallufo (2010-04-03):
-# According to Taiwan's CWB,
-# 
+# According to Taiwan's CWB [Central Weather Bureau],
 # http://www.cwb.gov.tw/V6/astronomy/cdata/summert.htm
-# 
 # Taipei has DST in 1979 between July 1st and Sep 30.
 
-# From Arthur David Olson (2010-04-07):
-# Here's Google's translation of the table at the bottom of the "summert.htm" page:
-# Decade 	                                                    Name                      Start and end date
-# Republic of China 34 years to 40 years (AD 1945-1951 years) Summer Time               May 1 to September 30
-# 41 years of the Republic of China (AD 1952)                 Daylight Saving Time      March 1 to October 31
-# Republic of China 42 years to 43 years (AD 1953-1954 years) Daylight Saving Time      April 1 to October 31
-# In the 44 years to 45 years (AD 1955-1956 years)            Daylight Saving Time      April 1 to September 30
-# Republic of China 46 years to 48 years (AD 1957-1959)       Summer Time               April 1 to September 30
-# Republic of China 49 years to 50 years (AD 1960-1961)       Summer Time               June 1 to September 30
-# Republic of China 51 years to 62 years (AD 1962-1973 years) Stop Summer Time
-# Republic of China 63 years to 64 years (1974-1975 AD)       Daylight Saving Time      April 1 to September 30
-# Republic of China 65 years to 67 years (1976-1978 AD)       Stop Daylight Saving Time
-# Republic of China 68 years (AD 1979)                        Daylight Saving Time      July 1 to September 30
-# Republic of China since 69 years (AD 1980)                  Stop Daylight Saving Time
+# From Yu-Cheng Chuang (2013-07-12):
+# On Dec 28, 1895, the Meiji Emperor announced Ordinance No. 167 of
+# Meiji Year 28 "The clause about standard time", mentioned that
+# Taiwan and Penghu Islands, as well as Yaeyama and Miyako Islands
+# (both in Okinawa) adopt the Western Standard Time which is based on
+# 120E. The adoption began from Jan 1, 1896. The original text can be
+# found on Wikisource:
+# http://ja.wikisource.org/wiki/標準時ニ關スル件_(公布時)
+# ... This could be the first adoption of time zone in Taiwan, because
+# during the Qing Dynasty, it seems that there was no time zone
+# declared officially.
+#
+# Later, in the beginning of World War II, on Sep 25, 1937, the Showa
+# Emperor announced Ordinance No. 529 of Showa Year 12 "The clause of
+# revision in the ordinance No. 167 of Meiji year 28 about standard
+# time", in which abolished the adoption of Western Standard Time in
+# western islands (listed above), which means the whole Japan
+# territory, including later occupations, adopt Japan Central Time
+# (UTC+9). The adoption began on Oct 1, 1937. The original text can
+# be found on Wikisource:
+# http://ja.wikisource.org/wiki/明治二十八年勅令第百六十七號標準時ニ關スル件中改正ノ件
+#
+# That is, the time zone of Taipei switched to UTC+9 on Oct 1, 1937.
+
+# From Yu-Cheng Chuang (2014-07-02):
+# I've found more evidence about when the time zone was switched from UTC+9
+# back to UTC+8 after WW2.  I believe it was on Sep 21, 1945.  In a document
+# during Japanese era [1] in which the officer told the staff to change time
+# zone back to Western Standard Time (UTC+8) on Sep 21.  And in another
+# history page of National Cheng Kung University [2], on Sep 21 there is a
+# note "from today, switch back to Western Standard Time".  From these two
+# materials, I believe that the time zone change happened on Sep 21.  And
+# today I have found another monthly journal called "The Astronomical Herald"
+# from The Astronomical Society of Japan [3] in which it mentioned the fact
+# that:
+#
+# 1. Standard Time of the Country (Japan) was adopted on Jan 1, 1888, using
+# the time at 135E (GMT+9)
+#
+# 2. Standard Time of the Country was renamed to Central Standard Time, on Jan
+# 1, 1898, and on the same day, the new territories Taiwan and Penghu islands,
+# as well as Yaeyama and Miyako islands, adopted a new time zone called
+# Western Standard Time, which is in GMT+8.
+#
+# 3. Western Standard Time was deprecated on Sep 30, 1937. From then all the
+# territories of Japan adopted the same time zone, which is Central Standard
+# Time.
+#
+# [1] Academica Historica, Taiwan:
+# http://163.29.208.22:8080/govsaleShowImage/connect_img.php?s=00101738900090036&e=00101738900090037
+# [2] Nat'l Cheng Kung University 70th Anniversary Special Site:
+# http://www.ncku.edu.tw/~ncku70/menu/001/01_01.htm
+# [3] Yukio Niimi, The Standard Time in Japan (1997), p.475:
+# http://www.asj.or.jp/geppou/archive_open/1997/pdf/19971001c.pdf
+
+# Yu-Cheng Chuang (2014-07-03):
+# I finally have found the real official gazette about changing back to
+# Western Standard Time on Sep 21 in Taiwan.  It's Taiwan Governor-General
+# Bulletin No. 386 in Showa 20 years (1945), published on Sep 19, 1945. [1] ...
+# [It] abolishes Bulletin No. 207 in Showa 12 years (1937), which is a local
+# bulletin in Taiwan for that Ordinance No. 529. It also mentioned that 1am on
+# Sep 21, 1945 will be 12am on Sep 21.  I think this bulletin is much more
+# official than the one I mentioned in my first mail, because it's from the
+# top-level government in Taiwan. If you're going to quote any resource, this
+# would be a good one.
+# [1] Taiwan Governor-General Gazette, No. 1018, Sep 19, 1945:
+# http://db2.th.gov.tw/db2/view/viewImg.php?imgcode=0072031018a&num=19&bgn=019&end=019&otherImg=&type=gener
+
+# From Yu-Cheng Chuang (2014-07-02):
+# In 1946, DST in Taiwan was from May 15 and ended on Sep 30. The info from
+# Central Weather Bureau website was not correct.
+#
+# Original Bulletin:
+# http://subtpg.tpg.gov.tw/og/image2.asp?f=03502F0AKM1AF
+# http://subtpg.tpg.gov.tw/og/image2.asp?f=0350300AKM1B0 (cont.)
+#
+# In 1947, DST in Taiwan was expanded to Oct 31. There is a backup of that
+# telegram announcement from Taiwan Province Government:
+#
+# http://subtpg.tpg.gov.tw/og/image2.asp?f=0360310AKZ431
+#
+# Here is a brief translation:
+#
+#   The Summer Time this year is adopted from midnight Apr 15 until Sep 20
+#   midnight. To save (energy?) consumption, we're expanding Summer Time
+#   adoption till Oct 31 midnight.
+#
+# The Central Weather Bureau website didn't mention that, however it can
+# 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
+# until 1945-09-21 at 01:00, overriding Shanks & Pottenger.
+# Likewise, use Yu-Cheng Chuang's data for DST in Taiwan.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
-Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
+Rule	Taiwan	1946	only	-	May	15	0:00	1:00	D
+Rule	Taiwan	1946	only	-	Oct	1	0:00	0	S
+Rule	Taiwan	1947	only	-	Apr	15	0:00	1:00	D
+Rule	Taiwan	1947	only	-	Nov	1	0:00	0	S
+Rule	Taiwan	1948	1951	-	May	1	0:00	1:00	D
+Rule	Taiwan	1948	1951	-	Oct	1	0:00	0	S
 Rule	Taiwan	1952	only	-	Mar	1	0:00	1:00	D
 Rule	Taiwan	1952	1954	-	Nov	1	0:00	0	S
 Rule	Taiwan	1953	1959	-	Apr	1	0:00	1:00	D
@@ -648,11 +762,14 @@ Rule	Taiwan	1955	1961	-	Oct	1	0:00	0	S
 Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
 Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
 Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
-Rule	Taiwan	1979	only	-	Jun	30	0:00	1:00	D
-Rule	Taiwan	1979	only	-	Sep	30	0:00	0	S
+Rule	Taiwan	1979	only	-	Jul	1	0:00	1:00	D
+Rule	Taiwan	1979	only	-	Oct	1	0:00	0	S
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
+# Taipei or Taibei or T'ai-pei
+Zone	Asia/Taipei	8:06:00 -	LMT	1896 Jan  1
+			8:00	-	JWST	1937 Oct  1
+			9:00	-	JST	1945 Sep 21  1:00
 			8:00	Taiwan	C%sT
 
 # Macau (Macao, Aomen)
@@ -672,7 +789,7 @@ Rule	Macau	1975	1977	-	Apr	Sun>=15	3:30	1:00	S
 Rule	Macau	1978	1980	-	Apr	Sun>=15	0:00	1:00	S
 Rule	Macau	1978	1980	-	Oct	Sun>=15	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Macau	7:34:20 -	LMT	1912
+Zone	Asia/Macau	7:34:20 -	LMT	1912 Jan  1
 			8:00	Macau	MO%sT	1999 Dec 20 # return to China
 			8:00	PRC	C%sT
 
@@ -721,7 +838,7 @@ Link	Asia/Nicosia	Europe/Nicosia
 # republic has changed its time zone back to that of Moscow.  As a result it
 # is now just four hours ahead of Greenwich Mean Time, rather than five hours
 # ahead.  The switch was decreed by the pro-Western president of Georgia,
-# Mikhail Saakashvili, who said the change was partly prompted by the process
+# Mikheil Saakashvili, who said the change was partly prompted by the process
 # of integration into Europe.
 
 # From Teimuraz Abashidze (2005-11-07):
@@ -734,29 +851,31 @@ Link	Asia/Nicosia	Europe/Nicosia
 # I don't know what can be done, especially knowing that some years ago our
 # DST rules where changed THREE TIMES during one month.
 
+# Milne 1899 says Tbilisi (Tiflis) time was 2:59:05.7.
+# Byalokoz 1919 says Georgia was 2:59:11.
+# Go with Byalokoz.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
-			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
+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
+			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 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
+			3:00 RussiaAsia	GE%sT	2005 Mar lastSun  2:00
 			4:00	-	GET
 
 # East Timor
 
 # See Indonesia for the 1945 transition.
 
-# From Joao Carrascalao, brother of the former governor of East Timor, in
-# 
+# From João Carrascalão, brother of the former governor of East Timor, in
 # East Timor may be late for its millennium
-#  (1999-12-26/31):
+#  (1999-12-26/31):
 # Portugal tried to change the time forward in 1974 because the sun
 # rises too early but the suggestion raised a lot of problems with the
 # Timorese and I still don't think it would work today because it
@@ -766,25 +885,25 @@ Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
 # We don't have any record of the above attempt.
 # Most likely our records are incomplete, but we have no better data.
 
-# 
 # From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
-# (2000-08-16):
+# http://www.hri.org/news/world/undh/2000/00-08-16.undh.html
+# (2000-08-16):
 # The Cabinet of the East Timor Transition Administration decided
 # today to advance East Timor's time by one hour.  The time change,
 # which will be permanent, with no seasonal adjustment, will happen at
 # midnight on Saturday, September 16.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Dili	8:22:20 -	LMT	1912
+Zone	Asia/Dili	8:22:20 -	LMT	1912 Jan  1
 			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
 			9:00	-	JST	1945 Sep 23
 			9:00	-	TLT	1976 May  3
-			8:00	-	WITA	2000 Sep 17 00:00
+			8:00	-	WITA	2000 Sep 17  0:00
 			9:00	-	TLT
 
 # India
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
+Zone	Asia/Kolkata	5:53:28 -	LMT	1880        # Kolkata
 			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
 			6:30	-	BURT	1942 May 15 # Burma Time
 			5:30	-	IST	1942 Sep
@@ -798,7 +917,7 @@ Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
 # Indonesia
 #
 # From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
-# 
+# http://www.sumatera-inc.com/go_to_invest/about_indonesia.asp#standtime
 # says that Indonesia's time zones changed on 1988-01-01.  Looking at some
 # time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
 # and Kalimantan Tengah) switching from UTC+8 to UTC+7.
@@ -810,7 +929,7 @@ Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
 # other formal surrender ceremonies were September 9, 11, and 13, plus
 # September 12 for the regional surrender to Mountbatten in Singapore.
 # These would be the earliest possible times for a change.
-# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
+# 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
 # (Hollandia).  For now, assume all Indonesian locations other than Jayapura
@@ -835,7 +954,7 @@ Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
 # Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
 # but this must be a typo.
 			7:07:12	-	BMT	1923 Dec 31 23:47:12 # Batavia
-			7:20	-	JAVT	1932 Nov	 # Java Time
+			7:20	-	JAVT	1932 Nov    # Java Time
 			7:30	-	WIB	1942 Mar 23
 			9:00	-	JST	1945 Sep 23
 			7:30	-	WIB	1948 May
@@ -861,7 +980,7 @@ Zone Asia/Makassar	7:57:36 -	LMT	1920
 # Maluku Islands, West Papua, Papua
 Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
 			9:00	-	WIT	1944 Sep  1
-			9:30	-	CST	1964
+			9:30	-	ACST	1964
 			9:00	-	WIT
 
 # Iran
@@ -927,7 +1046,7 @@ Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
 # Several of my users have reported that Iran will not observe DST anymore:
 # http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
 #
-# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
+# From Reuters (2007-09-16), with a heads-up from Jesper Nørgaard Welen:
 # ... the Guardian Council ... approved a law on Sunday to re-introduce
 # daylight saving time ...
 # http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
@@ -993,7 +1112,7 @@ Rule	Iran	2036	2037	-	Mar	21	0:00	1:00	D
 Rule	Iran	2036	2037	-	Sep	21	0:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Tehran	3:25:44	-	LMT	1916
-			3:25:44	-	TMT	1946	# Tehran Mean Time
+			3:25:44	-	TMT	1946     # Tehran Mean Time
 			3:30	-	IRST	1977 Nov
 			4:00	Iran	IR%sT	1979
 			3:30	Iran	IR%sT
@@ -1018,17 +1137,11 @@ Zone	Asia/Tehran	3:25:44	-	LMT	1916
 # From Steffen Thorsen (2008-03-10):
 # The cabinet in Iraq abolished DST last week, according to the following
 # news sources (in Arabic):
-# 
 # http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
-# 
-# 
 # http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
-# 
 #
 # We have published a short article in English about the change:
-# 
 # http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
-# 
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
@@ -1037,14 +1150,14 @@ Rule	Iraq	1983	only	-	Mar	31	0:00	1:00	D
 Rule	Iraq	1984	1985	-	Apr	1	0:00	1:00	D
 Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
 Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
-# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
+# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the ':01' is a typo.
 # Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
 #
 Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
 Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Baghdad	2:57:40	-	LMT	1890
-			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
+			2:57:36	-	BMT	1918     # Baghdad Mean Time?
 			3:00	-	AST	1982 May
 			3:00	Iraq	A%sT
 
@@ -1272,7 +1385,7 @@ Rule	Zion	2013	max	-	Oct	lastSun	2:00	0	S
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Jerusalem	2:20:54 -	LMT	1880
-			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
+			2:20:40	-	JMT	1918 # Jerusalem Mean Time?
 			2:00	Zion	I%sT
 
 
@@ -1281,15 +1394,15 @@ Zone	Asia/Jerusalem	2:20:54 -	LMT	1880
 
 # Japan
 
-# `9:00' and `JST' is from Guy Harris.
+# '9:00' and 'JST' is from Guy Harris.
 
 # From Paul Eggert (1995-03-06):
 # Today's _Asahi Evening News_ (page 4) reports that Japan had
-# daylight saving between 1948 and 1951, but ``the system was discontinued
-# because the public believed it would lead to longer working hours.''
+# daylight saving between 1948 and 1951, but "the system was discontinued
+# because the public believed it would lead to longer working hours."
 
-# From Mayumi Negishi in the 2005-08-10 Japan Times
-# :
+# From Mayumi Negishi in the 2005-08-10 Japan Times:
+# http://www.japantimes.co.jp/cgi-bin/getarticle.pl5?nn20050810f2.htm
 # Occupation authorities imposed daylight-saving time on Japan on
 # [1948-05-01]....  But lack of prior debate and the execution of
 # daylight-saving time just three days after the bill was passed generated
@@ -1313,7 +1426,8 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
 
 # From Hideyuki Suzuki (1998-11-09):
 # 'Tokyo' usually stands for the former location of Tokyo Astronomical
-# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
+# Observatory: 139 degrees 44' 40.90" E (9h 18m 58.727s),
+# 35 degrees 39' 16.0" N.
 # This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
 # edited by National Astronomical Observatory of Japan....
 # JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
@@ -1321,10 +1435,10 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
 
 # From Hideyuki Suzuki (1998-11-16):
 # The ordinance No. 51 (1886) established "standard time" in Japan,
-# which stands for the time on E 135 degree.
+# which stands for the time on 135 degrees E.
 # In the ordinance No. 167 (1895), "standard time" was renamed to "central
 # standard time".  And the same ordinance also established "western standard
-# time", which stands for the time on E 120 degree....  But "western standard
+# time", which stands for the time on 120 degrees E....  But "western standard
 # time" was abolished in the ordinance No. 529 (1937).  In the ordinance No.
 # 167, there is no mention regarding for what place western standard time is
 # standard....
@@ -1332,27 +1446,33 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
 # I wrote "ordinance" above, but I don't know how to translate.
 # In Japanese it's "chokurei", which means ordinance from emperor.
 
-# Shanks & Pottenger claim JST in use since 1896, and that a few
-# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
-# ordinances took effect on Jan 1.
+# From Yu-Cheng Chuang (2013-07-12):
+# ...the Meiji Emperor announced Ordinance No. 167 of Meiji Year 28 "The clause
+# about standard time" ... The adoption began from Jan 1, 1896.
+# http://ja.wikisource.org/wiki/標準時ニ關スル件_(公布時)
+#
+# ...the Showa Emperor announced Ordinance No. 529 of Showa Year 12 ... which
+# means the whole Japan territory, including later occupations, adopt Japan
+# Central Time (UTC+9). The adoption began on Oct 1, 1937.
+# http://ja.wikisource.org/wiki/明治二十八年勅令第百六十七號標準時ニ關スル件中改正ノ件
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
-			9:00	-	JST	1896
-			9:00	-	CJT	1938
+			9:00	-	JST	1896 Jan  1
+			9:00	-	JCST	1937 Oct  1
 			9:00	Japan	J%sT
 # Since 1938, all Japanese possessions have been like Asia/Tokyo.
 
 # Jordan
 #
-# From 
-# Jordan Week (1999-07-01)  via Steffen Thorsen (1999-09-09):
+# From 
+# Jordan Week (1999-07-01) via Steffen Thorsen (1999-09-09):
 # Clocks in Jordan were forwarded one hour on Wednesday at midnight,
 # in accordance with the government's decision to implement summer time
 # all year round.
 #
-# From 
-# Jordan Week (1999-09-30)  via Steffen Thorsen (1999-11-09):
+# From 
+# Jordan Week (1999-09-30) via Steffen Thorsen (1999-11-09):
 # Winter time starts today Thursday, 30 September. Clocks will be turned back
 # by one hour.  This is the latest government decision and it's final!
 # The decision was taken because of the increase in working hours in
@@ -1372,9 +1492,7 @@ Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
 
 # From Steffen Thorsen (2009-04-02):
 # This single one might be good enough, (2009-03-24, Arabic):
-# 
 # http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
-# 
 #
 # Google's translation:
 #
@@ -1465,9 +1583,8 @@ Zone	Asia/Amman	2:23:44 -	LMT	1931
 # - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
 # - Oral switched from +5:00 to +4:00 in spring 1989.
 
-# 
-# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
-# 
+# From Kazakhstan Embassy's News Bulletin #11
+#  (2005-03-21):
 # The Government of Kazakhstan passed a resolution March 15 abolishing
 # daylight saving time citing lack of economic benefits and health
 # complications coupled with a decrease in productivity.
@@ -1500,10 +1617,10 @@ Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
 			6:00	-	KIZT	1982 Apr  1
 			5:00 RussiaAsia	KIZ%sT	1991
 			5:00	-	KIZT	1991 Dec 16 # independence
-			5:00	-	QYZT	1992 Jan 19 2:00
+			5:00	-	QYZT	1992 Jan 19  2:00
 			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
 			6:00	-	QYZT
-# Aqtobe (aka Aktobe, formerly Akt'ubinsk)
+# Aqtobe (aka Aktobe, formerly Aktyubinsk)
 Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
 			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
 			5:00	-	AKTT	1981 Apr  1
@@ -1523,7 +1640,7 @@ Zone	Asia/Aqtau	3:21:04	-	LMT	1924 May  2
 			6:00	-	SHET	1982 Apr  1
 			5:00 RussiaAsia	SHE%sT	1991
 			5:00	-	SHET	1991 Dec 16 # independence
-			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
+			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun  2:00 # Aqtau Time
 			4:00 RussiaAsia	AQT%sT	2005 Mar 15
 			5:00	-	AQTT
 # West Kazakhstan
@@ -1532,7 +1649,7 @@ Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
 			5:00	-	URAT	1981 Apr  1
 			5:00	1:00	URAST	1981 Oct  1
 			6:00	-	URAT	1982 Apr  1
-			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
+			5:00 RussiaAsia	URA%sT	1989 Mar 26  2:00
 			4:00 RussiaAsia	URA%sT	1991
 			4:00	-	URAT	1991 Dec 16 # independence
 			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
@@ -1543,7 +1660,7 @@ Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
 
 # From Paul Eggert (2005-08-15):
 # According to an article dated today in the Kyrgyzstan Development Gateway
-# 
+# http://eng.gateway.kg/cgi-bin/page.pl?id=1&story_name=doc9979.shtml
 # Kyrgyzstan is canceling the daylight saving time system.  I take the article
 # to mean that they will leave their clocks at 6 hours ahead of UTC.
 # From Malik Abdugaliev (2005-09-21):
@@ -1558,17 +1675,17 @@ 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 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
 
 ###############################################################################
 
 # Korea (North and South)
 
-# From Annie I. Bang (2006-07-10) in
-# :
+# From Annie I. Bang (2006-07-10):
+# http://www.koreaherald.co.kr/SITE/data/html_dir/2006/07/10/200607100012.asp
 # The Ministry of Commerce, Industry and Energy has already
 # commissioned a research project [to reintroduce DST] and has said
 # the system may begin as early as 2008....  Korea ran a daylight
@@ -1581,19 +1698,29 @@ Rule	ROK	1960	only	-	Sep	13	0:00	0	S
 Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
 Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
 
+# From Paul Eggert (2014-07-01):
+# The following entries are from Shanks & Pottenger, except that 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.
+
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Seoul	8:27:52	-	LMT	1890
 			8:30	-	KST	1904 Dec
-			9:00	-	KST	1928
+			9:00	-	JCST	1928
 			8:30	-	KST	1932
+			9:00	-	JCST	1937 Oct  1
+			9:00	-	JST	1945 Sep  8
 			9:00	-	KST	1954 Mar 21
 			8:00	ROK	K%sT	1961 Aug 10
 			8:30	-	KST	1968 Oct
 			9:00	ROK	K%sT
 Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
 			8:30	-	KST	1904 Dec
-			9:00	-	KST	1928
+			9:00	-	JCST	1928
 			8:30	-	KST	1932
+			9:00	-	JCST	1937 Oct  1
+			9:00	-	JST	1945 Aug 24
 			9:00	-	KST	1954 Mar 21
 			8:00	-	KST	1961 Aug 10
 			9:00	-	KST
@@ -1602,21 +1729,13 @@ Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
 
 # Kuwait
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-# From the Arab Times (2007-03-14):
-# The Civil Service Commission (CSC) has approved a proposal forwarded
-# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
-# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
-# .
-# From Paul Eggert (2007-03-29):
-# We don't know the details, or whether the approval means it'll happen,
-# so for now we assume no DST.
 Zone	Asia/Kuwait	3:11:56 -	LMT	1950
 			3:00	-	AST
 
 # Laos
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9 # or Viangchan
-			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9       # or Viangchan
+			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
 			7:00	-	ICT	1912 May
 			8:00	-	ICT	1931 May
 			7:00	-	ICT
@@ -1657,8 +1776,8 @@ Rule	NBorneo	1935	1941	-	Sep	14	0:00	0:20	TS # one-Third Summer
 Rule	NBorneo	1935	1941	-	Dec	14	0:00	0	-
 #
 # peninsular Malaysia
-# The data here are taken from Mok Ly Yng (2003-10-30)
-# .
+# taken from Mok Ly Yng (2003-10-30)
+# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
 			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
@@ -1670,12 +1789,12 @@ Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
 			7:30	-	MALT	1982 Jan  1
 			8:00	-	MYT	# Malaysia Time
 # Sabah & Sarawak
-# From Paul Eggert (2006-03-22):
-# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
-# transition dates are from Mok Ly Yng.
+# From Paul Eggert (2014-08-12):
+# The data entries here are mostly from Shanks & Pottenger, but the 1942, 1945
+# and 1982 transition dates are from Mok Ly Yng.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
-			7:30	-	BORT	1933	# Borneo Time
+			7:30	-	BORT	1933        # Borneo Time
 			8:00	NBorneo	BOR%sT	1942 Feb 16
 			9:00	-	JST	1945 Sep 12
 			8:00	-	BORT	1982 Jan  1
@@ -1683,22 +1802,21 @@ Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
 
 # Maldives
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
-			4:54:00	-	MMT	1960	# Male Mean Time
-			5:00	-	MVT		# Maldives Time
+Zone	Indian/Maldives	4:54:00 -	LMT	1880 # Male
+			4:54:00	-	MMT	1960 # Male Mean Time
+			5:00	-	MVT	# Maldives Time
 
 # Mongolia
 
 # Shanks & Pottenger say that Mongolia has three time zones, but
-# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
-# both say that it has just one.
+# The USNO (1995-12-21) and the CIA map Standard Time Zones of the World
+# (2005-03) both say that it has just one.
 
 # From Oscar van Vlijmen (1999-12-11):
-# 
 # General Information Mongolia
-#  (1999-09)
+#  (1999-09)
 # "Time: Mongolia has two time zones. Three westernmost provinces of
-# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
+# Bayan-Ölgii, Uvs, and Hovd are one hour earlier than the capital city, and
 # the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
 # eight hours."
 
@@ -1709,7 +1827,7 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
 # of implementation may have been different....
 # Some maps in the past have indicated that there was an additional time
 # zone in the eastern part of Mongolia, including the provinces of Dornod,
-# Suhbaatar, and possibly Khentij.
+# Sükhbaatar, and possibly Khentii.
 
 # From Paul Eggert (1999-12-15):
 # Naming and spelling is tricky in Mongolia.
@@ -1723,10 +1841,10 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
 # (adopted DST on 2001-04-27 02:00 local time, ending 2001-09-28),
 # there are three time zones.
 #
-# Provinces [at 7:00]: Bayan-ulgii, Uvs, Khovd, Zavkhan, Govi-Altai
-# Provinces [at 8:00]: Khovsgol, Bulgan, Arkhangai, Khentii, Tov,
-#	Bayankhongor, Ovorkhangai, Dundgovi, Dornogovi, Omnogovi
-# Provinces [at 9:00]: Dornod, Sukhbaatar
+# Provinces [at 7:00]: Bayan-Ölgii, Uvs, Khovd, Zavkhan, Govi-Altai
+# Provinces [at 8:00]: Khövsgöl, Bulgan, Arkhangai, Khentii, Töv,
+#	Bayankhongor, Övörkhangai, Dundgovi, Dornogovi, Ömnögovi
+# Provinces [at 9:00]: Dornod, Sükhbaatar
 #
 # [The province of Selenge is omitted from the above lists.]
 
@@ -1743,16 +1861,16 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
 # We have wildly conflicting information about Mongolia's time zones.
 # 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 Nykanen (2005-05-16) reports that
+# 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.
 # 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
-# 
+# http://ubpost.mongolnews.mn/index.php?subaction=showcomments&id=1111634894&archive=&start_from=&ucat=1&
 # which also says that there is DST, and which has a comment by "Toddius"
 # (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
 # The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
-# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
+# and some Eastern provinces are +9 GMT but Sükhbaatar Aimag is SUHK +8.5 GMT.
 # The SUKH timezone is new this year, it is one of the few things the
 # parliament passed during the tumultuous winter session."
 # For now, let's ignore this information, until we have more confirmation.
@@ -1768,29 +1886,23 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
 # +08:00 instead. Different sources appear to disagree with the tz
 # database on this, e.g.:
 #
-# 
 # http://www.timeanddate.com/worldclock/city.html?n=1026
-# 
-# 
 # http://www.worldtimeserver.com/current_time_in_MN.aspx
-# 
 #
 # both say GMT+08:00.
 
 # From Steffen Thorsen (2008-03-31):
 # eznis airways, which operates several domestic flights, has a flight
 # schedule here:
-# 
 # http://www.eznis.com/Container.jsp?id=112
-# 
 # (click the English flag for English)
 #
-# There it appears that flights between Choibalsan and Ulaanbatar arrive
+# There it appears that flights between Choibalsan and Ulaanbaatar arrive
 # about 1:35 - 1:50 hours later in local clock time, no matter the
-# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
-# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
+# direction, while Ulaanbaatar-Khovd takes 2 hours in the Eastern
+# direction and 3:35 back, which indicates that Ulaanbaatar and Khovd are
 # in different time zones (like we know about), while Choibalsan and
-# Ulaanbatar are in the same time zone (correction needed).
+# Ulaanbaatar are in the same time zone (correction needed).
 
 # From Arthur David Olson (2008-05-19):
 # Assume that Choibalsan is indeed offset by 8:00.
@@ -1806,7 +1918,7 @@ Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
 # (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
 #
 # Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
-# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
+# in Choibalsan (more precisely, in Dornod and Sükhbaatar) took place
 # at 02:00 standard time, not at 00:00 local time as in the rest of
 # the country.  That would be odd, and possibly is a result of their
 # correction of 02:00 (in the previous edition) not being done correctly
@@ -1822,13 +1934,13 @@ Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 # Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
 Zone	Asia/Hovd	6:06:36 -	LMT	1905 Aug
-			6:00	-	HOVT	1978	# Hovd Time
+			6:00	-	HOVT	1978     # Hovd Time
 			7:00	Mongol	HOV%sT
 # Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
 Zone	Asia/Ulaanbaatar 7:07:32 -	LMT	1905 Aug
-			7:00	-	ULAT	1978	# Ulaanbaatar Time
+			7:00	-	ULAT	1978     # Ulaanbaatar Time
 			8:00	Mongol	ULA%sT
-# Choibalsan, a.k.a. Bajan Tuemen, Bajan Tumen, Chojbalsan,
+# Choibalsan, a.k.a. Bajan Tümen, Bajan Tumen, Chojbalsan,
 # Choybalsan, Sanbejse, Tchoibalsan
 Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
 			7:00	-	ULAT	1978
@@ -1860,7 +1972,7 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 # 00:01 was to make it clear which day it was on.
 
 # From Paul Eggert (2002-03-15):
-# Jesper Norgaard found this URL:
+# Jesper Nørgaard found this URL:
 # http://www.pak.gov.pk/public/news/app/app06_dec.htm
 # (dated 2001-12-06) which says that the Cabinet adopted a scheme "to
 # advance the clocks by one hour on the night between the first
@@ -1892,43 +2004,30 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 # Here is an article that Pakistan plan to introduce Daylight Saving Time
 # on June 1, 2008 for 3 months.
 #
-# "... The federal cabinet on Wednesday announced a new conservation plan to help
-# reduce load shedding by approving the closure of commercial centres at 9pm and
-# moving clocks forward by one hour for the next three months.
-# ...."
+# "... The federal cabinet on Wednesday announced a new conservation plan to
+# help reduce load shedding by approving the closure of commercial centres at
+# 9pm and moving clocks forward by one hour for the next three months. ...."
 #
-# 
 # http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
-# 
-# OR
-# 
 # http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
-# 
 
 # From Arthur David Olson (2008-05-19):
 # XXX--midnight transitions is a guess; 2008 only is a guess.
 
 # From Alexander Krivenyshev (2008-08-28):
 # Pakistan government has decided to keep the watches one-hour advanced
-# for another 2 months--plan to return to Standard Time on October 31
+# for another 2 months - plan to return to Standard Time on October 31
 # instead of August 31.
 #
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
-# 
-# OR
-# 
 # http://dailymailnews.com/200808/28/news/dmbrn03.html
-# 
 
 # From Alexander Krivenyshev (2009-04-08):
 # Based on previous media reports that "... proposed plan to
 # advance clocks by one hour from May 1 will cause disturbance
 # to the working schedules rather than bringing discipline in
 # official working."
-# 
 # http://www.thenews.com.pk/daily_detail.asp?id=171280
-# 
 #
 # recent news that instead of May 2009 - Pakistan plan to
 # introduce DST from April 15, 2009
@@ -1936,15 +2035,8 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 # FYI: Associated Press Of Pakistan
 # April 08, 2009
 # Cabinet okays proposal to advance clocks by one hour from April 15
-# 
 # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
-# 
-#
-# or
-#
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
-# 
 #
 # ....
 # The Federal Cabinet on Wednesday approved the proposal to
@@ -1957,34 +2049,20 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 # clocks backward by one hour from October 1. A formal announcement to
 # this effect will be made after the Prime Minister grants approval in
 # this regard."
-# 
 # http://www.thenews.com.pk/updates.asp?id=87168
-# 
 
 # From Alexander Krivenyshev (2009-09-28):
 # According to Associated Press Of Pakistan, it is confirmed that
-# Pakistan clocks across the country would be turned back by an hour from October
-# 1, 2009.
+# Pakistan clocks across the country would be turned back by an hour from
+# October 1, 2009.
 #
 # "Clocks to go back one hour from 1 Oct"
-# 
 # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
-# 
-
-# From Steffen Thorsen (2009-09-29):
-# Alexander Krivenyshev wrote:
-# > According to Associated Press Of Pakistan, it is confirmed that
-# > Pakistan clocks across the country would be turned back by an hour from October
-# > 1, 2009.
 #
+# From Steffen Thorsen (2009-09-29):
 # Now they seem to have changed their mind, November 1 is the new date:
-# 
 # http://www.thenews.com.pk/top_story_detail.asp?Id=24742
-# 
 # "The country's clocks will be reversed by one hour on November 1.
 # Officials of Federal Ministry for Interior told this to Geo News on
 # Monday."
@@ -1996,11 +2074,9 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 #
 # We have confirmed this year's end date with both with the Ministry of
 # Water and Power and the Pakistan Electric Power Company:
-# 
 # http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
-# 
 
-# From Christoph Goehre (2009-10-01):
+# From Christoph Göhre (2009-10-01):
 # [T]he German Consulate General in Karachi reported me today that Pakistan
 # will go back to standard time on 1st of November.
 
@@ -2016,22 +2092,17 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
 # Now, it seems that the decision to not observe DST in final:
 #
 # "Govt Withdraws Plan To Advance Clocks"
-# 
 # http://www.apakistannews.com/govt-withdraws-plan-to-advance-clocks-172041
-# 
 #
 # "People laud PM's announcement to end DST"
-# 
 # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=99374&Itemid=2
-# 
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
 Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
 Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
-Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
+Rule Pakistan	2008	2009	-	Nov	1	0:00	0	-
 Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
-Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Karachi	4:28:12 -	LMT	1907
@@ -2105,10 +2176,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # the PA has decided to implement DST in April.
 
 # From Paul Eggert (1999-09-20):
-# Daoud Kuttab writes in
-# 
-# Holiday havoc
-#  (Jerusalem Post, 1999-04-22) that
+# Daoud Kuttab writes in Holiday havoc
+# http://www.jpost.com/com/Archive/22.Apr.1999/Opinion/Article-2.html
+# (Jerusalem Post, 1999-04-22) that
 # the Palestinian National Authority changed to DST on 1999-04-15.
 # I vaguely recall that they switch back in October (sorry, forgot the source).
 # For now, let's assume that the spring switch was at 24:00,
@@ -2121,7 +2191,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # A user from Gaza reported that Gaza made the change early because of
 # the Ramadan.  Next year Ramadan will be even earlier, so I think
 # there is a good chance next year's end date will be around two weeks
-# earlier--the same goes for Jordan.
+# earlier - the same goes for Jordan.
 
 # From Steffen Thorsen (2006-08-17):
 # I was informed by a user in Bethlehem that in Bethlehem it started the
@@ -2140,7 +2210,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # I guess it is likely that next year's date will be moved as well,
 # because of the Ramadan.
 
-# From Jesper Norgaard Welen (2007-09-18):
+# From Jesper Nørgaard Welen (2007-09-18):
 # According to Steffen Thorsen's web site the Gaza Strip and the rest of the
 # Palestinian territories left DST early on 13.th. of September at 2:00.
 
@@ -2157,16 +2227,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
 # the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
 #
-# 
 # http://www.guardian.co.uk/world/feedarticle/7759001
-# 
-# 
 # http://www.abcnews.go.com/International/wireStory?id=5676087
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
-# 
 
 # From Alexander Krivenyshev (2009-03-26):
 # According to the Palestine News Network (arabic.pnn.ps), Palestinian
@@ -2174,24 +2237,17 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # 26 and continue until the night of 27 September 2009.
 #
 # (in Arabic)
-# 
 # http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
-# 
 #
-# or
 # (English translation)
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
-# 
 
 # From Steffen Thorsen (2009-08-31):
 # Palestine's Council of Ministers announced that they will revert back to
 # winter time on Friday, 2009-09-04.
 #
 # One news source:
-# 
 # http://www.safa.ps/ara/?action=showdetail&seid=4158
-# 
 # (Palestinian press agency, Arabic),
 # Google translate: "Decided that the Palestinian government in Ramallah
 # headed by Salam Fayyad, the start of work in time for the winter of
@@ -2200,9 +2256,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 #
 # We are not sure if Gaza will do the same, last year they had a different
 # end date, we will keep this page updated:
-# 
 # http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
-# 
 
 # From Alexander Krivenyshev (2009-09-02):
 # Seems that Gaza Strip will go back to Winter Time same date as West Bank.
@@ -2212,51 +2266,35 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 #
 # "Winter time unite the West Bank and Gaza"
 # (from Palestinian National Authority):
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
-# 
 
 # From Alexander Krivenyshev (2010-03-19):
 # According to Voice of Palestine DST will last for 191 days, from March
 # 26, 2010 till "the last Sunday before the tenth day of Tishri
 # (October), each year" (October 03, 2010?)
 #
-# 
 # http://palvoice.org/forums/showthread.php?t=245697
-# 
 # (in Arabic)
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_westbank03.html
-# 
 
 # From Steffen Thorsen (2010-03-24):
 # ...Ma'an News Agency reports that Hamas cabinet has decided it will
 # start one day later, at 12:01am. Not sure if they really mean 12:01am or
 # noon though:
 #
-# 
 # http://www.maannews.net/eng/ViewDetails.aspx?ID=271178
-# 
 # (Ma'an News Agency)
 # "At 12:01am Friday, clocks in Israel and the West Bank will change to
 # 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
 
 # From Steffen Thorsen (2010-08-11):
 # According to several sources, including
-# 
 # http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
-# 
 # the clocks were set back one hour at 2010-08-11 00:00:00 local time in
 # Gaza and the West Bank.
 # Some more background info:
-# 
 # http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
-# 
 
 # From Steffen Thorsen (2011-08-26):
 # Gaza and the West Bank did go back to standard time in the beginning of
@@ -2264,13 +2302,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # 00:00 (so two periods of DST in 2011). The pause was because of
 # Ramadan.
 #
-# 
 # http://www.maannews.net/eng/ViewDetails.aspx?ID=416217
-# 
 # Additional info:
-# 
 # http://www.timeanddate.com/news/time/palestine-dst-2011.html
-# 
 
 # From Alexander Krivenyshev (2011-08-27):
 # According to the article in The Jerusalem Post:
@@ -2280,14 +2314,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # The Hamas government said on Saturday that it won't observe summertime after
 # the Muslim feast of Id al-Fitr, which begins on Tuesday..."
 # ...
-# 
 # http://www.jpost.com/MiddleEast/Article.aspx?id=235650
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_gazastrip05.html
-# 
-# The rules for Egypt are stolen from the `africa' file.
+# The rules for Egypt are stolen from the 'africa' file.
 
 # From Steffen Thorsen (2011-09-30):
 # West Bank did end Daylight Saving Time this morning/midnight (2011-09-30
@@ -2295,26 +2324,18 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # So West Bank and Gaza now have the same time again.
 #
 # Many sources, including:
-# 
 # http://www.maannews.net/eng/ViewDetails.aspx?ID=424808
-# 
 
 # From Steffen Thorsen (2012-03-26):
 # Palestinian news sources tell that both Gaza and West Bank will start DST
 # on Friday (Thursday midnight, 2012-03-29 24:00).
 # Some of many sources in Arabic:
-# 
 # http://www.samanews.com/index.php?act=Show&id=122638
-# 
 #
-# 
 # http://safa.ps/details/news/74352/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-%D8%A8%D8%A7%D9%84%D8%B6%D9%81%D8%A9-%D9%88%D8%BA%D8%B2%D8%A9-%D9%84%D9%8A%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D9%85%D8%B9%D8%A9.html
-# 
 #
 # Our brief summary:
-# 
 # http://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html
-# 
 
 # From Steffen Thorsen (2013-03-26):
 # The following news sources tells that Palestine will "start daylight saving
@@ -2374,10 +2395,10 @@ Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
 			2:00 EgyptAsia	EE%sT	1967 Jun  5
 			2:00	Zion	I%sT	1996
 			2:00	Jordan	EE%sT	1999
-			2:00 Palestine	EE%sT	2008 Aug 29 0:00
+			2:00 Palestine	EE%sT	2008 Aug 29  0:00
 			2:00	-	EET	2008 Sep
 			2:00 Palestine	EE%sT	2010
-			2:00	-	EET	2010 Mar 27 0:01
+			2:00	-	EET	2010 Mar 27  0:01
 			2:00 Palestine	EE%sT	2011 Aug  1
 			2:00	-	EET	2012
 			2:00 Palestine	EE%sT
@@ -2393,25 +2414,27 @@ Zone	Asia/Hebron	2:20:23	-	LMT	1900 Oct
 # no information
 
 # Philippines
-# On 1844-08-16, Narciso Claveria, governor-general of the
+# On 1844-08-16, Narciso Clavería, governor-general of the
 # Philippines, issued a proclamation announcing that 1844-12-30 was to
-# be immediately followed by 1845-01-01.  Robert H. van Gent has a
-# transcript of the decree in .
-# The rest of the data are from Shanks & Pottenger.
+# be immediately followed by 1845-01-01; see R.H. van Gent's
+# History of the International Date Line
+# http://www.staff.science.uu.nl/~gent0113/idl/idl_philippines.htm
+# The rest of the data entries are from Shanks & Pottenger.
 
-# From Paul Eggert (2006-04-25):
-# Tomorrow's Manila Standard reports that the Philippines Department of
-# Trade and Industry is considering adopting DST this June when the
-# rainy season begins.  See
-# .
-# For now, we'll ignore this, since it's not definite and we lack details.
-#
-# From Jesper Norgaard Welen (2006-04-26):
+# From Jesper Nørgaard Welen (2006-04-26):
 # ... claims that Philippines had DST last time in 1990:
 # http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
 # [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
 # but no details]
 
+# From Paul Eggert (2014-08-14):
+# The following source says DST may be instituted November-January and again
+# March-June, but this is not definite.  It also says DST was last proclaimed
+# during the Ramos administration (1992-1998); but again, no details.
+# Carcamo D. PNoy urged to declare use of daylight saving time.
+# Philippine Star 2014-08-05
+# http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time
+
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
 Rule	Phil	1937	only	-	Feb	1	0:00	0	-
@@ -2428,18 +2451,39 @@ Zone	Asia/Manila	-15:56:00 -	LMT	1844 Dec 31
 
 # Qatar
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Qatar	3:26:08 -	LMT	1920	# Al Dawhah / Doha
+Zone	Asia/Qatar	3:26:08 -	LMT	1920     # Al Dawhah / Doha
 			4:00	-	GST	1972 Jun
 			3:00	-	AST
 
 # Saudi Arabia
+#
+# From Paul Eggert (2014-07-15):
+# Time in Saudi Arabia and other countries in the Arabian peninsula was not
+# standardized until relatively recently; we don't know when, and possibly it
+# has never been made official.  Richard P Hunt, in "Islam city yielding to
+# modern times", New York Times (1961-04-09), p 20, wrote that only airlines
+# observed standard time, and that people in Jeddah mostly observed quasi-solar
+# time, doing so by setting their watches at sunrise to 6 o'clock (or to 12
+# o'clock for "Arab" time).
+#
+# The TZ database cannot represent quasi-solar time; airline time is the best
+# we can do.  The 1946 foreign air news digest of the U.S. Civil Aeronautics
+# Board (OCLC 42299995) reported that the "... Arabian Government, inaugurated
+# a weekly Dhahran-Cairo service, via the Saudi Arabian cities of Riyadh and
+# Jidda, on March 14, 1947".  Shanks & Pottenger guessed 1950; go with the
+# 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
+# the country.  Ignore this, as it's before our 1970 cutoff.
+#
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Riyadh	3:06:52 -	LMT	1950
+Zone	Asia/Riyadh	3:06:52 -	LMT	1947 Mar 14
 			3:00	-	AST
 
 # Singapore
-# The data here are taken from Mok Ly Yng (2003-10-30)
-# .
+# taken from Mok Ly Yng (2003-10-30)
+# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
 			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
@@ -2465,26 +2509,24 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
 
 # From Paul Eggert (1996-09-03):
 # "Sri Lanka advances clock by an hour to avoid blackout"
-# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
+# (, 1996-05-24,
 # no longer available as of 1999-08-17)
-# reported ``the country's standard time will be put forward by one hour at
-# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
+# reported "the country's standard time will be put forward by one hour at
+# midnight Friday (1830 GMT) 'in the light of the present power crisis'."
 #
 # From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
-# by Shamindra in
-# 
-# Daily News - Hot News Section (1996-10-26)
-# :
+# by Shamindra in Daily News - Hot News Section
+#  (1996-10-26):
 # With effect from 12.30 a.m. on 26th October 1996
 # Sri Lanka will be six (06) hours ahead of GMT.
 
-# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
+# From Jesper Nørgaard Welen (2006-04-14), quoting Sri Lanka News Online
 #  (2006-04-13):
 # 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
 # at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
 
 # From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
-# 
+# http://today.reuters.co.uk/news/newsArticle.aspx?type=scienceNews&storyID=2006-04-12T172228Z_01_COL295762_RTRIDST_0_SCIENCE-SRILANKA-TIME-DC.XML
 # [The Tamil Tigers] never accepted the original 1996 time change and simply
 # kept their clocks set five and a half hours ahead of Greenwich Mean
 # Time (GMT), in line with neighbor India.
@@ -2498,7 +2540,7 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
 # twice in 1996 and probably SL Government or its standardization
 # agencies never declared an abbreviation as a national standard.
 #
-# I recollect before the recent change the government annoucemments
+# I recollect before the recent change the government announcements
 # mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
 # Time and no mention was made about the abbreviation.
 #
@@ -2508,7 +2550,7 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
 # item....
 #
 # Within Sri Lanka I think LKT is well known among computer users and
-# adminsitrators.  In my opinion SLT may not be a good choice because the
+# administrators.  In my opinion SLT may not be a good choice because the
 # nation's largest telcom / internet operator Sri Lanka Telcom is well
 # known by that abbreviation - simply as SLT (there IP domains are
 # slt.lk and sltnet.lk).
@@ -2523,13 +2565,13 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Colombo	5:19:24 -	LMT	1880
-			5:19:32	-	MMT	1906	# Moratuwa Mean Time
+			5:19:32	-	MMT	1906        # Moratuwa Mean Time
 			5:30	-	IST	1942 Jan  5
 			5:30	0:30	IHST	1942 Sep
-			5:30	1:00	IST	1945 Oct 16 2:00
-			5:30	-	IST	1996 May 25 0:00
-			6:30	-	LKT	1996 Oct 26 0:30
-			6:00	-	LKT	2006 Apr 15 0:30
+			5:30	1:00	IST	1945 Oct 16  2:00
+			5:30	-	IST	1996 May 25  0:00
+			6:30	-	LKT	1996 Oct 26  0:30
+			6:00	-	LKT	2006 Apr 15  0:30
 			5:30	-	IST
 
 # Syria
@@ -2580,7 +2622,7 @@ Rule	Syria	2006	only	-	Sep	22	0:00	0	-
 # Today the AP reported "Syria will switch to summertime at midnight Thursday."
 # http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
 Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
-# From Jesper Norgard (2007-10-27):
+# From Jesper Nørgaard (2007-10-27):
 # The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
 # not take place 1st November at 0:00 o'clock but 1st November at 24:00 or
 # rather Midnight between Thursday and Friday. This does make more sense than
@@ -2589,7 +2631,7 @@ Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
 # it is implemented at midnight of the last workday before weekend...
 #
 # From Steffen Thorsen (2007-10-27):
-# Jesper Norgaard Welen wrote:
+# Jesper Nørgaard Welen wrote:
 #
 # > "Winter local time in Syria will be observed at midnight of Thursday 1
 # > November 2007, and the clock will be put back 1 hour."
@@ -2605,8 +2647,7 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
 
 # From Stephen Colebourne (2008-03-17):
 # For everyone's info, I saw an IATA time zone change for [Syria] for
-# this month (March 2008) in the last day or so...This is the data IATA
-# are now using:
+# this month (March 2008) in the last day or so....
 # Country     Time Standard   --- DST Start ---   --- DST End ---  DST
 # Name        Zone Variation   Time    Date        Time    Date
 # Variation
@@ -2618,16 +2659,15 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
 # From Arthur David Olson (2008-03-17):
 # Here's a link to English-language coverage by the Syrian Arab News
 # Agency (SANA)...
-# 
 # http://www.sana.sy/eng/21/2008/03/11/165173.htm
-# ...which reads (in part) "The Cabinet approved the suggestion of the
+# ...which reads (in part) "The Cabinet approved the suggestion of the
 # Ministry of Electricity to begin daylight savings time on Friday April
 # 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
 # Since Syria is two hours east of UTC, the 2200 and 2100 transition times
 # shown above match up with midnight in Syria.
 
 # From Arthur David Olson (2008-03-18):
-# My buest guess at a Syrian rule is "the Friday nearest April 1";
+# My best guess at a Syrian rule is "the Friday nearest April 1";
 # coding that involves either using a "Mar Fri>=29" construct that old time zone
 # compilers can't handle  or having multiple Rules (a la Israel).
 # For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
@@ -2640,37 +2680,27 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
 # winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
 # clocks back 60 minutes).
 #
-# 
 # http://sana.sy/ara/2/2008/10/07/195459.htm
-# 
 
 # From Steffen Thorsen (2009-03-19):
 # Syria will start DST on 2009-03-27 00:00 this year according to many sources,
 # two examples:
 #
-# 
 # http://www.sana.sy/eng/21/2009/03/17/217563.htm
-# 
 # (English, Syrian Arab News # Agency)
-# 
 # http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
-# 
 # (Arabic, gov-site)
 #
 # We have not found any sources saying anything about when DST ends this year.
 #
 # Our summary
-# 
 # http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
-# 
 
 # From Steffen Thorsen (2009-10-27):
 # The Syrian Arab News Network on 2009-09-29 reported that Syria will
 # revert back to winter (standard) time on midnight between Thursday
 # 2009-10-29 and Friday 2009-10-30:
-# 
 # http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
-# 
 
 # From Arthur David Olson (2009-10-28):
 # We'll see if future DST switching times turn out to be end of the last
@@ -2681,23 +2711,17 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
 # The "Syrian News Station" reported on 2010-03-16 that the Council of
 # Ministers has decided that Syria will start DST on midnight Thursday
 # 2010-04-01: (midnight between Thursday and Friday):
-# 
 # http://sns.sy/sns/?path=news/read/11421 (Arabic)
-# 
 
 # From Steffen Thorsen (2012-03-26):
 # Today, Syria's government announced that they will start DST early on Friday
 # (00:00). This is a bit earlier than the past two years.
 #
 # From Syrian Arab News Agency, in Arabic:
-# 
 # http://www.sana.sy/ara/2/2012/03/26/408215.htm
-# 
 #
 # Our brief summary:
-# 
 # http://www.timeanddate.com/news/time/syria-dst-2012.html
-# 
 
 # From Arthur David Olson (2012-03-27):
 # Assume last Friday in March going forward XXX.
@@ -2710,7 +2734,7 @@ Rule	Syria	2012	max	-	Mar	lastFri	0:00	1:00	S
 Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
+Zone	Asia/Damascus	2:25:12 -	LMT	1920 # Dimashq
 			2:00	Syria	EE%sT
 
 # Tajikistan
@@ -2718,9 +2742,9 @@ Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
 # 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
+			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
 
 # Thailand
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -2733,9 +2757,9 @@ Zone	Asia/Bangkok	6:42:04	-	LMT	1880
 # 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
+			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
+			4:00 RussiaAsia	TM%sT	1992 Jan 19  2:00
 			5:00	-	TMT
 
 # United Arab Emirates
@@ -2744,8 +2768,9 @@ Zone	Asia/Dubai	3:41:12 -	LMT	1920
 			4:00	-	GST
 
 # Uzbekistan
+# Byalokoz 1919 says Uzbekistan was 4:27:53.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
+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
@@ -2753,9 +2778,10 @@ Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
 			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
 			5:00 RussiaAsia	UZ%sT	1992
 			5:00	-	UZT
-Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
+# 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
+			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
@@ -2769,13 +2795,13 @@ Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
 # and Pottenger.
 
 # From Arthur David Olson (2008-03-18):
-# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
-# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
+# The English-language name of Vietnam's most populous city is "Ho Chi Minh
+# City"; use Ho_Chi_Minh below to avoid a name of more than 14 characters.
 
 # From Shanks & Pottenger:
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
-			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
 			7:00	-	ICT	1912 May
 			8:00	-	ICT	1931 May
 			7:00	-	ICT
diff --git a/jdk/make/data/tzdata/australasia b/jdk/make/data/tzdata/australasia
index 94c9adb912c..52d32904178 100644
--- a/jdk/make/data/tzdata/australasia
+++ b/jdk/make/data/tzdata/australasia
@@ -21,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -36,13 +35,13 @@
 # Please see the notes below for the controversy about "EST" versus "AEST" etc.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	-
-Rule	Aus	1917	only	-	Mar	25	2:00	0	-
-Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	-
-Rule	Aus	1942	only	-	Mar	29	2:00	0	-
-Rule	Aus	1942	only	-	Sep	27	2:00	1:00	-
-Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	-
-Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
+Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	D
+Rule	Aus	1917	only	-	Mar	25	2:00	0	S
+Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	D
+Rule	Aus	1942	only	-	Mar	29	2:00	0	S
+Rule	Aus	1942	only	-	Sep	27	2:00	1:00	D
+Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	S
+Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	D
 # Go with Whitman and the Australian National Standards Commission, which
 # says W Australia didn't use DST in 1943/1944.  Ignore Whitman's claim that
 # 1944/1945 was just like 1943/1944.
@@ -50,26 +49,26 @@ Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 # Northern Territory
 Zone Australia/Darwin	 8:43:20 -	LMT	1895 Feb
-			 9:00	-	CST	1899 May
-			 9:30	Aus	CST
+			 9:00	-	ACST	1899 May
+			 9:30	Aus	AC%sT
 # Western Australia
 #
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
-Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
-Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
-Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
-Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
-Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
-Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
-Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
-Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
+Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	D
+Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	S
+Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	D
+Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	S
+Rule	AW	1991	only	-	Nov	17	2:00s	1:00	D
+Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	S
+Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	D
+Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	S
+Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	D
 Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
-			 8:00	Aus	WST	1943 Jul
-			 8:00	AW	WST
+			 8:00	Aus	AW%sT	1943 Jul
+			 8:00	AW	AW%sT
 Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
-			 8:45	Aus	CWST	1943 Jul
-			 8:45	AW	CWST
+			 8:45	Aus	ACW%sT	1943 Jul
+			 8:45	AW	ACW%sT
 
 # Queensland
 #
@@ -85,150 +84,150 @@ Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
 # so use Lindeman.
 #
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	-
-Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	-
-Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	-
-Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	-
-Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	-
-Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	-
+Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	D
+Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	S
+Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	D
+Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	S
+Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	D
+Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	S
 Zone Australia/Brisbane	10:12:08 -	LMT	1895
-			10:00	Aus	EST	1971
-			10:00	AQ	EST
+			10:00	Aus	AE%sT	1971
+			10:00	AQ	AE%sT
 Zone Australia/Lindeman  9:55:56 -	LMT	1895
-			10:00	Aus	EST	1971
-			10:00	AQ	EST	1992 Jul
-			10:00	Holiday	EST
+			10:00	Aus	AE%sT	1971
+			10:00	AQ	AE%sT	1992 Jul
+			10:00	Holiday	AE%sT
 
 # South Australia
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
-Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
-Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
-Rule	AS	1972	only	-	Feb	27	2:00s	0	-
-Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
-Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
-Rule	AS	1991	only	-	Mar	3	2:00s	0	-
-Rule	AS	1992	only	-	Mar	22	2:00s	0	-
-Rule	AS	1993	only	-	Mar	7	2:00s	0	-
-Rule	AS	1994	only	-	Mar	20	2:00s	0	-
-Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
-Rule	AS	2006	only	-	Apr	2	2:00s	0	-
-Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
-Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
-Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	D
+Rule	AS	1986	only	-	Oct	19	2:00s	1:00	D
+Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	D
+Rule	AS	1972	only	-	Feb	27	2:00s	0	S
+Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	S
+Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	S
+Rule	AS	1991	only	-	Mar	3	2:00s	0	S
+Rule	AS	1992	only	-	Mar	22	2:00s	0	S
+Rule	AS	1993	only	-	Mar	7	2:00s	0	S
+Rule	AS	1994	only	-	Mar	20	2:00s	0	S
+Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	S
+Rule	AS	2006	only	-	Apr	2	2:00s	0	S
+Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	S
+Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	S
+Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
-			9:00	-	CST	1899 May
-			9:30	Aus	CST	1971
-			9:30	AS	CST
+			9:00	-	ACST	1899 May
+			9:30	Aus	AC%sT	1971
+			9:30	AS	AC%sT
 
 # Tasmania
 #
 # From Paul Eggert (2005-08-16):
-# 
+# http://www.bom.gov.au/climate/averages/tables/dst_times.shtml
 # says King Island didn't observe DST from WWII until late 1971.
 #
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
-Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
-Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	-
-Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	-
-Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	-
-Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	-
-Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	-
-Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	-
-Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
-Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	-
-Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
-Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
-Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
-Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
-Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
-Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
-Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
-Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
-Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
+Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	D
+Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	S
+Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	D
+Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	S
+Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	S
+Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	S
+Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	S
+Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	S
+Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	D
+Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	S
+Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	D
+Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	D
+Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	D
+Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	S
+Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	D
+Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	D
+Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	S
+Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	S
+Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
-			10:00	-	EST	1916 Oct 1 2:00
-			10:00	1:00	EST	1917 Feb
-			10:00	Aus	EST	1967
-			10:00	AT	EST
+			10:00	-	AEST	1916 Oct  1  2:00
+			10:00	1:00	AEDT	1917 Feb
+			10:00	Aus	AE%sT	1967
+			10:00	AT	AE%sT
 Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
-			10:00	-	EST	1916 Oct 1 2:00
-			10:00	1:00	EST	1917 Feb
-			10:00	Aus	EST	1971 Jul
-			10:00	AT	EST
+			10:00	-	AEST	1916 Oct  1  2:00
+			10:00	1:00	AEDT	1917 Feb
+			10:00	Aus	AE%sT	1971 Jul
+			10:00	AT	AE%sT
 
 # Victoria
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	-
-Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	-
-Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	-
-Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	-
-Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
-Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
-Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
-Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
-Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
-Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
-Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
-Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
-Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
-Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	D
+Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	S
+Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	S
+Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	S
+Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	D
+Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	D
+Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	S
+Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	S
+Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	D
+Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	D
+Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	S
+Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	S
+Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	S
+Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
-			10:00	Aus	EST	1971
-			10:00	AV	EST
+			10:00	Aus	AE%sT	1971
+			10:00	AV	AE%sT
 
 # New South Wales
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	-
-Rule	AN	1972	only	-	Feb	27	2:00s	0	-
-Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	-
-Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	-
-Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	-
-Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	-
-Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
-Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
-Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
-Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
-Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
-Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
-Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
-Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
-Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
-Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	D
+Rule	AN	1972	only	-	Feb	27	2:00s	0	S
+Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	S
+Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	S
+Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	S
+Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	S
+Rule	AN	1986	only	-	Oct	19	2:00s	1:00	D
+Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	D
+Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	S
+Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	S
+Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	D
+Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	D
+Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	S
+Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	S
+Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	S
+Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
-			10:00	Aus	EST	1971
-			10:00	AN	EST
+			10:00	Aus	AE%sT	1971
+			10:00	AN	AE%sT
 Zone Australia/Broken_Hill 9:25:48 -	LMT	1895 Feb
-			10:00	-	EST	1896 Aug 23
-			9:00	-	CST	1899 May
-			9:30	Aus	CST	1971
-			9:30	AN	CST	2000
-			9:30	AS	CST
+			10:00	-	AEST	1896 Aug 23
+			9:00	-	ACST	1899 May
+			9:30	Aus	AC%sT	1971
+			9:30	AN	AC%sT	2000
+			9:30	AS	AC%sT
 
 # Lord Howe Island
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	-
-Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	-
-Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	-
-Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	-
-Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
-Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
-Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
-Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
-Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
-Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
-Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
-Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
-Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
-Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
+Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	D
+Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	S
+Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	D
+Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	S
+Rule	LH	1986	only	-	Oct	19	2:00	0:30	D
+Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	D
+Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	S
+Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	S
+Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	D
+Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	D
+Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	S
+Rule	LH	2007	only	-	Mar	lastSun	2:00	0	S
+Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	S
+Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	D
 Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
-			10:00	-	EST	1981 Mar
-			10:30	LH	LHST
+			10:00	-	AEST	1981 Mar
+			10:30	LH	LH%sT
 
 # Australian miscellany
 #
@@ -244,8 +243,8 @@ Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
 # Permanent occupation (scientific station) 1911-1915 and since 25 March 1948;
 # sealing and penguin oil station operated Nov 1899 to Apr 1919.  See the
 # Tasmania Parks & Wildlife Service history of sealing at Macquarie Island
-# 
-# .
+# http://www.parks.tas.gov.au/index.aspx?base=1828
+# http://www.parks.tas.gov.au/index.aspx?base=1831
 # Guess that it was like Australia/Hobart while inhabited before 2010.
 #
 # From Steffen Thorsen (2010-03-10):
@@ -256,16 +255,16 @@ Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
 #
 # From Arthur David Olson (2013-05-23):
 # The 1919 transition is overspecified below so pre-2013 zics
-# will produce a binary file with an EST-type as the first 32-bit type;
+# will produce a binary file with an [A]EST-type as the first 32-bit type;
 # this is required for correct handling of times before 1916 by
 # pre-2013 versions of localtime.
 Zone Antarctica/Macquarie 0	-	zzz	1899 Nov
-			10:00	-	EST	1916 Oct 1 2:00
-			10:00	1:00	EST	1917 Feb
-			10:00	Aus	EST	1919 Apr 1 0:00s
+			10:00	-	AEST	1916 Oct  1  2:00
+			10:00	1:00	AEDT	1917 Feb
+			10:00	Aus	AE%sT	1919 Apr  1  0:00s
 			0	-	zzz	1948 Mar 25
-			10:00	Aus	EST	1967
-			10:00	AT	EST	2010 Apr 4 3:00
+			10:00	Aus	AE%sT	1967
+			10:00	AT	AE%sT	2010 Apr  4  3:00
 			11:00	-	MIST	# Macquarie I Standard Time
 
 # Christmas
@@ -273,24 +272,14 @@ Zone Antarctica/Macquarie 0	-	zzz	1899 Nov
 Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
 			7:00	-	CXT	# Christmas Island Time
 
-# Cook Is
-# From Shanks & Pottenger:
-# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
-Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
-Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
-# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901		# Avarua
-			-10:30	-	CKT	1978 Nov 12	# Cook Is Time
-			-10:00	Cook	CK%sT
-
-# Cocos
+# Cocos (Keeling) Is
 # These islands were ruled by the Ross family from about 1830 to 1978.
 # We don't know when standard time was introduced; for now, we guess 1900.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Indian/Cocos	6:27:40	-	LMT	1900
 			6:30	-	CCT	# Cocos Islands Time
 
+
 # Fiji
 
 # Milne gives 11:55:44 for Suva.
@@ -300,20 +289,13 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
 # from November 29th 2009  to April 25th 2010.
 #
 # "Daylight savings to commence this month"
-# 
 # http://www.radiofiji.com.fj/fullstory.php?id=23719
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_fiji01.html
-# 
 
 # From Steffen Thorsen (2009-11-10):
 # The Fiji Government has posted some more details about the approved
 # amendments:
-# 
 # http://www.fiji.gov.fj/publish/page_16198.shtml
-# 
 
 # From Steffen Thorsen (2010-03-03):
 # The Cabinet in Fiji has decided to end DST about a month early, on
@@ -322,35 +304,24 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
 # 2011 (last Sunday a good guess?).
 #
 # Official source:
-# 
 # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
-# 
 #
 # A bit more background info here:
-# 
 # http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
-# 
 
 # From Alexander Krivenyshev (2010-10-24):
 # According to Radio Fiji and Fiji Times online, Fiji will end DST 3
 # weeks earlier than expected - on March 6, 2011, not March 27, 2011...
 # Here is confirmation from Government of the Republic of the Fiji Islands,
 # Ministry of Information (fiji.gov.fj) web site:
-# 
 # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
-# 
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
-# 
 
 # From Steffen Thorsen (2011-10-03):
 # Now the dates have been confirmed, and at least our start date
 # assumption was correct (end date was one week wrong).
 #
-# 
-# www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
-# 
+# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
 # which says
 # Members of the public are reminded to change their time to one hour in
 # advance at 2am to 3am on October 23, 2011 and one hour back at 3am to
@@ -360,9 +331,7 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
 # Another change to the Fiji DST end date. In the TZ database the end date for
 # Fiji DST 2012, is currently Feb 26. This has been changed to Jan 22.
 #
-# 
 # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=5017:amendments-to-daylight-savings&catid=71:press-releases&Itemid=155
-# 
 # states:
 #
 # The end of daylight saving scheduled initially for the 26th of February 2012
@@ -400,16 +369,16 @@ Rule	Fiji	2011	only	-	Mar	Sun>=1	3:00	0	-
 Rule	Fiji	2012	2013	-	Jan	Sun>=18	3:00	0	-
 Rule	Fiji	2014	max	-	Jan	Sun>=18	2:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Fiji	11:55:44 -	LMT	1915 Oct 26	# Suva
+Zone	Pacific/Fiji	11:55:44 -	LMT	1915 Oct 26 # Suva
 			12:00	Fiji	FJ%sT	# Fiji Time
 
 # French Polynesia
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct	# Rikitea
+Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct # Rikitea
 			 -9:00	-	GAMT	# Gambier Time
 Zone	Pacific/Marquesas -9:18:00 -	LMT	1912 Oct
 			 -9:30	-	MART	# Marquesas Time
-Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
+Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct # Papeete
 			-10:00	-	TAHT	# Tahiti Time
 # Clipperton (near North America) is administered from French Polynesia;
 # it is uninhabited.
@@ -417,14 +386,14 @@ Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
 # Guam
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Pacific/Guam	-14:21:00 -	LMT	1844 Dec 31
-			 9:39:00 -	LMT	1901		# Agana
-			10:00	-	GST	2000 Dec 23	# Guam
+			 9:39:00 -	LMT	1901        # Agana
+			10:00	-	GST	2000 Dec 23 # Guam
 			10:00	-	ChST	# Chamorro Standard Time
 
 # Kiribati
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Pacific/Tarawa	 11:32:04 -	LMT	1901		# Bairiki
-			 12:00	-	GILT		 # Gilbert Is Time
+Zone Pacific/Tarawa	 11:32:04 -	LMT	1901 # Bairiki
+			 12:00	-	GILT	# Gilbert Is Time
 Zone Pacific/Enderbury	-11:24:20 -	LMT	1901
 			-12:00	-	PHOT	1979 Oct # Phoenix Is Time
 			-11:00	-	PHOT	1995
@@ -438,7 +407,7 @@ Zone Pacific/Kiritimati	-10:29:20 -	LMT	1901
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Pacific/Saipan	-14:17:00 -	LMT	1844 Dec 31
 			 9:43:00 -	LMT	1901
-			 9:00	-	MPT	1969 Oct # N Mariana Is Time
+			 9:00	-	MPT	1969 Oct    # N Mariana Is Time
 			10:00	-	MPT	2000 Dec 23
 			10:00	-	ChST	# Chamorro Standard Time
 
@@ -449,24 +418,24 @@ Zone Pacific/Majuro	11:24:48 -	LMT	1901
 			12:00	-	MHT
 Zone Pacific/Kwajalein	11:09:20 -	LMT	1901
 			11:00	-	MHT	1969 Oct
-			-12:00	-	KWAT	1993 Aug 20	# Kwajalein Time
+			-12:00	-	KWAT	1993 Aug 20 # Kwajalein Time
 			12:00	-	MHT
 
 # Micronesia
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Pacific/Chuuk	10:07:08 -	LMT	1901
-			10:00	-	CHUT			# Chuuk Time
-Zone Pacific/Pohnpei	10:32:52 -	LMT	1901		# Kolonia
-			11:00	-	PONT			# Pohnpei Time
+			10:00	-	CHUT	# Chuuk Time
+Zone Pacific/Pohnpei	10:32:52 -	LMT	1901 # Kolonia
+			11:00	-	PONT	# Pohnpei Time
 Zone Pacific/Kosrae	10:51:56 -	LMT	1901
-			11:00	-	KOST	1969 Oct	# Kosrae Time
+			11:00	-	KOST	1969 Oct # Kosrae Time
 			12:00	-	KOST	1999
 			11:00	-	KOST
 
 # Nauru
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15	# Uaobe
-			11:30	-	NRT	1942 Mar 15	# Nauru Time
+Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15 # Uaobe
+			11:30	-	NRT	1942 Mar 15 # Nauru Time
 			9:00	-	JST	1944 Aug 15
 			11:30	-	NRT	1979 May
 			12:00	-	NRT
@@ -479,7 +448,7 @@ Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
 # Shanks & Pottenger say the following was at 2:00; go with IATA.
 Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
+Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13 # Nouméa
 			11:00	NC	NC%sT
 
 
@@ -496,7 +465,8 @@ Rule	NZ	1934	1940	-	Apr	lastSun	2:00	0	M
 Rule	NZ	1934	1940	-	Sep	lastSun	2:00	0:30	S
 Rule	NZ	1946	only	-	Jan	 1	0:00	0	S
 # Since 1957 Chatham has been 45 minutes ahead of NZ, but there's no
-# convenient notation for this so we must duplicate the Rule lines.
+# convenient single notation for the date and time of this transition
+# so we must duplicate the Rule lines.
 Rule	NZ	1974	only	-	Nov	Sun>=1	2:00s	1:00	D
 Rule	Chatham	1974	only	-	Nov	Sun>=1	2:45s	1:00	D
 Rule	NZ	1975	only	-	Feb	lastSun	2:00s	0	S
@@ -519,13 +489,14 @@ Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
 Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
 			11:30	NZ	NZ%sT	1946 Jan  1
 			12:00	NZ	NZ%sT
-Zone Pacific/Chatham	12:13:48 -	LMT	1957 Jan  1
+Zone Pacific/Chatham	12:13:48 -	LMT	1868 Nov  2
+			12:15	-	CHAST	1946 Jan  1
 			12:45	Chatham	CHA%sT
 
 Link Pacific/Auckland Antarctica/McMurdo
 
 # Auckland Is
-# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
+# uninhabited; Māori and Moriori, colonial settlers, pastoralists, sealers,
 # and scientific personnel have wintered
 
 # Campbell I
@@ -534,48 +505,58 @@ Link Pacific/Auckland Antarctica/McMurdo
 # previously whalers, sealers, pastoralists, and scientific personnel wintered
 # was probably like Pacific/Auckland
 
+# Cook Is
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
+Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
+Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901        # Avarua
+			-10:30	-	CKT	1978 Nov 12 # Cook Is Time
+			-10:00	Cook	CK%sT
+
 ###############################################################################
 
 
 # Niue
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Niue	-11:19:40 -	LMT	1901		# Alofi
-			-11:20	-	NUT	1951	# Niue Time
-			-11:30	-	NUT	1978 Oct 1
+Zone	Pacific/Niue	-11:19:40 -	LMT	1901        # Alofi
+			-11:20	-	NUT	1951        # Niue Time
+			-11:30	-	NUT	1978 Oct  1
 			-11:00	-	NUT
 
 # Norfolk
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Norfolk	11:11:52 -	LMT	1901		# Kingston
-			11:12	-	NMT	1951	# Norfolk Mean Time
-			11:30	-	NFT		# Norfolk Time
+Zone	Pacific/Norfolk	11:11:52 -	LMT	1901 # Kingston
+			11:12	-	NMT	1951 # Norfolk Mean Time
+			11:30	-	NFT	# Norfolk Time
 
 # Palau (Belau)
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Pacific/Palau	8:57:56 -	LMT	1901		# Koror
+Zone Pacific/Palau	8:57:56 -	LMT	1901 # Koror
 			9:00	-	PWT	# Palau Time
 
 # Papua New Guinea
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Pacific/Port_Moresby 9:48:40 -	LMT	1880
-			9:48:32	-	PMMT	1895	# Port Moresby Mean Time
-			10:00	-	PGT		# Papua New Guinea Time
+			9:48:32	-	PMMT	1895 # Port Moresby Mean Time
+			10:00	-	PGT	# Papua New Guinea Time
 
 # Pitcairn
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901		# Adamstown
-			-8:30	-	PNT	1998 Apr 27 00:00
+Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901        # Adamstown
+			-8:30	-	PNT	1998 Apr 27  0:00
 			-8:00	-	PST	# Pitcairn Standard Time
 
 # American Samoa
 Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
 			-11:22:48 -	LMT	1911
-			-11:30	-	SAMT	1950		# Samoa Time
-			-11:00	-	NST	1967 Apr	# N=Nome
-			-11:00	-	BST	1983 Nov 30	# B=Bering
-			-11:00	-	SST			# S=Samoa
+			-11:00	-	NST	1967 Apr    # N=Nome
+			-11:00	-	BST	1983 Nov 30 # B=Bering
+			-11:00	-	SST	            # S=Samoa
 
-# Samoa
+# Samoa (formerly and also known as Western Samoa)
 
 # From Steffen Thorsen (2009-10-16):
 # We have been in contact with the government of Samoa again, and received
@@ -586,141 +567,80 @@ Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
 # Sunday of April 2011."
 #
 # Background info:
-# 
 # http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
-# 
 #
 # Samoa's Daylight Saving Time Act 2009 is available here, but does not
 # contain any dates:
-# 
 # http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
-# 
 
 # From Laupue Raymond Hughes (2010-10-07):
 # Please see
-# 
 # http://www.mcil.gov.ws
-# ,
 # the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
 # September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
 # to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
 # backwards from 1:00am to 12:00am"
 
 # From Laupue Raymond Hughes (2011-03-07):
-# I believe this will be posted shortly on the website
-# 
-# www.mcil.gov.ws
-# 
+# [http://www.mcil.gov.ws/ftcd/daylight_saving_2011.pdf]
 #
-# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
-#
-# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
-# businesses and the general public are hereby advised that daylight
-# saving time is on the first Saturday of April 2011 (02/04/11).
-#
-# The public is therefore advised that when the standard time strikes
-# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
-# then all instruments used to measure standard time are to be
-# adjusted/changed to three oclock (3:00am or 0300Hrs).
-#
-# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
-# INDUSTRY AND LABOUR 28th February 2011
+# ... when the standard time strikes the hour of four o'clock (4.00am
+# or 0400 Hours) on the 2nd April 2011, then all instruments used to
+# measure standard time are to be adjusted/changed to three o'clock
+# (3:00am or 0300Hrs).
 
-# From David Zuelke (2011-05-09):
+# From David Zülke (2011-05-09):
 # Subject: Samoa to move timezone from east to west of international date line
 #
-# 
 # http://www.morningstar.co.uk/uk/markets/newsfeeditem.aspx?id=138501958347963
-# 
 
-# From Mark Sim-Smith (2011-08-17):
-# I have been in contact with Leilani Tuala Warren from the Samoa Law
-# Reform Commission, and she has sent me a copy of the Bill that she
-# confirmed has been passed...Most of the sections are about maps rather
-# than the time zone change, but I'll paste the relevant bits below. But
-# the essence is that at midnight 29 Dec (UTC-11 I suppose), Samoa
-# changes from UTC-11 to UTC+13:
-#
-# International Date Line Bill 2011
-#
-# AN ACT to provide for the change to standard time in Samoa and to make
-# consequential amendments to the position of the International Date
-# Line, and for related purposes.
-#
-# BE IT ENACTED by the Legislative Assembly of Samoa in Parliament
-# assembled as follows:
-#
-# 1. Short title and commencement-(1) This Act may be cited as the
-# International Date Line Act 2011. (2) Except for section 5(3) this Act
-# commences at 12 o'clock midnight, on Thursday 29th December 2011. (3)
-# Section 5(3) commences on the date of assent by the Head of State.
-#
-# [snip]
-#
-# 3. Interpretation - [snip] "Samoa standard time" in this Act and any
-# other statute of Samoa which refers to 'Samoa standard time' means the
-# time 13 hours in advance of Co-ordinated Universal Time.
-#
-# 4. Samoa standard time - (1) Upon the commencement of this Act, Samoa
-# standard time shall be set at 13 hours in advance of Co-ordinated
-# Universal Time for the whole of Samoa. (2) All references to Samoa's
-# time zone and to Samoa standard time in Samoa in all legislation and
-# instruments after the commencement of this Act shall be references to
-# Samoa standard time as provided for in this Act. (3) Nothing in this
-# Act affects the provisions of the Daylight Saving Act 2009, except that
-# it defines Samoa standard time....
+# 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
+# Thursday 29th December 2011".  The International Date Line was adjusted
+# accordingly.
 
 # From Laupue Raymond Hughes (2011-09-02):
-# 
 # http://www.mcil.gov.ws/mcil_publications.html
-# 
 #
 # here is the official website publication for Samoa DST and dateline change
 #
 # DST
-# Year	End	Time	Start	Time
-# 2011	- - -	- - -	24 September	3:00am to 4:00am
-# 2012	01 April	4:00am to 3:00am	- - -	- - -
+# Year  End      Time              Start        Time
+# 2011  - - -    - - -             24 September 3:00am to 4:00am
+# 2012  01 April 4:00am to 3:00am  - - -        - - -
 #
 # Dateline Change skip Friday 30th Dec 2011
 # Thursday 29th December 2011	23:59:59 Hours
 # Saturday 31st December 2011	00:00:00 Hours
 #
-# Clarification by Tim Parenti (2012-01-03):
-# Although Samoa has used Daylight Saving Time in the 2010-2011 and 2011-2012
-# seasons, there is not yet any indication that this trend will continue on
-# a regular basis. For now, we have explicitly listed the transitions below.
-#
-# From Nicky (2012-09-10):
+# From Nicholas Pereira (2012-09-10):
 # Daylight Saving Time commences on Sunday 30th September 2012 and
-# ends on Sunday 7th of April 2013.
-#
-# Please find link below for more information.
+# ends on Sunday 7th of April 2013....
 # http://www.mcil.gov.ws/mcil_publications.html
 #
-# That publication also includes dates for Summer of 2013/4 as well
-# which give the impression of a pattern in selecting dates for the
-# future, so for now, we will guess this will continue.
+# From Paul Eggert (2014-07-08):
+# That web page currently lists transitions for 2012/3 and 2013/4.
+# Assume the pattern instituted in 2012 will continue indefinitely.
 
-# Western Samoa
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	WS	2010	only	-	Sep	lastSun	0:00	1	D
+Rule	WS	2011	only	-	Apr	Sat>=1	4:00	0	S
+Rule	WS	2011	only	-	Sep	lastSat	3:00	1	D
+Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	S
 Rule	WS	2012	max	-	Sep	lastSun	3:00	1	D
-Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
 			-11:26:56 -	LMT	1911
-			-11:30	-	SAMT	1950		# Samoa Time
-			-11:00	-	WST	2010 Sep 26
-			-11:00	1:00	WSDT	2011 Apr 2 4:00
-			-11:00	-	WST	2011 Sep 24 3:00
-			-11:00	1:00	WSDT	2011 Dec 30
-			 13:00	1:00	WSDT	2012 Apr Sun>=1 4:00
+			-11:30	-	WSST	1950
+			-11:00	WS	S%sT	2011 Dec 29 24:00 # S=Samoa
 			 13:00	WS	WS%sT
 
 # Solomon Is
 # excludes Bougainville, for which see Papua New Guinea
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
+Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct # Honiara
 			11:00	-	SBT	# Solomon Is Time
 
 # Tokelau Is
@@ -744,7 +664,7 @@ Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Pacific/Fakaofo	-11:24:56 -	LMT	1901
-			-11:00	-	TKT 2011 Dec 30	# Tokelau Time
+			-11:00	-	TKT	2011 Dec 30 # Tokelau Time
 			13:00	-	TKT
 
 # Tonga
@@ -804,8 +724,8 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
 # time from Operation Newsreel (Hardtack I/Teak shot, 1958-08-01) to the last
 # Operation Fishbowl shot (Tightrope, 1962-11-04).... [See] Herman Hoerlin,
 # "The United States High-Altitude Test Experience: A Review Emphasizing the
-# Impact on the Environment", Los Alamos LA-6405, Oct 1976
-# .
+# Impact on the Environment", Los Alamos LA-6405, Oct 1976.
+# http://www.fas.org/sgp/othergov/doe/lanl/docs1/00322994.pdf
 # See the table on page 4 where he lists GMT and local times for the tests; a
 # footnote for the JI tests reads that local time is "JI time = Hawaii Time
 # Minus One Hour".
@@ -820,7 +740,7 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
 # From Mark Brader (2005-01-23):
 # [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
 # published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
-# reproduced a Pan American Airways timeables from 1936, for their weekly
+# reproduced a Pan American Airways timetable from 1936, for their weekly
 # "Orient Express" flights between San Francisco and Manila, and connecting
 # flights to Chicago and the US East Coast.  As it uses some time zone
 # designations that I've never seen before:....
@@ -830,9 +750,9 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
 Zone Pacific/Midway	-11:49:28 -	LMT	1901
 			-11:00	-	NST	1956 Jun  3
 			-11:00	1:00	NDT	1956 Sep  2
-			-11:00	-	NST	1967 Apr	# N=Nome
-			-11:00	-	BST	1983 Nov 30	# B=Bering
-			-11:00	-	SST			# S=Samoa
+			-11:00	-	NST	1967 Apr    # N=Nome
+			-11:00	-	BST	1983 Nov 30 # B=Bering
+			-11:00	-	SST	            # S=Samoa
 
 # Palmyra
 # uninhabited since World War II; was probably like Pacific/Kiritimati
@@ -852,7 +772,7 @@ Rule	Vanuatu	1985	1991	-	Sep	Sun>=23	0:00	1:00	S
 Rule	Vanuatu	1992	1993	-	Jan	Sun>=23	0:00	0	-
 Rule	Vanuatu	1992	only	-	Oct	Sun>=23	0:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13		# Vila
+Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13 # Vila
 			11:00	Vanuatu	VU%sT	# Vanuatu Time
 
 # Wallis and Futuna
@@ -864,9 +784,10 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 
 # NOTES
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
 # From Paul Eggert (2013-02-21):
 # A good source for time zone historical data outside the U.S. is
@@ -887,165 +808,188 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # I found in the UCLA library.
 #
 # For data circa 1899, a common source is:
-# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
-# .
+# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
+# http://www.jstor.org/stable/1774359
 #
 # A reliable and entertaining source about time zones is
 # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
 #
-# I invented the abbreviations marked `*' in the following table;
+# I invented the abbreviations marked '*' in the following table;
 # the rest are from earlier versions of this file, or from other sources.
 # Corrections are welcome!
-#		std dst
-#		LMT	Local Mean Time
-#	  8:00	WST WST	Western Australia
-#	  8:45	CWST CWST Central Western Australia*
-#	  9:00	JST	Japan
-#	  9:30	CST CST	Central Australia
-#	 10:00	EST EST	Eastern Australia
-#	 10:00	ChST	Chamorro
-#	 10:30	LHST LHST Lord Howe*
-#	 11:30	NZMT NZST New Zealand through 1945
-#	 12:00	NZST NZDT New Zealand 1946-present
-#	 12:45	CHAST CHADT Chatham*
-#	-11:00	SST	Samoa
-#	-10:00	HST	Hawaii
-#	- 8:00	PST	Pitcairn*
+#		std	dst
+#		LMT		Local Mean Time
+#	  8:00	AWST	AWDT	Western Australia
+#	  8:45	ACWST	ACWDT	Central Western Australia*
+#	  9:00	JST		Japan
+#	  9:30	ACST	ACDT	Central Australia
+#	 10:00	AEST	AEDT	Eastern Australia
+#	 10:00	ChST		Chamorro
+#	 10:30	LHST	LHDT	Lord Howe*
+#	 11:30	NZMT	NZST	New Zealand through 1945
+#	 12:00	NZST	NZDT	New Zealand 1946-present
+#	 12:15	CHAST		Chatham through 1945*
+#	 12:45	CHAST	CHADT	Chatham 1946-present*
+#	 13:00	WSST	WSDT	(western) Samoa 2011-present*
+#	-11:30	WSST		Western Samoa through 1950*
+#	-11:00	SST		Samoa
+#	-10:00	HST		Hawaii
+#	- 8:00	PST		Pitcairn*
 #
-# See the `northamerica' file for Hawaii.
-# See the `southamerica' file for Easter I and the Galapagos Is.
+# See the 'northamerica' file for Hawaii.
+# See the 'southamerica' file for Easter I and the Galápagos Is.
 
 ###############################################################################
 
 # Australia
 
+# From Paul Eggert (2014-06-30):
+# Daylight saving time has long been controversial in Australia, pitting
+# region against region, rural against urban, and local against global.
+# For example, in her review of Graeme Davison's _The Unforgiving
+# Minute: how Australians learned to tell the time_ (1993), Perth native
+# Phillipa J Martyr wrote, "The section entitled 'Saving Daylight' was
+# very informative, but was (as can, sadly, only be expected from a
+# Melbourne-based study) replete with the usual chuckleheaded
+# Queenslanders and straw-chewing yokels from the West prattling fables
+# about fading curtains and crazed farm animals."
+# Electronic Journal of Australian and New Zealand History (1997-03-03)
+# http://www.jcu.edu.au/aff/history/reviews/davison.htm
+
 # From Paul Eggert (2005-12-08):
-# 
 # Implementation Dates of Daylight Saving Time within Australia
-#  summarizes daylight saving issues in Australia.
+# http://www.bom.gov.au/climate/averages/tables/dst_times.shtml
+# summarizes daylight saving issues in Australia.
 
 # From Arthur David Olson (2005-12-12):
-# 
 # Lawlink NSW:Daylight Saving in New South Wales
-#  covers New South Wales in particular.
+# http://www.lawlink.nsw.gov.au/lawlink/Corporate/ll_agdinfo.nsf/pages/community_relations_daylight_saving
+# covers New South Wales in particular.
 
 # From John Mackin (1991-03-06):
-# We in Australia have _never_ referred to DST as `daylight' time.
-# It is called `summer' time.  Now by a happy coincidence, `summer'
-# and `standard' happen to start with the same letter; hence, the
+# We in Australia have _never_ referred to DST as 'daylight' time.
+# It is called 'summer' time.  Now by a happy coincidence, 'summer'
+# and 'standard' happen to start with the same letter; hence, the
 # abbreviation does _not_ change...
 # The legislation does not actually define abbreviations, at least
 # in this State, but the abbreviation is just commonly taken to be the
 # initials of the phrase, and the legislation here uniformly uses
-# the phrase `summer time' and does not use the phrase `daylight
+# the phrase 'summer time' and does not use the phrase 'daylight
 # time'.
 # Announcers on the Commonwealth radio network, the ABC (for Australian
-# Broadcasting Commission), use the phrases `Eastern Standard Time'
-# or `Eastern Summer Time'.  (Note, though, that as I say in the
+# Broadcasting Commission), use the phrases 'Eastern Standard Time'
+# or 'Eastern Summer Time'.  (Note, though, that as I say in the
 # current australasia file, there is really no such thing.)  Announcers
 # on its overseas service, Radio Australia, use the same phrases
-# prefixed by the word `Australian' when referring to local times;
+# prefixed by the word 'Australian' when referring to local times;
 # time announcements on that service, naturally enough, are made in UTC.
 
-# From Arthur David Olson (1992-03-08):
-# Given the above, what's chosen for year-round use is:
-#	CST	for any place operating at a GMTOFF of 9:30
-#	WST	for any place operating at a GMTOFF of 8:00
-#	EST	for any place operating at a GMTOFF of 10:00
-
-# From Chuck Soper (2006-06-01):
-# I recently found this Australian government web page on time zones:
-# 
-# And this government web page lists time zone names and abbreviations:
-# 
-
-# From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
-# versus "AEST" etc.:
+# From Paul Eggert (2014-06-30):
 #
-# I see the following points of dispute:
+# Inspired by Mackin's remarks quoted above, earlier versions of this
+# file used "EST" for both Eastern Standard Time and Eastern Summer
+# Time in Australia, and similarly for "CST", "CWST", and "WST".
+# However, these abbreviations were confusing and were not common
+# practice among Australians, and there were justifiable complaints
+# about them, so I attempted to survey current Australian usage.
+# For the tz database, the full English phrase is not that important;
+# what matters is the abbreviation.  It's difficult to survey the web
+# directly for abbreviation usage, as there are so many false hits for
+# strings like "EST" and "EDT", so I looked for pages that defined an
+# abbreviation for eastern or central DST in Australia, and got the
+# following numbers of unique hits for the listed Google queries:
 #
-# * How important are unique time zone abbreviations?
+#   10 "Eastern Daylight Time AEST" site:au [some are false hits]
+#   10 "Eastern Summer Time AEST" site:au
+#   10 "Summer Time AEDT" site:au
+#   13 "EDST Eastern Daylight Saving Time" site:au
+#   18 "Summer Time ESST" site:au
+#   28 "Eastern Daylight Saving Time EDST" site:au
+#   39 "EDT Eastern Daylight Time" site:au [some are false hits]
+#   53 "Eastern Daylight Time EDT" site:au [some are false hits]
+#   54 "AEDT Australian Eastern Daylight Time" site:au
+#  182 "Eastern Daylight Time AEDT" site:au
 #
-#   Here I tend to agree with the point (most recently made by Chris
-#   Newman) that unique abbreviations should not be essential for proper
-#   operation of software.  We have other instances of ambiguity
-#   (e.g. "IST" denoting both "Israel Standard Time" and "Indian
-#   Standard Time"), and they are not likely to go away any time soon.
-#   In the old days, some software mistakenly relied on unique
-#   abbreviations, but this is becoming less true with time, and I don't
-#   think it's that important to cater to such software these days.
+#   17 "Central Daylight Time CDT" site:au [some are false hits]
+#   46 "Central Daylight Time ACDT" site:au
 #
-#   On the other hand, there is another motivation for unambiguous
-#   abbreviations: it cuts down on human confusion.  This is
-#   particularly true for Australia, where "EST" can mean one thing for
-#   time T and a different thing for time T plus 1 second.
+# I tried several other variants (e.g., "Eastern Summer Time EST") but
+# they all returned fewer than 10 unique hits.  I also looked for pages
+# mentioning both "western standard time" and an abbreviation, since
+# there is no WST in the US to generate false hits, and found:
 #
-# * Does the relevant legislation indicate which abbreviations should be used?
+#  156 "western standard time" AWST site:au
+#  226 "western standard time" WST site:au
 #
-#   Here I tend to think that things are a mess, just as they are in
-#   many other countries.  We Americans are currently disagreeing about
-#   which abbreviation to use for the newly legislated Chamorro Standard
-#   Time, for example.
+# I then surveyed the top ten newspapers in Australia by circulation as
+# listed in Wikipedia, using Google queries like "AEDT site:heraldsun.com.au"
+# and obtaining estimated counts from the initial page of search results.
+# All ten papers greatly preferred "AEDT" to "EDT".  The papers
+# surveyed were the Herald Sun, The Daily Telegraph, The Courier-Mail,
+# The Sydney Morning Herald, The West Australian, The Age, The Advertiser,
+# The Australian, The Financial Review, and The Herald (Newcastle).
 #
-#   Personally, I would prefer to use common practice; I would like to
-#   refer to legislation only for examples of common practice, or as a
-#   tiebreaker.
+# I also searched for historical usage, to see whether abbreviations
+# like "AEDT" are new.  A Trove search 
+# found only one newspaper (The Canberra Times) with a house style
+# dating back to the 1970s, I expect because other newspapers weren't
+# fully indexed.  The Canberra Times strongly preferred abbreviations
+# like "AEDT".  The first occurrence of "AEDT" was a World Weather
+# column (1971-11-17, page 24), and of "ACDT" was a Scoreboard column
+# (1993-01-24, p 16).  The style was the typical usage but was not
+# strictly enforced; for example, "Welcome to the twilight zones ..."
+# (1994-10-29, p 1) uses the abbreviations AEST/AEDT, CST/CDT, and
+# WST, and goes on to say, "The confusion and frustration some feel
+# about the lack of uniformity among Australia's six states and two
+# territories has prompted one group to form its very own political
+# party -- the Sydney-based Daylight Saving Extension Party."
 #
-# * Do Australians more often use "Eastern Daylight Time" or "Eastern
-#   Summer Time"?  Do they typically prefix the time zone names with
-#   the word "Australian"?
+# I also surveyed federal government sources.  They did not agree:
 #
-#   My own impression is that both "Daylight Time" and "Summer Time" are
-#   common and are widely understood, but that "Summer Time" is more
-#   popular; and that the leading "A" is also common but is omitted more
-#   often than not.  I just used AltaVista advanced search and got the
-#   following count of page hits:
+#   The Australian Government (2014-03-26)
+#   http://australia.gov.au/about-australia/our-country/time
+#   (This document was produced by the Department of Finance.)
+#   AEST ACST AWST AEDT ACDT
 #
-#     1,103 "Eastern Summer Time" AND domain:au
-#       971 "Australian Eastern Summer Time" AND domain:au
-#       613 "Eastern Daylight Time" AND domain:au
-#       127 "Australian Eastern Daylight Time" AND domain:au
+#   Bureau of Meteorology (2012-11-08)
+#   http://www.bom.gov.au/climate/averages/tables/daysavtm.shtml
+#   EST CST WST EDT CDT
 #
-#   Here "Summer" seems quite a bit more popular than "Daylight",
-#   particularly when we know the time zone is Australian and not US,
-#   say.  The "Australian" prefix seems to be popular for Eastern Summer
-#   Time, but unpopular for Eastern Daylight Time.
+#   Civil Aviation Safety Authority (undated)
+#   http://services.casa.gov.au/outnback/inc/pages/episode3/episode-3_time_zones.shtml
+#   EST CST WST (no abbreviations given for DST)
 #
-#   For abbreviations, tools like AltaVista are less useful because of
-#   ambiguity.  Many hits are not really time zones, unfortunately, and
-#   many hits denote US time zones and not Australian ones.  But here
-#   are the hit counts anyway:
+#   Geoscience Australia (2011-11-24)
+#   http://www.ga.gov.au/geodesy/astro/sunrise.jsp
+#   AEST ACST AWST AEDT ACDT
 #
-#     161,304 "EST" and domain:au
-#      25,156 "EDT" and domain:au
-#      18,263 "AEST" and domain:au
-#      10,416 "AEDT" and domain:au
+#   Parliamentary Library (2008-11-10)
+#   http://www.aph.gov.au/binaries/library/pubs/rp/2008-09/09rp14.pdf
+#   EST CST WST preferred for standard time; AEST AEDT ACST ACDT also used
 #
-#      14,538 "CST" and domain:au
-#       5,728 "CDT" and domain:au
-#         176 "ACST" and domain:au
-#          29 "ACDT" and domain:au
+#   The Transport Safety Bureau has an extensive series of accident reports,
+#   and investigators seem to use whatever abbreviation they like.
+#   Googling site:atsb.gov.au found the following number of unique hits:
+#   311 "ESuT", 195 "EDT", 26 "AEDT", 83 "CSuT", 46 "CDT".
+#   "_SuT" tended to appear in older reports, and "A_DT" tended to
+#   appear in reports of events with international implications.
 #
-#       7,539 "WST" and domain:au
-#          68 "AWST" and domain:au
-#
-#   This data suggest that Australians tend to omit the "A" prefix in
-#   practice.  The situation for "ST" versus "DT" is less clear, given
-#   the ambiguities involved.
-#
-# * How do Australians feel about the abbreviations in the tz database?
-#
-#   If you just count Australians on this list, I count 2 in favor and 3
-#   against.  One of the "against" votes (David Keegel) counseled delay,
-#   saying that both AEST/AEDT and EST/EST are widely used and
-#   understood in Australia.
+# From the above it appears that there is a working consensus in
+# Australia to use trailing "DT" for daylight saving time; although
+# some sources use trailing "SST" or "ST" or "SuT" they are by far in
+# the minority.  The case for leading "A" is weaker, but since it
+# seems to be preferred in the overall web and is preferred in all
+# the leading newspaper websites and in many government departments,
+# it has a stronger case than omitting the leading "A".  The current
+# version of the database therefore uses abbreviations like "AEST" and
+# "AEDT" for Australian time zones.
 
 # From Paul Eggert (1995-12-19):
 # Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
 # Mark Prior writes that his newspaper
 # reports that NSW's fall 1995 change will occur at 2:00,
 # but Robert Elz says it's been 3:00 in Victoria since 1970
-# and perhaps the newspaper's `2:00' is referring to standard time.
+# and perhaps the newspaper's '2:00' is referring to standard time.
 # For now we'll continue to assume 2:00s for changes since 1960.
 
 # From Eric Ulevik (1998-01-05):
@@ -1055,17 +999,14 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # relevant entries in this database.
 #
 # NSW (including LHI and Broken Hill):
-# 
 # Standard Time Act 1987 (updated 1995-04-04)
-# 
+# http://www.austlii.edu.au/au/legis/nsw/consol_act/sta1987137/index.html
 # ACT
-# 
 # Standard Time and Summer Time Act 1972
-# 
+# http://www.austlii.edu.au/au/legis/act/consol_act/stasta1972279/index.html
 # SA
-# 
 # Standard Time Act, 1898
-# 
+# http://www.austlii.edu.au/au/legis/sa/consol_act/sta1898137/index.html
 
 # From David Grosz (2005-06-13):
 # It was announced last week that Daylight Saving would be extended by
@@ -1083,7 +1024,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # Victoria: I wasn't able to find anything separate, but the other articles
 # allude to it.
 # But not Queensland
-# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
+# http://www.news.com.au/story/0,10117,15564030-1248,00.html
 
 # Northern Territory
 
@@ -1130,9 +1071,9 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # The 1992 ending date used in the rules is a best guess;
 # it matches what was used in the past.
 
-# 
 # The Australian Bureau of Meteorology FAQ
-#  (1999-09-27) writes that Giles Meteorological Station uses
+# http://www.bom.gov.au/faq/faqgen.htm
+# (1999-09-27) writes that Giles Meteorological Station uses
 # South Australian time even though it's located in Western Australia.
 
 # Queensland
@@ -1173,9 +1114,9 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
 
 # From Christopher Hunt (2006-11-21), after an advance warning
-# from Jesper Norgaard Welen (2006-11-01):
+# from Jesper Nørgaard Welen (2006-11-01):
 # WA are trialing DST for three years.
-# 
+# http://www.parliament.wa.gov.au/parliament/bills.nsf/9A1B183144403DA54825721200088DF1/$File/Bill175-1B.pdf
 
 # From Rives McDow (2002-04-09):
 # The most interesting region I have found consists of three towns on the
@@ -1189,7 +1130,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # From Paul Eggert (2002-04-09):
 # This is confirmed by the section entitled
 # "What's the deal with time zones???" in
-# .
+# http://www.earthsci.unimelb.edu.au/~awatkins/null.html
 #
 # From Alex Livingston (2006-12-07):
 # ... it was just on four years ago that I drove along the Eyre Highway,
@@ -1337,7 +1278,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # Based on law library research by John Mackin,
 # who notes:
 #	In Australia, time is not legislated federally, but rather by the
-#	individual states.  Thus, while such terms as ``Eastern Standard Time''
+#	individual states.  Thus, while such terms as "Eastern Standard Time"
 #	[I mean, of course, Australian EST, not any other kind] are in common
 #	use, _they have NO REAL MEANING_, as they are not defined in the
 #	legislation.  This is very important to understand.
@@ -1345,48 +1286,42 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 
 # From Eric Ulevik (1999-05-26):
 # DST will start in NSW on the last Sunday of August, rather than the usual
-# October in 2000.  [See: Matthew Moore,
-# 
-# Two months more daylight saving
-# 
-# Sydney Morning Herald (1999-05-26).]
+# October in 2000.  See: Matthew Moore,
+# Two months more daylight saving, Sydney Morning Herald (1999-05-26).
+# http://www.smh.com.au/news/9905/26/pageone/pageone4.html
 
 # From Paul Eggert (1999-09-27):
 # See the following official NSW source:
-# 
 # Daylight Saving in New South Wales.
-# 
+# http://dir.gis.nsw.gov.au/cgi-bin/genobject/document/other/daylightsaving/tigGmZ
 #
 # Narrabri Shire (NSW) council has announced it will ignore the extension of
 # daylight saving next year.  See:
-# 
 # Narrabri Council to ignore daylight saving
-#  (1999-07-22).  For now, we'll wait to see if this really happens.
+# http://abc.net.au/news/regionals/neweng/monthly/regeng-22jul1999-1.htm
+# (1999-07-22).  For now, we'll wait to see if this really happens.
 #
 # Victoria will following NSW.  See:
-# 
-# Vic to extend daylight saving
-#  (1999-07-28).
+# Vic to extend daylight saving (1999-07-28)
+# http://abc.net.au/local/news/olympics/1999/07/item19990728112314_1.htm
 #
 # However, South Australia rejected the DST request.  See:
-# 
-# South Australia rejects Olympics daylight savings request
-#  (1999-07-19).
+# South Australia rejects Olympics daylight savings request (1999-07-19)
+# http://abc.net.au/news/olympics/1999/07/item19990719151754_1.htm
 #
 # Queensland also will not observe DST for the Olympics.  See:
-# 
 # Qld says no to daylight savings for Olympics
-#  (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
-# ``Look you've got to remember in my family when this came up last time
+# http://abc.net.au/news/olympics/1999/06/item19990601114608_1.htm
+# (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
+# "Look you've got to remember in my family when this came up last time
 # I voted for it, my wife voted against it and she said to me it's all very
 # well for you, you don't have to worry about getting the children out of
 # bed, getting them to school, getting them to sleep at night.
-# I've been through all this argument domestically...my wife rules.''
+# I've been through all this argument domestically...my wife rules."
 #
 # Broken Hill will stick with South Australian time in 2000.  See:
-# 
-# Broken Hill to be behind the times
-#  (1999-07-21).
+# Broken Hill to be behind the times (1999-07-21)
+# http://abc.net.au/news/regionals/brokenh/monthly/regbrok-21jul1999-6.htm
 
 # IATA SSIM (1998-09) says that the spring 2000 change for Australian
 # Capital Territory, New South Wales except Lord Howe Island and Broken
@@ -1402,7 +1337,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # Yancowinna
 
 # From John Mackin (1989-01-04):
-# `Broken Hill' means the County of Yancowinna.
+# 'Broken Hill' means the County of Yancowinna.
 
 # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
 # # YANCOWINNA..  [ Confirmation courtesy of Broken Hill Postmaster ]
@@ -1459,9 +1394,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # summer (southern hemisphere).
 #
 # From
-# 
 # http://www.safework.sa.gov.au/uploaded_files/DaylightDatesSet.pdf
-# 
 # The extended daylight saving period that South Australia has been trialling
 # for over the last year is now set to be ongoing.
 # Daylight saving will continue to start on the first Sunday in October each
@@ -1471,9 +1404,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # the ACT for all 52 weeks of the year...
 #
 # We have a wrap-up here:
-# 
 # http://www.timeanddate.com/news/time/south-australia-extends-dst.html
-# 
 ###############################################################################
 
 # New Zealand
@@ -1482,7 +1413,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # the 1989/90 year was a trial of an extended "daylight saving" period.
 # This trial was deemed successful and the extended period adopted for
 # subsequent years (with the addition of a further week at the start).
-# source -- phone call to Ministry of Internal Affairs Head Office.
+# source - phone call to Ministry of Internal Affairs Head Office.
 
 # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
 # # The Country of New Zealand   (Australia's east island -) Gee they hate that!
@@ -1524,6 +1455,19 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # that DST will begin on 2007-09-30 2008-04-06.
 # http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
 
+# From Paul Eggert (2014-07-14):
+# Chatham Island time was formally standardized on 1957-01-01 by
+# New Zealand's Standard Time Amendment Act 1956 (1956-10-26).
+# http://www.austlii.edu.au/nz/legis/hist_act/staa19561956n100244.pdf
+# According to Google Books snippet view, a speaker in the New Zealand
+# parliamentary debates in 1956 said "Clause 78 makes provision for standard
+# time in the Chatham Islands.  The time there is 45 minutes in advance of New
+# 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
+# not observe New Zealand's prewar DST.
+
 ###############################################################################
 
 
@@ -1543,7 +1487,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 
 # From the BBC World Service in
 # http://news.bbc.co.uk/2/hi/asia-pacific/205226.stm (1998-10-31 16:03 UTC):
-# The Fijiian government says the main reasons for the time change is to
+# The Fijian government says the main reasons for the time change is to
 # improve productivity and reduce road accidents.... [T]he move is also
 # intended to boost Fiji's ability to attract tourists to witness the dawning
 # of the new millennium.
@@ -1551,16 +1495,12 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
 # reports that Fiji has discontinued DST.
 
-# Johnston
-
-# Johnston data is from usno1995.
-
 
 # Kiribati
 
 # From Paul Eggert (1996-01-22):
 # Today's _Wall Street Journal_ (page 1) reports that Kiribati
-# ``declared it the same day [throughout] the country as of Jan. 1, 1995''
+# "declared it the same day [throughout] the country as of Jan. 1, 1995"
 # as part of the competition to be first into the 21st century.
 
 
@@ -1575,8 +1515,8 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 
 # N Mariana Is, Guam
 
-# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
-# Philippines and the Ladrones from America,'' and implies that the Ladrones
+# Howse writes (p 153) "The Spaniards, on the other hand, reached the
+# Philippines and the Ladrones from America," and implies that the Ladrones
 # (now called the Marianas) kept American date for quite some time.
 # For now, we assume the Ladrones switched at the same time as the Philippines;
 # see Asia/Manila.
@@ -1590,17 +1530,16 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # Micronesia
 
 # Alan Eugene Davis writes (1996-03-16),
-# ``I am certain, having lived there for the past decade, that "Truk"
-# (now properly known as Chuuk) ... is in the time zone GMT+10.''
+# "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
 # 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)
+# 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.
 
@@ -1646,27 +1585,34 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # Sacramento but it was changed a couple of years ago.
 
 
-# Samoa
+# (Western) Samoa and American Samoa
 
 # Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
 # that in 1879 the King of Samoa decided to change
-# ``the date in his kingdom from the Antipodean to the American system,
-# ordaining -- by a masterpiece of diplomatic flattery -- that
-# the Fourth of July should be celebrated twice in that year.''
+# "the date in his kingdom from the Antipodean to the American system,
+# 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
+# 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,
+# 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.
 
 # Tonga
 
 # From Paul Eggert (1996-01-22):
-# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
-# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
+# Today's _Wall Street Journal_ (p 1) reports that "Tonga has been plotting
+# to sneak ahead of [New Zealanders] by introducing daylight-saving time."
 # Since Kiribati has moved the Date Line it's not clear what Tonga will do.
 
 # Don Mundell writes in the 1997-02-20 Tonga Chronicle
-# 
-# How Tonga became `The Land where Time Begins'
-# :
-
+# How Tonga became 'The Land where Time Begins':
+# http://www.tongatapu.net.to/tonga/homeland/timebegins.htm
+#
 # Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
 # 12 hours and 20 minutes ahead of GMT.  When New Zealand adjusted its
 # standard time in 1940s, Tonga had the choice of subtracting from its
@@ -1674,8 +1620,8 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # advancing its time to maintain the differential of 13 degrees
 # (approximately 50 minutes ahead of New Zealand time).
 #
-# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
-# Tungi, preferred to ensure Tonga's title as the land where time
+# Because His Majesty King Tāufaʻāhau Tupou IV, then Crown Prince
+# Tungī, preferred to ensure Tonga's title as the land where time
 # begins, the Legislative Assembly approved the latter change.
 #
 # But some of the older, more conservative members from the outer
@@ -1701,9 +1647,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # * Tonga will introduce DST in November
 #
 # I was given this link by John Letts:
-# 
 # http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
-# 
 #
 # I have not been able to find exact dates for the transition in November
 # yet. By reading this article it seems like Fiji will be 14 hours ahead
@@ -1711,9 +1655,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # (12 + 1 hour DST).
 
 # From Arthur David Olson (1999-09-20):
-# According to 
-# http://www.tongaonline.com/news/sept1799.html
-# :
+# According to :
 # "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
 # and annually thereafter from the first Saturday in October through the
 # third Saturday of April.  Under the system approved by Privy Council on
@@ -1731,7 +1673,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # instead of the original reported date April 16. Unfortunately, the article
 # is no longer available on the site, and I did not make a copy of the
 # text, and I have forgotten to report it here.
-# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
+# (Original URL was )
 
 # From Rives McDow (2000-12-01):
 # Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
@@ -1751,7 +1693,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # From Vernice Anderson, Personal Secretary to Philip Jessup,
 # US Ambassador At Large (oral history interview, 1971-02-02):
 #
-# Saturday, the 14th [of October, 1950] -- ...  The time was all the
+# Saturday, the 14th [of October, 1950] - ...  The time was all the
 # more confusing at that point, because we had crossed the
 # International Date Line, thus getting two Sundays.  Furthermore, we
 # discovered that Wake Island had two hours of daylight saving time
@@ -1796,7 +1738,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # on the high seas.  Whenever a ship was within the territorial waters of any
 # nation it would use that nation's standard time.  The captain was permitted
 # to change his ship's clocks at a time of his choice following his ship's
-# entry into another zone time--he often chose midnight.  These zones were
+# entry into another zone time - he often chose midnight.  These zones were
 # adopted by all major fleets between 1920 and 1925 but not by many
 # independent merchant ships until World War II.
 
@@ -1804,6 +1746,6 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
 # (2005-03-20):
 #
 # The American Practical Navigator (2002)
-# 
+# http://pollux.nss.nima.mil/pubs/pubs_j_apn_sections.html?rid=187
 # talks only about the 180-degree meridian with respect to ships in
 # international waters; it ignores the international date line.
diff --git a/jdk/make/data/tzdata/backward b/jdk/make/data/tzdata/backward
index 5afe9a317ff..ba012f45733 100644
--- a/jdk/make/data/tzdata/backward
+++ b/jdk/make/data/tzdata/backward
@@ -21,15 +21,15 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
 # This file provides links between current names for time zones
 # and their old names.  Many names changed in late 1993.
 
+# Link	TARGET			LINK-NAME
 Link	Africa/Asmara		Africa/Asmera
-Link	Africa/Bamako		Africa/Timbuktu
+Link	Africa/Abidjan		Africa/Timbuktu
 Link	America/Argentina/Catamarca	America/Argentina/ComodRivadavia
 Link	America/Adak		America/Atka
 Link	America/Argentina/Buenos_Aires	America/Buenos_Aires
@@ -50,8 +50,11 @@ Link	America/Port_of_Spain	America/Virgin
 Link	Pacific/Auckland	Antarctica/South_Pole
 Link	Asia/Ashgabat		Asia/Ashkhabad
 Link	Asia/Kolkata		Asia/Calcutta
-Link	Asia/Chongqing		Asia/Chungking
+Link	Asia/Shanghai		Asia/Chongqing
+Link	Asia/Shanghai		Asia/Chungking
 Link	Asia/Dhaka		Asia/Dacca
+Link	Asia/Shanghai		Asia/Harbin
+Link	Asia/Urumqi		Asia/Kashgar
 Link	Asia/Kathmandu		Asia/Katmandu
 Link	Asia/Macau		Asia/Macao
 Link	Asia/Ho_Chi_Minh	Asia/Saigon
diff --git a/jdk/make/data/tzdata/etcetera b/jdk/make/data/tzdata/etcetera
index ebaa5fdfc04..d2fb91c9dd6 100644
--- a/jdk/make/data/tzdata/etcetera
+++ b/jdk/make/data/tzdata/etcetera
@@ -21,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -37,7 +36,7 @@ Zone	Etc/UTC		0	-	UTC
 Zone	Etc/UCT		0	-	UCT
 
 # The following link uses older naming conventions,
-# but it belongs here, not in the file `backward',
+# but it belongs here, not in the file 'backward',
 # as functions like gmtime load the "GMT" file to handle leap seconds properly.
 # We want this to work even on installations that omit the other older names.
 Link	Etc/GMT				GMT
diff --git a/jdk/make/data/tzdata/europe b/jdk/make/data/tzdata/europe
index 226c393a0f2..0c5f5667da9 100644
--- a/jdk/make/data/tzdata/europe
+++ b/jdk/make/data/tzdata/europe
@@ -21,15 +21,15 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
-# From Paul Eggert (2006-03-22):
+# From Paul Eggert (2014-05-31):
 # A good source for time zone historical data outside the U.S. is
 # Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
 # San Diego: ACS Publications, Inc. (2003).
@@ -40,6 +40,9 @@
 # published semiannually.  Law sent in several helpful summaries
 # of the IATA's data after 1990.
 #
+# A reliable and entertaining source about time zones is
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+#
 # Except where otherwise noted, Shanks & Pottenger is the source for
 # entries through 1991, and IATA SSIM is the source for entries afterwards.
 #
@@ -49,9 +52,9 @@
 #	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
 #	which I found in the UCLA library.
 #
-#	
 #	William Willett, The Waste of Daylight, 19th edition
-#	 (1914-03)
+#	
+#	[PDF] (1914-03)
 #
 #	Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
 #	.  He writes:
@@ -59,10 +62,20 @@
 #	may be sent to Mr. John Milne, Royal Geographical Society,
 #	Savile Row, London."  Nowadays please email them to tz@iana.org.
 #
-#	Brazil's Departamento Servico da Hora (DSH),
-#	
+#	Byalokoz EL. New Counting of Time in Russia since July 1, 1919.
+#	This Russian-language source was consulted by Vladimir Karpinsky; see
+#	http://mm.icann.org/pipermail/tz/2014-August/021320.html
+#	The full Russian citation is:
+#	Бялокоз, Евгений Людвигович. Новый счет времени в течении суток
+#	введенный декретом Совета народных комиссаров для всей России с 1-го
+#	июля 1919 г. / Изд. 2-е Междуведомственной комиссии. - Петроград:
+#	Десятая гос. тип., 1919.
+#	http://resolver.gpntb.ru/purl?docushare/dsweb/Get/Resource-2011/Byalokoz__E.L.__Novyy__schet__vremeni__v__techenie__sutok__izd__2(1).pdf
+#
+#	Brazil's Divisão Serviço da Hora (DSHO),
 #	History of Summer Time
-#	 (1998-09-21, in Portuguese)
+#	
+#	(1998-09-21, in Portuguese)
 
 #
 # I invented the abbreviations marked '*' in the following table;
@@ -81,10 +94,8 @@
 #        1:00       CET CEST CEMT Central Europe
 #        1:00:14    SET           Swedish (1879-1899)*
 #        2:00       EET EEST      Eastern Europe
-#        3:00       MSK MSD       Moscow
-#
-# A reliable and entertaining source about time zones, especially in Britain,
-# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+#        3:00       FET           Further-eastern Europe*
+#        3:00       MSK MSD  MSM* Moscow
 
 # From Peter Ilieve (1994-12-04),
 # The original six [EU members]: Belgium, France, (West) Germany, Italy,
@@ -128,7 +139,7 @@
 # along the towpath within a few yards of it.'
 #
 # I have a one inch to one mile map of London and my estimate of the stone's
-# position is 51 deg. 28' 30" N, 0 deg. 18' 45" W. The longitude should
+# position is 51 degrees 28' 30" N, 0 degrees 18' 45" W. The longitude should
 # be within about +-2". The Ordnance Survey grid reference is TQ172761.
 #
 # [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
@@ -160,8 +171,22 @@
 # transition date for London, namely 1847-12-01.  We don't know as much
 # about Dublin, so we use 1880-08-02, the legal transition time.
 
-# From Paul Eggert (2003-09-27):
-# Summer Time was first seriously proposed by William Willett (1857-1915),
+# From Paul Eggert (2014-07-19):
+# The ancients had no need for daylight saving, as they kept time
+# informally or via hours whose length depended on the time of year.
+# Daylight saving time in its modern sense was invented by the
+# New Zealand entomologist George Vernon Hudson (1867-1946),
+# whose day job as a postal clerk led him to value
+# after-hours daylight in which to pursue his research.
+# In 1895 he presented a paper to the Wellington Philosophical Society
+# that proposed a two-hour daylight-saving shift.  See:
+# Hudson GV. On seasonal time-adjustment in countries south of lat. 30 deg.
+# Transactions and Proceedings of the New Zealand Institute. 1895;28:734
+# http://rsnz.natlib.govt.nz/volume/rsnz_28/rsnz_28_00_006110.html
+# Although some interest was expressed in New Zealand, his proposal
+# did not find its way into law and eventually it was almost forgotten.
+#
+# In England, DST was independently reinvented by William Willett (1857-1915),
 # a London builder and member of the Royal Astronomical Society
 # who circulated a pamphlet "The Waste of Daylight" (1907)
 # that proposed advancing clocks 20 minutes on each of four Sundays in April,
@@ -174,7 +199,7 @@
 # A monument to Willett was unveiled on 1927-05-21, in an open space in
 # a 45-acre wood near Chislehurst, Kent that was purchased by popular
 # subscription and open to the public.  On the south face of the monolith,
-# designed by G. W. Miller, is the...William Willett Memorial Sundial,
+# designed by G. W. Miller, is the William Willett Memorial Sundial,
 # which is permanently set to Summer Time.
 
 # From Winston Churchill (1934-04-28):
@@ -183,9 +208,9 @@
 # between 160 and 170 hours more daylight leisure, to a war which
 # plunged Europe into darkness for four years, and shook the
 # foundations of civilization throughout the world.
-#	-- 
-#	"A Silent Toast to William Willett", Pictorial Weekly
-#	
+#	-- "A Silent Toast to William Willett", Pictorial Weekly;
+#	republished in Finest Hour (Spring 2002) 1(114):26
+#	http://www.winstonchurchill.org/images/finesthour/Vol.01%20No.114.pdf
 
 # From Paul Eggert (1996-09-03):
 # The OED Supplement says that the English originally said "Daylight Saving"
@@ -194,7 +219,6 @@
 # proponents (who eventually won the argument) are quoted as using "Summer".
 
 # From Arthur David Olson (1989-01-19):
-#
 # A source at the British Information Office in New York avers that it's
 # known as "British" Summer Time in all parts of the United Kingdom.
 
@@ -221,8 +245,8 @@
 # official designation; the reply of the 21st was that there wasn't
 # but he couldn't think of anything better than the "Double British
 # Summer Time" that the BBC had been using informally.
-# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
-# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
+# http://www.polyomino.org.uk/british-time/bbc-19410418.png
+# http://www.polyomino.org.uk/british-time/ho-19410421.png
 
 # From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
 # [N]o official designation has as far as I know been adopted for the time
@@ -239,23 +263,14 @@
 # the history of summer time legislation in the United Kingdom.
 # Since 1998 Joseph S. Myers has been updating
 # and extending this list, which can be found in
-# http://student.cusu.cam.ac.uk/~jsm28/british-time/
-# 
-# History of legal time in Britain
-# 
-# Rob Crowther (2012-01-04) reports that that URL no longer
-# exists, and the article can now be found at:
-# 
 # http://www.polyomino.org.uk/british-time/
-# 
 
 # From Joseph S. Myers (1998-01-06):
 #
 # The legal time in the UK outside of summer time is definitely GMT, not UTC;
 # see Lord Tanlaw's speech
-# 
-# (Lords Hansard 11 June 1997 columns 964 to 976)
-# .
+# http://www.publications.parliament.uk/pa/ld199798/ldhansrd/vo970611/text/70611-10.htm#70611-10_head0
+# (Lords Hansard 11 June 1997 columns 964 to 976).
 
 # From Paul Eggert (2006-03-22):
 #
@@ -295,8 +310,8 @@
 #   -- James Joyce, Ulysses
 
 # From Joseph S. Myers (2005-01-26):
-# Irish laws are available online at www.irishstatutebook.ie.  These include
-# various relating to legal time, for example:
+# Irish laws are available online at .
+# These include various relating to legal time, for example:
 #
 # ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
 #
@@ -458,25 +473,27 @@ Rule	GB-Eire 1990	1995	-	Oct	Sun>=22	1:00u	0	GMT
 # Use Europe/London for Jersey, Guernsey, and the Isle of Man.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
+Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1  0:00s
 			 0:00	GB-Eire	%s	1968 Oct 27
-			 1:00	-	BST	1971 Oct 31 2:00u
+			 1:00	-	BST	1971 Oct 31  2:00u
 			 0:00	GB-Eire	%s	1996
 			 0:00	EU	GMT/BST
 Link	Europe/London	Europe/Jersey
 Link	Europe/London	Europe/Guernsey
 Link	Europe/London	Europe/Isle_of_Man
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
-			-0:25:21 -	DMT	1916 May 21 2:00
-			-0:25:21 1:00	IST	1916 Oct  1 2:00s
+			-0:25:21 -	DMT	1916 May 21  2:00
+			-0:25:21 1:00	IST	1916 Oct  1  2:00s
 			 0:00	GB-Eire	%s	1921 Dec  6 # independence
-			 0:00	GB-Eire	GMT/IST	1940 Feb 25 2:00
-			 0:00	1:00	IST	1946 Oct  6 2:00
-			 0:00	-	GMT	1947 Mar 16 2:00
-			 0:00	1:00	IST	1947 Nov  2 2:00
-			 0:00	-	GMT	1948 Apr 18 2:00
+			 0:00	GB-Eire	GMT/IST	1940 Feb 25  2:00
+			 0:00	1:00	IST	1946 Oct  6  2:00
+			 0:00	-	GMT	1947 Mar 16  2:00
+			 0:00	1:00	IST	1947 Nov  2  2:00
+			 0:00	-	GMT	1948 Apr 18  2:00
 			 0:00	GB-Eire	GMT/IST	1968 Oct 27
-			 1:00	-	IST	1971 Oct 31 2:00u
+			 1:00	-	IST	1971 Oct 31  2:00u
 			 0:00	GB-Eire	GMT/IST	1996
 			 0:00	EU	GMT/IST
 
@@ -495,10 +512,9 @@ Rule	EU	1979	1995	-	Sep	lastSun	 1:00u	0	-
 Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
 Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
 # The most recent directive covers the years starting in 2002.  See:
-# 
 # Directive 2000/84/EC of the European Parliament and of the Council
 # of 19 January 2001 on summer-time arrangements.
-# 
+# http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=CELEX:32000L0084:EN:NOT
 
 # W-Eur differs from EU only in that W-Eur uses standard time.
 Rule	W-Eur	1977	1980	-	Apr	Sun>=1	 1:00s	1:00	S
@@ -521,18 +537,18 @@ Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
 Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
 # Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
 Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
-# From Jesper Norgaard Welen (2008-07-13):
+# From Jesper Nørgaard Welen (2008-07-13):
 #
 # I found what is probably a typo of 2:00 which should perhaps be 2:00s
 # in the C-Eur rule from tz database version 2008d (this part was
-# corrected in version 2008d). The circumstancial evidence is simply the
+# corrected in version 2008d). The circumstantial evidence is simply the
 # tz database itself, as seen below:
 #
 # Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
 #    0:00 France WE%sT 1945 Sep 16  3:00
 #
 # Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
-#    0:00 France WE%sT 1945 Sep 16 3:00
+#    0:00 France WE%sT 1945 Sep 16  3:00
 #
 # Zone Europe/Belgrade 1:22:00 - LMT 1884
 #    1:00 1:00 CEST 1945 Sep 16  2:00s
@@ -576,16 +592,16 @@ Rule	E-Eur	1981	max	-	Mar	lastSun	 0:00	1:00	S
 Rule	E-Eur	1996	max	-	Oct	lastSun	 0:00	0	-
 
 # 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
-Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT	# Moscow Mean Time
-Rule	Russia	1918	only	-	May	31	22:00	2:00	MDST	# Moscow Double Summer Time
+Rule	Russia	1917	only	-	Jul	 1	23:00	1:00	MST  # Moscow Summer Time
+Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT  # Moscow Mean Time
+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
 Rule	Russia	1919	only	-	May	31	23:00	2:00	MDST
-Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	S
-Rule	Russia	1919	only	-	Aug	16	 0:00	0	-
-Rule	Russia	1921	only	-	Feb	14	23:00	1:00	S
-Rule	Russia	1921	only	-	Mar	20	23:00	2:00	M # Midsummer
-Rule	Russia	1921	only	-	Sep	 1	 0:00	1:00	S
+Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	MSD
+Rule	Russia	1919	only	-	Aug	16	 0:00	0	MSK
+Rule	Russia	1921	only	-	Feb	14	23:00	1:00	MSD
+Rule	Russia	1921	only	-	Mar	20	23:00	2:00	MSM  # Midsummer
+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):
 Rule	Russia	1981	1984	-	Apr	 1	 0:00	1:00	S
@@ -607,14 +623,10 @@ Rule	Russia	1996	2010	-	Oct	lastSun	 2:00s	0	-
 # According to the law Russia is abolishing daylight saving time.
 #
 # Medvedev signed a law "On the Calculation of Time" (in russian):
-# 
 # http://bmockbe.ru/events/?ID=7583
-# 
 #
 # Medvedev signed a law on the calculation of the time (in russian):
-# 
 # http://www.regnum.ru/news/polit/1413906.html
-# 
 
 # From Arthur David Olson (2011-06-15):
 # Take "abolishing daylight saving time" to mean that time is now considered
@@ -634,10 +646,10 @@ Zone	EET		2:00	EU	EE%sT
 # From Markus Kuhn (1996-07-12):
 # The official German names ... are
 #
-#	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
-#	Mitteleuropaeische Sommerzeit (MESZ)  = UTC+02:00
+#	Mitteleuropäische Zeit (MEZ)         = UTC+01:00
+#	Mitteleuropäische Sommerzeit (MESZ)  = UTC+02:00
 #
-# as defined in the German Time Act (Gesetz ueber die Zeitbestimmung (ZeitG),
+# as defined in the German Time Act (Gesetz über die Zeitbestimmung (ZeitG),
 # 1978-07-25, Bundesgesetzblatt, Jahrgang 1978, Teil I, S. 1110-1111)....
 # I wrote ... to the German Federal Physical-Technical Institution
 #
@@ -692,7 +704,7 @@ Zone	Europe/Tirane	1:19:20 -	LMT	1914
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Andorra	0:06:04 -	LMT	1901
 			0:00	-	WET	1946 Sep 30
-			1:00	-	CET	1985 Mar 31 2:00
+			1:00	-	CET	1985 Mar 31  2:00
 			1:00	EU	CE%sT
 
 # Austria
@@ -718,9 +730,9 @@ Rule	Austria	1980	only	-	Sep	28	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Vienna	1:05:21 -	LMT	1893 Apr
 			1:00	C-Eur	CE%sT	1920
-			1:00	Austria	CE%sT	1940 Apr  1 2:00s
-			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
-			1:00	1:00	CEST	1945 Apr 12 2:00s
+			1:00	Austria	CE%sT	1940 Apr  1  2:00s
+			1:00	C-Eur	CE%sT	1945 Apr  2  2:00s
+			1:00	1:00	CEST	1945 Apr 12  2:00s
 			1:00	-	CET	1946
 			1:00	Austria	CE%sT	1981
 			1:00	EU	CE%sT
@@ -731,38 +743,29 @@ Zone	Europe/Vienna	1:05:21 -	LMT	1893 Apr
 # GMT+3 without DST (was GMT+2 with DST).
 #
 # Sources (Russian language):
-# 1.
-# 
 # http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
-# 
-# 2.
-# 
 # http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
-# 
-# 3.
-# 
 # http://news.tut.by/society/250578.html
-# 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Minsk	1:50:16 -	LMT	1880
-			1:50	-	MMT	1924 May 2 # Minsk Mean Time
+			1:50	-	MMT	1924 May  2 # Minsk Mean Time
 			2:00	-	EET	1930 Jun 21
 			3:00	-	MSK	1941 Jun 28
 			1:00	C-Eur	CE%sT	1944 Jul  3
 			3:00	Russia	MSK/MSD	1990
-			3:00	-	MSK	1991 Mar 31 2:00s
-			2:00	1:00	EEST	1991 Sep 29 2:00s
-			2:00	-	EET	1992 Mar 29 0:00s
-			2:00	1:00	EEST	1992 Sep 27 0:00s
-			2:00	Russia	EE%sT	2011 Mar 27 2:00s
-			3:00	-	FET # Further-eastern European Time
+			3:00	-	MSK	1991 Mar 31  2:00s
+			2:00	1:00	EEST	1991 Sep 29  2:00s
+			2:00	-	EET	1992 Mar 29  0:00s
+			2:00	1:00	EEST	1992 Sep 27  0:00s
+			2:00	Russia	EE%sT	2011 Mar 27  2:00s
+			3:00	-	FET
 
 # Belgium
 #
 # From Paul Eggert (1997-07-02):
 # Entries from 1918 through 1991 are taken from:
 #	Annuaire de L'Observatoire Royal de Belgique,
-#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
+#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe année, 1991
 #	(Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
 #	pp 8-9.
 # LMT before 1892 was 0:17:30, according to the official journal of Belgium:
@@ -812,7 +815,7 @@ Rule	Belgium	1946	only	-	May	19	 2:00s	1:00	S
 Rule	Belgium	1946	only	-	Oct	 7	 2:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Brussels	0:17:30 -	LMT	1880
-			0:17:30	-	BMT	1892 May  1 12:00 # Brussels MT
+			0:17:30	-	BMT	1892 May  1 12:00  # Brussels MT
 			0:00	-	WET	1914 Nov  8
 			1:00	-	CET	1916 May  1  0:00
 			1:00	C-Eur	CE%sT	1918 Nov 11 11:00u
@@ -828,8 +831,8 @@ Zone	Europe/Brussels	0:17:30 -	LMT	1880
 #
 # From Plamen Simenov via Steffen Thorsen (1999-09-09):
 # A document of Government of Bulgaria (No.94/1997) says:
-# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
-# EETDST --> EET is in 04:00 Local time in last Sunday of October
+# EET -> EETDST is in 03:00 Local time in last Sunday of March ...
+# EETDST -> EET is in 04:00 Local time in last Sunday of October
 #
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
@@ -842,7 +845,7 @@ Zone	Europe/Sofia	1:33:16 -	LMT	1880
 			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
 			2:00	-	EET	1942 Nov  2  3:00
 			1:00	C-Eur	CE%sT	1945
-			1:00	-	CET	1945 Apr 2 3:00
+			1:00	-	CET	1945 Apr  2  3:00
 			2:00	-	EET	1979 Mar 31 23:00
 			2:00	Bulg	EE%sT	1982 Sep 26  2:00
 			2:00	C-Eur	EE%sT	1991
@@ -866,15 +869,15 @@ Rule	Czech	1948	only	-	Apr	18	2:00s	1:00	S
 Rule	Czech	1949	only	-	Apr	 9	2:00s	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Prague	0:57:44 -	LMT	1850
-			0:57:44	-	PMT	1891 Oct     # Prague Mean Time
-			1:00	C-Eur	CE%sT	1944 Sep 17 2:00s
+			0:57:44	-	PMT	1891 Oct    # Prague Mean Time
+			1:00	C-Eur	CE%sT	1944 Sep 17  2:00s
 			1:00	Czech	CE%sT	1979
 			1:00	EU	CE%sT
 # Use Europe/Prague also for Slovakia.
 
 # Denmark, Faroe Islands, and Greenland
 
-# From Jesper Norgaard Welen (2005-04-26):
+# From Jesper Nørgaard Welen (2005-04-26):
 # http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
 # [introducing standard time] was in effect from 1894-01-01....
 # The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
@@ -884,7 +887,7 @@ Zone	Europe/Prague	0:57:44 -	LMT	1850
 # http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
 #
 # This provoked a new law from 1974 to make possible summer time changes
-# in subsequenet decrees with the law
+# in subsequent decrees with the law
 # http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
 #
 # It seems however that no decree was set forward until 1980.  I have
@@ -899,7 +902,7 @@ Zone	Europe/Prague	0:57:44 -	LMT	1850
 # was suspended on that night):
 # http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
 
-# From Jesper Norgaard Welen (2005-06-11):
+# From Jesper Nørgaard Welen (2005-06-11):
 # The Herning Folkeblad (1980-09-26) reported that the night between
 # Saturday and Sunday the clock is set back from three to two.
 
@@ -923,11 +926,11 @@ Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
 			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
-			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
-			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
+			 1:00	Denmark	CE%sT	1942 Nov  2  2:00s
+			 1:00	C-Eur	CE%sT	1945 Apr  2  2:00
 			 1:00	Denmark	CE%sT	1980
 			 1:00	EU	CE%sT
-Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
+Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11 # Tórshavn
 			 0:00	-	WET	1981
 			 0:00	EU	WE%sT
 #
@@ -939,11 +942,11 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
 # From Paul Eggert (2006-03-22):
 # Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
 # and left the EU on 1985-02-01.  It therefore should have been using EU
-# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
+# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthåb
 # used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
 # rules since at least 1991.  Assume EU rules since 1980.
 
-# From Gwillin Law (2001-06-06), citing
+# From Gwillim Law (2001-06-06), citing
 #  (2001-03-15),
 # and with translations corrected by Steffen Thorsen:
 #
@@ -978,16 +981,16 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
 # DPC research station at Zackenberg.
 #
 # Scoresbysund and two small villages nearby keep time UTC-1 and use
-# the same daylight savings time period as in West Greenland (Godthab).
+# the same daylight savings time period as in West Greenland (Godthåb).
 #
-# The rest of Greenland, including Godthab (this area, although it
+# The rest of Greenland, including Godthåb (this area, although it
 # includes central Greenland, is known as west Greenland), keeps time
 # UTC-3, with daylight savings methods according to European rules.
 #
 # It is common procedure to use UTC 0 in the wilderness of East and
 # North Greenland, because it is mainly Icelandic aircraft operators
 # maintaining traffic in these areas.  However, the official status of
-# this area is that it sticks with Godthab time.  This area might be
+# this area is that it sticks with Godthåb time.  This area might be
 # considered a dual time zone in some respects because of this.
 
 # From Rives McDow (2001-11-19):
@@ -996,8 +999,8 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
 
 # From Paul Eggert (2006-03-22):
 # From 1997 on the CIA map shows Danmarkshavn on GMT;
-# the 1995 map as like Godthab.
-# For lack of better info, assume they were like Godthab before 1996.
+# the 1995 map as like Godthåb.
+# For lack of better info, assume they were like Godthåb before 1996.
 # startkart.no says Thule does not observe DST, but this is clearly an error,
 # so go with Shanks & Pottenger for Thule transitions until this year.
 # For 2007 on assume Thule will stay in sync with US DST rules.
@@ -1012,15 +1015,15 @@ Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
 #
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
-			-3:00	-	WGT	1980 Apr  6 2:00
+			-3:00	-	WGT	1980 Apr  6  2:00
 			-3:00	EU	WG%sT	1996
 			0:00	-	GMT
 Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
-			-2:00	-	CGT	1980 Apr  6 2:00
+			-2:00	-	CGT	1980 Apr  6  2:00
 			-2:00	C-Eur	CG%sT	1981 Mar 29
 			-1:00	EU	EG%sT
 Zone America/Godthab	-3:26:56 -	LMT	1916 Jul 28 # Nuuk
-			-3:00	-	WGT	1980 Apr  6 2:00
+			-3:00	-	WGT	1980 Apr  6  2:00
 			-3:00	EU	WG%sT
 Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
 			-4:00	Thule	A%sT
@@ -1042,17 +1045,16 @@ Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
 # summer time next spring."
 
 # From Peter Ilieve (1998-11-04), heavily edited:
-# 
 # The 1998-09-22 Estonian time law
-# 
+# http://trip.rk.ee/cgi-bin/thw?${BASE}=akt&${OOHTML}=rtd&TA=1998&TO=1&AN=1390
 # refers to the Eighth Directive and cites the association agreement between
-# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
+# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22-27, 120).
 #
 # I also asked [my relative] whether they use any standard abbreviation
 # for their standard and summer times. He says no, they use "suveaeg"
 # (summer time) and "talveaeg" (winter time).
 
-# From The Baltic Times (1999-09-09)
+# From The Baltic Times  (1999-09-09)
 # via Steffen Thorsen:
 # This year will mark the last time Estonia shifts to summer time,
 # a council of the ruling coalition announced Sept. 6....
@@ -1070,19 +1072,19 @@ Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
 # The Estonian government has changed once again timezone politics.
 # Now we are using again EU rules.
 #
-# From Urmet Jaanes (2002-03-28):
+# From Urmet Jänes (2002-03-28):
 # The legislative reference is Government decree No. 84 on 2002-02-21.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Tallinn	1:39:00	-	LMT	1880
-			1:39:00	-	TMT	1918 Feb # Tallinn Mean Time
+			1:39:00	-	TMT	1918 Feb    # Tallinn Mean Time
 			1:00	C-Eur	CE%sT	1919 Jul
 			1:39:00	-	TMT	1921 May
 			2:00	-	EET	1940 Aug  6
 			3:00	-	MSK	1941 Sep 15
 			1:00	C-Eur	CE%sT	1944 Sep 22
-			3:00	Russia	MSK/MSD	1989 Mar 26 2:00s
-			2:00	1:00	EEST	1989 Sep 24 2:00s
+			3:00	Russia	MSK/MSD	1989 Mar 26  2:00s
+			2:00	1:00	EEST	1989 Sep 24  2:00s
 			2:00	C-Eur	EE%sT	1998 Sep 22
 			2:00	EU	EE%sT	1999 Nov  1
 			2:00	-	EET	2002 Feb 21
@@ -1104,35 +1106,45 @@ Zone	Europe/Tallinn	1:39:00	-	LMT	1880
 # This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
 # Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
 # Finnish) at
-#
-# 
 # http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
-# 
 #
 # Page 105 (56 in PDF version) has a handy table of all past daylight savings
 # transitions. It is easy enough to interpret without Finnish skills.
 #
 # This is also confirmed by Finnish Broadcasting Company's archive at:
-#
-# 
 # http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
-# 
 #
 # The news clip from 1981 says that "the time between 2 and 3 o'clock does not
 # exist tonight."
 
+# From Konstantin Hyppönen (2014-06-13):
+# [Heikki Oja's book Aikakirja 2013]
+# http://almanakka.helsinki.fi/images/aikakirja/Aikakirja2013kokonaan.pdf
+# pages 104-105, including a scan from a newspaper published on Apr 2 1942
+# say that ... [o]n Apr 2 1942, 24 o'clock (which means Apr 3 1942,
+# 00:00), clocks were moved one hour forward. The newspaper
+# mentions "on the night from Thursday to Friday"....
+# On Oct 4 1942, clocks were moved at 1:00 one hour backwards.
+#
+# From Paul Eggert (2014-06-14):
+# Go with Oja over Shanks.
+
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
-Rule	Finland	1942	only	-	Oct	3	0:00	0	-
+Rule	Finland	1942	only	-	Apr	2	24:00	1:00	S
+Rule	Finland	1942	only	-	Oct	4	1:00	0	-
 Rule	Finland	1981	1982	-	Mar	lastSun	2:00	1:00	S
 Rule	Finland	1981	1982	-	Sep	lastSun	3:00	0	-
+
+# Milne says Helsinki (Helsingfors) time was 1:39:49.2 (official document);
+# round to nearest.
+
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
-			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
+Zone	Europe/Helsinki	1:39:49 -	LMT	1878 May 31
+			1:39:49	-	HMT	1921 May    # Helsinki Mean Time
 			2:00	Finland	EE%sT	1983
 			2:00	EU	EE%sT
 
-# Aaland Is
+# Åland Is
 Link	Europe/Helsinki	Europe/Mariehamn
 
 
@@ -1140,14 +1152,14 @@ Link	Europe/Helsinki	Europe/Mariehamn
 
 # From Ciro Discepolo (2000-12-20):
 #
-# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
+# Henri Le Corre, Régimes horaires pour le monde entier, Éditions
 # Traditionnelles - Paris 2 books, 1993
 #
-# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
+# Gabriel, Traité de l'heure dans le monde, Guy Trédaniel,
 # Paris, 1991
 #
-# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
-# Guy tredaniel, Paris 1987
+# Françoise Gauquelin, Problèmes de l'heure résolus en astrologie,
+# Guy Trédaniel, Paris 1987
 
 
 #
@@ -1188,16 +1200,16 @@ Rule	France	1939	only	-	Nov	18	23:00s	0	-
 Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
 # The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
 # write that they were used in Monaco and in many French locations.
-# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
-# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
-# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
+# Le Corre writes that the upper limit of the free zone was Arnéguy, Orthez,
+# Mont-de-Marsan, Bazas, Langon, Lamothe-Montravel, Marœuil, La
+# Rochefoucauld, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
 # Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
-# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
+# Paray-le-Monial, Montceau-les-Mines, Chalon-sur-Saône, Arbois,
 # Dole, Morez, St-Claude, and Collonges (Haute-Savoie).
 Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
 # Shanks & Pottenger say this transition occurred at Oct 6 1:00,
 # but go with Denis Excoffier (1997-12-12),
-# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
+# who quotes the Ephémérides astronomiques for 1998 from Bureau des Longitudes
 # as saying 5/10/41 22hUT.
 Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
 Rule	France	1942	only	-	Mar	 9	 0:00	2:00	M
@@ -1218,7 +1230,7 @@ Rule	France	1976	only	-	Sep	26	 1:00	0	-
 # on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
-			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
+			0:09:21	-	PMT	1911 Mar 11  0:01 # Paris MT
 # Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
 			0:00	France	WE%sT	1940 Jun 14 23:00
 # Le Corre says Paris stuck with occupied-France time after the liberation;
@@ -1235,15 +1247,13 @@ Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
 # Bundesanstalt contains DST information back to 1916.
 # [See tz-link.htm for the URL.]
 
-# From Joerg Schilling (2002-10-23):
+# From Jörg Schilling (2002-10-23):
 # In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
-# 
-# General [Nikolai] Bersarin.
+# http://www.dhm.de/lemo/html/biografien/BersarinNikolai/
+# General [Nikolai] Bersarin.
 
 # From Paul Eggert (2003-03-08):
-# 
 # 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.
@@ -1268,23 +1278,23 @@ Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
-			1:00	C-Eur	CE%sT	1945 May 24 2:00
+			1:00	C-Eur	CE%sT	1945 May 24  2:00
 			1:00 SovietZone	CE%sT	1946
 			1:00	Germany	CE%sT	1980
 			1:00	EU	CE%sT
 
 # From Tobias Conradi (2011-09-12):
-# Busingen , surrounded by the Swiss canton
+# Büsingen , surrounded by the Swiss canton
 # Schaffhausen, did not start observing DST in 1980 as the rest of DE
 # (West Germany at that time) and DD (East Germany at that time) did.
 # DD merged into DE, the area is currently covered by code DE in ISO 3166-1,
 # which in turn is covered by the zone Europe/Berlin.
 #
-# Source for the time in Busingen 1980:
+# Source for the time in Büsingen 1980:
 # http://www.srf.ch/player/video?id=c012c029-03b7-4c2b-9164-aa5902cd58d3
 
 # From Arthur David Olson (2012-03-03):
-# Busingen and Zurich have shared clocks since 1970.
+# Büsingen and Zurich have shared clocks since 1970.
 
 Link	Europe/Zurich	Europe/Busingen
 
@@ -1295,8 +1305,8 @@ Link	Europe/Zurich	Europe/Busingen
 
 # Gibraltar
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
-			0:00	GB-Eire	%s	1957 Apr 14 2:00
+Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2  0:00s
+			0:00	GB-Eire	%s	1957 Apr 14  2:00
 			1:00	-	CET	1982
 			1:00	EU	CE%sT
 
@@ -1327,7 +1337,7 @@ Rule	Greece	1980	only	-	Apr	 1	0:00	1:00	S
 Rule	Greece	1980	only	-	Sep	28	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
-			1:34:52	-	AMT	1916 Jul 28 0:01     # Athens MT
+			1:34:52	-	AMT	1916 Jul 28  0:01 # Athens MT
 			2:00	Greece	EE%sT	1941 Apr 30
 			1:00	Greece	CE%sT	1944 Apr  4
 			2:00	Greece	EE%sT	1981
@@ -1336,15 +1346,20 @@ Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
 			2:00	EU	EE%sT
 
 # Hungary
+# From Paul Eggert (2014-07-15):
+# Dates for 1916-1945 are taken from:
+# Oross A. Jelen a múlt jövője: a nyári időszámítás Magyarországon 1916-1945.
+# National Archives of Hungary (2012-10-29).
+# http://mnl.gov.hu/a_het_dokumentuma/a_nyari_idoszamitas_magyarorszagon_19161945.html
+# This source does not always give times, which are taken from Shanks
+# & Pottenger (which disagree about the dates).
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Hungary	1918	only	-	Apr	 1	 3:00	1:00	S
-Rule	Hungary	1918	only	-	Sep	29	 3:00	0	-
+Rule	Hungary	1918	only	-	Sep	16	 3:00	0	-
 Rule	Hungary	1919	only	-	Apr	15	 3:00	1:00	S
-Rule	Hungary	1919	only	-	Sep	15	 3:00	0	-
-Rule	Hungary	1920	only	-	Apr	 5	 3:00	1:00	S
-Rule	Hungary	1920	only	-	Sep	30	 3:00	0	-
+Rule	Hungary	1919	only	-	Nov	24	 3:00	0	-
 Rule	Hungary	1945	only	-	May	 1	23:00	1:00	S
-Rule	Hungary	1945	only	-	Nov	 3	 0:00	0	-
+Rule	Hungary	1945	only	-	Nov	 1	 0:00	0	-
 Rule	Hungary	1946	only	-	Mar	31	 2:00s	1:00	S
 Rule	Hungary	1946	1949	-	Oct	Sun>=1	 2:00s	0	-
 Rule	Hungary	1947	1949	-	Apr	Sun>=4	 2:00s	1:00	S
@@ -1360,7 +1375,7 @@ Rule	Hungary	1980	only	-	Apr	 6	 1:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
 			1:00	C-Eur	CE%sT	1918
-			1:00	Hungary	CE%sT	1941 Apr  6  2:00
+			1:00	Hungary	CE%sT	1941 Apr  8
 			1:00	C-Eur	CE%sT	1945
 			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
 			1:00	EU	CE%sT
@@ -1423,7 +1438,7 @@ Rule	Iceland	1967	only	-	Oct	29	 1:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
 			-1:27:48 -	RMT	1908 # Reykjavik Mean Time?
-			-1:00	Iceland	IS%sT	1968 Apr 7 1:00s
+			-1:00	Iceland	IS%sT	1968 Apr  7  1:00s
 			 0:00	-	GMT
 
 # Italy
@@ -1438,9 +1453,8 @@ Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
 # From Paul Eggert (2006-03-22):
 # For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
 # F. Pollastri
-# 
 # Day-light Saving Time in Italy (2006-02-03)
-# 
+# http://toi.iriti.cnr.it/uk/ienitlt.html
 # ('FP' below), taken from an Italian National Electrotechnical Institute
 # publication. When the three sources disagree, guess who's right, as follows:
 #
@@ -1500,8 +1514,8 @@ Rule	Italy	1978	only	-	Oct	 1	0:00s	0	-
 Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
-			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
-			1:00	Italy	CE%sT	1942 Nov  2 2:00s
+			0:49:56	-	RMT	1893 Nov  1  0:00s # Rome Mean
+			1:00	Italy	CE%sT	1942 Nov  2  2:00s
 			1:00	C-Eur	CE%sT	1944 Jul
 			1:00	Italy	CE%sT	1980
 			1:00	EU	CE%sT
@@ -1548,18 +1562,18 @@ Link	Europe/Rome	Europe/San_Marino
 
 # From Andrei Ivanov (2000-03-06):
 # This year Latvia will not switch to Daylight Savings Time (as specified in
-# 
 # The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
-# 29-Feb-2000 (#79), in Latvian for subscribers only).
+# 29-Feb-2000 (#79) ,
+# in Latvian for subscribers only).
 
-# 
-# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
-# 
+# From RFE/RL Newsline
+# http://www.rferl.org/newsline/2001/01/3-CEE/cee-030101.html
+# (2001-01-03), noted after a heads-up by Rives McDow:
 # The Latvian government on 2 January decided that the country will
 # institute daylight-saving time this spring, LETA reported.
 # Last February the three Baltic states decided not to turn back their
 # clocks one hour in the spring....
-# Minister of Economy Aigars Kalvitis noted that Latvia had too few
+# Minister of Economy Aigars Kalvītis noted that Latvia had too few
 # daylight hours and thus decided to comply with a draft European
 # Commission directive that provides for instituting daylight-saving
 # time in EU countries between 2002 and 2006. The Latvian government
@@ -1569,18 +1583,23 @@ Link	Europe/Rome	Europe/San_Marino
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Latvia	1989	1996	-	Mar	lastSun	 2:00s	1:00	S
 Rule	Latvia	1989	1996	-	Sep	lastSun	 2:00s	0	-
+
+# Milne 1899 says Riga was 1:36:28 (Polytechnique House time).
+# Byalokoz 1919 says Latvia was 1:36:34.
+# Go with Byalokoz.
+
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Europe/Riga	1:36:24	-	LMT	1880
-			1:36:24	-	RMT	1918 Apr 15 2:00 #Riga Mean Time
-			1:36:24	1:00	LST	1918 Sep 16 3:00 #Latvian Summer
-			1:36:24	-	RMT	1919 Apr  1 2:00
-			1:36:24	1:00	LST	1919 May 22 3:00
-			1:36:24	-	RMT	1926 May 11
+Zone	Europe/Riga	1:36:34	-	LMT	1880
+			1:36:34	-	RMT	1918 Apr 15  2:00 # Riga MT
+			1:36:34	1:00	LST	1918 Sep 16  3:00 # Latvian ST
+			1:36:34	-	RMT	1919 Apr  1  2:00
+			1:36:34	1:00	LST	1919 May 22  3:00
+			1:36:34	-	RMT	1926 May 11
 			2:00	-	EET	1940 Aug  5
 			3:00	-	MSK	1941 Jul
 			1:00	C-Eur	CE%sT	1944 Oct 13
-			3:00	Russia	MSK/MSD	1989 Mar lastSun 2:00s
-			2:00	1:00	EEST	1989 Sep lastSun 2:00s
+			3:00	Russia	MSK/MSD	1989 Mar lastSun  2:00s
+			2:00	1:00	EEST	1989 Sep lastSun  2:00s
 			2:00	Latvia	EE%sT	1997 Jan 21
 			2:00	EU	EE%sT	2000 Feb 29
 			2:00	-	EET	2001 Jan  2
@@ -1614,7 +1633,7 @@ Link Europe/Zurich Europe/Vaduz
 # I would like to inform that in this year Lithuanian time zone
 # (Europe/Vilnius) was changed.
 
-# From ELTA No. 972 (2582) (1999-09-29),
+# From ELTA No. 972 (2582) (1999-09-29) ,
 # via Steffen Thorsen:
 # Lithuania has shifted back to the second time zone (GMT plus two hours)
 # to be valid here starting from October 31,
@@ -1623,9 +1642,9 @@ Link Europe/Zurich Europe/Vaduz
 # motion to give up shifting to summer time in spring, as it was
 # already done by Estonia.
 
-# From the 
-# Fact File, Lithuanian State Department of Tourism
-#  (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
+# From the Fact File, Lithuanian State Department of Tourism
+#  (2000-03-27):
+# Local time is GMT+2 hours ..., no daylight saving.
 
 # From a user via Klaus Marten (2003-02-07):
 # As a candidate for membership of the European Union, Lithuania will
@@ -1638,18 +1657,18 @@ Link Europe/Zurich Europe/Vaduz
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Vilnius	1:41:16	-	LMT	1880
-			1:24:00	-	WMT	1917	    # Warsaw Mean Time
+			1:24:00	-	WMT	1917        # Warsaw Mean Time
 			1:35:36	-	KMT	1919 Oct 10 # Kaunas Mean Time
 			1:00	-	CET	1920 Jul 12
 			2:00	-	EET	1920 Oct  9
 			1:00	-	CET	1940 Aug  3
 			3:00	-	MSK	1941 Jun 24
 			1:00	C-Eur	CE%sT	1944 Aug
-			3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
-			2:00	1:00	EEST	1991 Sep 29 2:00s
+			3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
+			2:00	1:00	EEST	1991 Sep 29  2:00s
 			2:00	C-Eur	EE%sT	1998
-			2:00	-	EET	1998 Mar 29 1:00u
-			1:00	EU	CE%sT	1999 Oct 31 1:00u
+			2:00	-	EET	1998 Mar 29  1:00u
+			1:00	EU	CE%sT	1999 Oct 31  1:00u
 			2:00	-	EET	2003 Jan  1
 			2:00	EU	EE%sT
 
@@ -1683,9 +1702,9 @@ Rule	Lux	1929	only	-	Apr	20	23:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Europe/Luxembourg	0:24:36 -	LMT	1904 Jun
 			1:00	Lux	CE%sT	1918 Nov 25
-			0:00	Lux	WE%sT	1929 Oct  6 2:00s
-			0:00	Belgium	WE%sT	1940 May 14 3:00
-			1:00	C-Eur	WE%sT	1944 Sep 18 3:00
+			0:00	Lux	WE%sT	1929 Oct  6  2:00s
+			0:00	Belgium	WE%sT	1940 May 14  3:00
+			1:00	C-Eur	WE%sT	1944 Sep 18  3:00
 			1:00	Belgium	CE%sT	1977
 			1:00	EU	CE%sT
 
@@ -1702,9 +1721,9 @@ Rule	Malta	1975	1979	-	Apr	Sun>=15	2:00	1:00	S
 Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
 Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
-			1:00	Italy	CE%sT	1942 Nov  2 2:00s
-			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
+Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2  0:00s # Valletta
+			1:00	Italy	CE%sT	1942 Nov  2  2:00s
+			1:00	C-Eur	CE%sT	1945 Apr  2  2:00s
 			1:00	Italy	CE%sT	1973 Mar 31
 			1:00	Malta	CE%sT	1981
 			1:00	EU	CE%sT
@@ -1719,7 +1738,7 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
 # In early 1992 there was large-scale interethnic violence in the area
 # and it's possible that some Russophones continued to observe Moscow time.
 # But [two people] separately reported via
-# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
+# Jesper Nørgaard that as of 2001-01-24 Tiraspol was like Chisinau.
 # The Tiraspol entry has therefore been removed for now.
 #
 # From Alexander Krivenyshev (2011-10-17):
@@ -1728,13 +1747,8 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
 # to the Winter Time).
 #
 # News (in Russian):
-# 
 # http://www.kyivpost.ua/russia/news/pridnestrove-otkazalos-ot-perehoda-na-zimnee-vremya-30954.html
-# 
-#
-# 
 # http://www.allmoldova.com/moldova-news/1249064116.html
-# 
 #
 # The substance of this change (reinstatement of the Tiraspol entry)
 # is from a patch from Petr Machata (2011-10-17)
@@ -1752,9 +1766,7 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
 # Following Moldova and neighboring Ukraine- Transnistria (Pridnestrovie)-
 # Tiraspol will go back to winter time on October 30, 2011.
 # News from Moldova (in russian):
-# 
 # http://ru.publika.md/link_317061.html
-# 
 
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -1777,8 +1789,8 @@ Zone	Europe/Chisinau	1:55:20 -	LMT	1880
 # more precise 0:09:21.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
-			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
-			0:00	France	WE%sT	1945 Sep 16 3:00
+			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
+			0:00	France	WE%sT	1945 Sep 16  3:00
 			1:00	France	CE%sT	1977
 			1:00	EU	CE%sT
 
@@ -1822,8 +1834,8 @@ Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
 # was not until 1866 when they were all required by law to observe
 # Amsterdam mean time.
 
-# The data before 1945 are taken from
-# .
+# The data entries before 1945 are taken from
+# http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Neth	1916	only	-	May	 1	0:00	1:00	NST	# Netherlands Summer Time
@@ -1854,8 +1866,8 @@ Rule	Neth	1945	only	-	Sep	16	2:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Europe/Amsterdam	0:19:32 -	LMT	1835
 			0:19:32	Neth	%s	1937 Jul  1
-			0:20	Neth	NE%sT	1940 May 16 0:00 # Dutch Time
-			1:00	C-Eur	CE%sT	1945 Apr  2 2:00
+			0:20	Neth	NE%sT	1940 May 16  0:00 # Dutch Time
+			1:00	C-Eur	CE%sT	1945 Apr  2  2:00
 			1:00	Neth	CE%sT	1977
 			1:00	EU	CE%sT
 
@@ -1885,14 +1897,14 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
 # time they were declared as parts of Norway.  Svalbard was declared
 # as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan
 # Mayen by law of 1930-02-27 no 2, section 2. (From
-# http://www.lovdata.no/all/nl-19250717-011.html and
-# http://www.lovdata.no/all/nl-19300227-002.html).  The law/regulation
+#  and
+# ).  The law/regulation
 # for normal/standard time in Norway is from 1894-06-29 no 1 (came
 # into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a
 # part of this law since 1925/1930. (From
-# http://www.lovdata.no/all/nl-18940629-001.html ) I have not been
+# ) I have not been
 # able to find if Jan Mayen used a different time zone (e.g. -0100)
-# before 1930. Jan Mayen has only been "inhabitated" since 1921 by
+# before 1930. Jan Mayen has only been "inhabited" since 1921 by
 # Norwegian meteorologists and maybe used the same time as Norway ever
 # since 1921.  Svalbard (Arctic/Longyearbyen) has been inhabited since
 # before 1895, and therefore probably changed the local time somewhere
@@ -1907,7 +1919,7 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
 #  says that the meteorologists
 # burned down their station in 1940 and left the island, but returned in
 # 1941 with a small Norwegian garrison and continued operations despite
-# frequent air ttacks from Germans.  In 1943 the Americans established a
+# frequent air attacks from Germans.  In 1943 the Americans established a
 # radiolocating station on the island, called "Atlantic City".  Possibly
 # the UT offset changed during the war, but I think it unlikely that
 # Jan Mayen used German daylight-saving rules.
@@ -1918,7 +1930,7 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
 #  says that the Germans were
 # expelled on 1942-05-14.  However, small parties of Germans did return,
 # and according to Wilhelm Dege's book "War North of 80" (1954)
-# 
+# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html
 # the German armed forces at the Svalbard weather station code-named
 # Haudegen did not surrender to the Allies until September 1945.
 #
@@ -1927,6 +1939,10 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
 Link	Europe/Oslo	Arctic/Longyearbyen
 
 # Poland
+
+# The 1919 dates and times can be found in Tygodnik Urzędowy nr 1 (1919-03-20),
+#  pp 1-2.
+
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
 Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
@@ -1937,9 +1953,9 @@ Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
 Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
 Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
 # For 1946 on the source is Kazimierz Borkowski,
-# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
-# 
-# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
+# Toruń Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
+# http://www.astro.uni.torun.pl/~kb/Artykuly/U-PA/Czas2.htm#tth_tAb1
+# Thanks to Przemysław Augustyniak (2005-05-28) for this reference.
 # He also gives these further references:
 # Mon Pol nr 13, poz 162 (1995) 
 # Druk nr 2180 (2003) 
@@ -1959,10 +1975,10 @@ Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
 Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Warsaw	1:24:00 -	LMT	1880
-			1:24:00	-	WMT	1915 Aug  5   # Warsaw Mean Time
-			1:00	C-Eur	CE%sT	1918 Sep 16 3:00
+			1:24:00	-	WMT	1915 Aug  5 # Warsaw Mean Time
+			1:00	C-Eur	CE%sT	1918 Sep 16  3:00
 			2:00	Poland	EE%sT	1922 Jun
-			1:00	Poland	CE%sT	1940 Jun 23 2:00
+			1:00	Poland	CE%sT	1940 Jun 23  2:00
 			1:00	C-Eur	CE%sT	1944 Oct
 			1:00	Poland	CE%sT	1977
 			1:00	W-Eur	CE%sT	1988
@@ -1970,6 +1986,14 @@ Zone	Europe/Warsaw	1:24:00 -	LMT	1880
 
 # Portugal
 #
+# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne:
+# According to a Portuguese decree (1911-05-26)
+# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
+# Lisbon was at -0:36:44.68, but switched to GMT on 1912-01-01 at 00:00.
+# Round the old offset to -0:36:45.  This agrees with Willett but disagrees
+# with Shanks, who says the transition occurred on 1911-05-24 at 00:00 for
+# Europe/Lisbon, Atlantic/Azores, and Atlantic/Madeira.
+#
 # From Rui Pedro Salgueiro (1992-11-12):
 # Portugal has recently (September, 27) changed timezone
 # (from WET to MET or CET) to harmonize with EEC.
@@ -2049,35 +2073,34 @@ Rule	Port	1979	1982	-	Sep	lastSun	 1:00s	0	-
 Rule	Port	1980	only	-	Mar	lastSun	 0:00s	1:00	S
 Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
 Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
+#
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
-# Willett says 1912-01-01.  Go with Willett.
-Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
-			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
-			 0:00	Port	WE%sT	1966 Apr  3 2:00
-			 1:00	-	CET	1976 Sep 26 1:00
-			 0:00	Port	WE%sT	1983 Sep 25 1:00s
-			 0:00	W-Eur	WE%sT	1992 Sep 27 1:00s
-			 1:00	EU	CE%sT	1996 Mar 31 1:00u
+Zone	Europe/Lisbon	-0:36:45 -	LMT	1884
+			-0:36:45 -	LMT	1912 Jan  1 # Lisbon Mean Time
+			 0:00	Port	WE%sT	1966 Apr  3  2:00
+			 1:00	-	CET	1976 Sep 26  1:00
+			 0:00	Port	WE%sT	1983 Sep 25  1:00s
+			 0:00	W-Eur	WE%sT	1992 Sep 27  1:00s
+			 1:00	EU	CE%sT	1996 Mar 31  1:00u
 			 0:00	EU	WE%sT
-Zone Atlantic/Azores	-1:42:40 -	LMT	1884		# Ponta Delgada
-			-1:54:32 -	HMT	1911 May 24  # Horta Mean Time
-			-2:00	Port	AZO%sT	1966 Apr  3 2:00 # Azores Time
-			-1:00	Port	AZO%sT	1983 Sep 25 1:00s
-			-1:00	W-Eur	AZO%sT	1992 Sep 27 1:00s
-			 0:00	EU	WE%sT	1993 Mar 28 1:00u
+Zone Atlantic/Azores	-1:42:40 -	LMT	1884        # Ponta Delgada
+			-1:54:32 -	HMT	1912 Jan  1 # Horta Mean Time
+			-2:00	Port	AZO%sT	1966 Apr  3  2:00  # Azores Time
+			-1:00	Port	AZO%sT	1983 Sep 25  1:00s
+			-1:00	W-Eur	AZO%sT	1992 Sep 27  1:00s
+			 0:00	EU	WE%sT	1993 Mar 28  1:00u
 			-1:00	EU	AZO%sT
-Zone Atlantic/Madeira	-1:07:36 -	LMT	1884		# Funchal
-			-1:07:36 -	FMT	1911 May 24  # Funchal Mean Time
-			-1:00	Port	MAD%sT	1966 Apr  3 2:00 # Madeira Time
-			 0:00	Port	WE%sT	1983 Sep 25 1:00s
+Zone Atlantic/Madeira	-1:07:36 -	LMT	1884        # Funchal
+			-1:07:36 -	FMT	1912 Jan  1 # Funchal Mean Time
+			-1:00	Port	MAD%sT	1966 Apr  3  2:00 # Madeira Time
+			 0:00	Port	WE%sT	1983 Sep 25  1:00s
 			 0:00	EU	WE%sT
 
 # Romania
 #
 # From Paul Eggert (1999-10-07):
-# 
-# Nine O'clock (1998-10-23) reports that the switch occurred at
+# Nine O'clock 
+# (1998-10-23) reports that the switch occurred at
 # 04:00 local time in fall 1998.  For lack of better info,
 # assume that Romania and Moldova switched to EU rules in 1997,
 # the same year as Bulgaria.
@@ -2094,32 +2117,28 @@ Rule	Romania	1991	1993	-	Mar	lastSun	 0:00s	1:00	S
 Rule	Romania	1991	1993	-	Sep	lastSun	 0:00s	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
-			1:44:24	-	BMT	1931 Jul 24	# Bucharest MT
-			2:00	Romania	EE%sT	1981 Mar 29 2:00s
+			1:44:24	-	BMT	1931 Jul 24 # Bucharest MT
+			2:00	Romania	EE%sT	1981 Mar 29  2:00s
 			2:00	C-Eur	EE%sT	1991
 			2:00	Romania	EE%sT	1994
 			2:00	E-Eur	EE%sT	1997
 			2:00	EU	EE%sT
 
+
 # Russia
 
 # From Alexander Krivenyshev (2011-09-15):
 # Based on last Russian Government Decree # 725 on August 31, 2011
 # (Government document
-# 
 # http://www.government.ru/gov/results/16355/print/
-# 
 # in Russian)
 # there are few corrections have to be made for some Russian time zones...
 # All updated Russian Time Zones were placed in table and translated to English
 # by WorldTimeZone.com at the link below:
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_russia36.htm
-# 
 
 # From Sanjeev Gupta (2011-09-27):
 # Scans of [Decree #23 of January 8, 1992] are available at:
-# 
 # http://government.consultant.ru/page.aspx?1223966
 # They are in Cyrillic letters (presumably Russian).
 
@@ -2128,16 +2147,12 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
 # changed in September 2011:
 #
 # One source is
-# < a href="http://government.ru/gov/results/16355/>
 # http://government.ru/gov/results/16355/
-# 
 # which, according to translate.google.com, begins "Decree of August 31,
 # 2011 No 725" and contains no other dates or "effective date" information.
 #
 # Another source is
-# 
 # http://www.rg.ru/2011/09/06/chas-zona-dok.html
-# 
 # which, according to translate.google.com, begins "Resolution of the
 # Government of the Russian Federation on August 31, 2011 N 725" and also
 # contains "Date first official publication: September 6, 2011 Posted on:
@@ -2145,28 +2160,45 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
 # does not contain any "effective date" information.
 #
 # Another source is
-# 
 # http://en.wikipedia.org/wiki/Oymyakonsky_District#cite_note-RuTime-7
-# 
 # which, in note 8, contains "Resolution #725 of August 31, 2011...
 # Effective as of after 7 days following the day of the official publication"
 # but which does not contain any reference to September 6, 2011.
 #
 # The Wikipedia article refers to
-# 
 # http://base.consultant.ru/cons/cgi/online.cgi?req=doc;base=LAW;n=118896
-# 
 # which seems to copy the text of the government.ru page.
 #
 # Tobias Conradi combines Wikipedia's
 # "as of after 7 days following the day of the official publication"
-# with www.rg.ru's "Date of first official publication: September 6, 2011" to get
-# September 13, 2011 as the cutover date (unusually, a Tuesday, as Tobias Conradi notes).
+# with www.rg.ru's "Date of first official publication: September 6, 2011" to
+# get September 13, 2011 as the cutover date (unusually, a Tuesday, as Tobias
+# Conradi notes).
 #
 # None of the sources indicates a time of day for changing clocks.
 #
 # Go with 2011-09-13 0:00s.
 
+# From Alexander Krivenyshev (2014-07-01):
+# According to the Russian news (ITAR-TASS News Agency)
+# http://en.itar-tass.com/russia/738562
+# the State Duma has approved ... the draft bill on returning to
+# winter time standard and return Russia 11 time zones.  The new
+# regulations will come into effect on October 26, 2014 at 02:00 ...
+# http://asozd2.duma.gov.ru/main.nsf/%28Spravka%29?OpenAgent&RN=431985-6&02
+# Here is a link where we put together table (based on approved Bill N
+# 431985-6) with proposed 11 Russian time zones and corresponding
+# areas/cities/administrative centers in the Russian Federation (in English):
+# http://www.worldtimezone.com/dst_news/dst_news_russia65.html
+#
+# From Alexander Krivenyshev (2014-07-22):
+# Putin signed the Federal Law 431985-6 ... (in Russian)
+# http://itar-tass.com/obschestvo/1333711
+# http://www.pravo.gov.ru:8080/page.aspx?111660
+# http://www.kremlin.ru/acts/46279
+# From October 26, 2014 the new Russian time zone map will looks like this:
+# 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,
@@ -2193,9 +2225,9 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
 #
 # For Grozny, Chechnya, we have the following story from
 # John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
-# News--often false--is spread by word of mouth.  A rumor that it was
+# News - often false - is spread by word of mouth.  A rumor that it was
 # time to move the clocks back put this whole city out of sync with
-# the rest of Russia for two weeks--even soldiers stationed here began
+# the rest of Russia for two weeks - even soldiers stationed here began
 # enforcing curfew at the wrong time.
 #
 # From Gwillim Law (2001-06-05):
@@ -2206,107 +2238,265 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
 # since September 1997....  Although the Kuril Islands are
 # administratively part of Sakhalin oblast', they appear to have
 # remained on UTC+11 along with Magadan.
-#
+
+# From Tim Parenti (2014-07-06):
+# The comments detailing the coverage of each Russian zone are meant to assist
+# with maintenance only and represent our best guesses as to which regions
+# are covered by each zone.  They are not meant to be taken as an authoritative
+# listing.  The region codes listed come from
+# http://en.wikipedia.org/w/?title=Federal_subjects_of_Russia&oldid=611810498
+# and are used for convenience only; no guarantees are made regarding their
+# future stability.  ISO 3166-2:RU codes are also listed for first-level
+# divisions where available.
+
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-#
-# Kaliningradskaya oblast'.
+
+
+# From Tim Parenti (2014-07-03):
+# Europe/Kaliningrad covers...
+# 39	RU-KGD	Kaliningrad Oblast
+
 Zone Europe/Kaliningrad	 1:22:00 -	LMT	1893 Apr
 			 1:00	C-Eur	CE%sT	1945
 			 2:00	Poland	CE%sT	1946
-			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
-			 2:00	Russia	EE%sT	2011 Mar 27 2:00s
-			 3:00	-	FET # Further-eastern European Time
+			 3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
+			 2:00	Russia	EE%sT	2011 Mar 27  2:00s
+			 3:00	-	FET	2014 Oct 26  2:00s
+			 2:00	-	EET
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Europe/Moscow covers...
+# 01	RU-AD	Adygea, Republic of
+# 05	RU-DA	Dagestan, Republic of
+# 06	RU-IN	Ingushetia, Republic of
+# 07	RU-KB	Kabardino-Balkar Republic
+# 08	RU-KL	Kalmykia, Republic of
+# 09	RU-KC	Karachay-Cherkess Republic
+# 10	RU-KR	Karelia, Republic of
+# 11	RU-KO	Komi Republic
+# 12	RU-ME	Mari El Republic
+# 13	RU-MO	Mordovia, Republic of
+# 15	RU-SE	North Ossetia-Alania, Republic of
+# 16	RU-TA	Tatarstan, Republic of
+# 20	RU-CE	Chechen Republic
+# 21	RU-CU	Chuvash Republic
+# 23	RU-KDA	Krasnodar Krai
+# 26	RU-STA	Stavropol Krai
+# 29	RU-ARK	Arkhangelsk Oblast
+# 31	RU-BEL	Belgorod Oblast
+# 32	RU-BRY	Bryansk Oblast
+# 33	RU-VLA	Vladimir Oblast
+# 35	RU-VLG	Vologda Oblast
+# 36	RU-VOR	Voronezh Oblast
+# 37	RU-IVA	Ivanovo Oblast
+# 40	RU-KLU	Kaluga Oblast
+# 44	RU-KOS	Kostroma Oblast
+# 46	RU-KRS	Kursk Oblast
+# 47	RU-LEN	Leningrad Oblast
+# 48	RU-LIP	Lipetsk Oblast
+# 50	RU-MOS	Moscow Oblast
+# 51	RU-MUR	Murmansk Oblast
+# 52	RU-NIZ	Nizhny Novgorod Oblast
+# 53	RU-NGR	Novgorod Oblast
+# 57	RU-ORL	Oryol Oblast
+# 58	RU-PNZ	Penza Oblast
+# 60	RU-PSK	Pskov Oblast
+# 61	RU-ROS	Rostov Oblast
+# 62	RU-RYA	Ryazan Oblast
+# 67	RU-SMO	Smolensk Oblast
+# 68	RU-TAM	Tambov Oblast
+# 69	RU-TVE	Tver Oblast
+# 71	RU-TUL	Tula Oblast
+# 73	RU-ULY	Ulyanovsk Oblast
+# 76	RU-YAR	Yaroslavl Oblast
+# 77	RU-MOW	Moscow
+# 78	RU-SPE	Saint Petersburg
+# 83	RU-NEN	Nenets Autonomous Okrug
+
+# From Vladimir Karpinsky (2014-07-08):
+# LMT in Moscow (before Jul 3, 1916) is 2:30:17, that was defined by Moscow
+# Observatory (coordinates: 55 deg. 45'29.70", 37 deg. 34'05.30")....
+# LMT in Moscow since Jul 3, 1916 is 2:31:01 as a result of new standard.
+# (The info is from the book by Byalokoz ... p. 18.)
+# The time in St. Petersburg as capital of Russia was defined by
+# Pulkov observatory, near St. Petersburg.  In 1916 LMT Moscow
+# was synchronized with LMT St. Petersburg (+30 minutes), (Pulkov observatory
+# coordinates: 59 deg. 46'18.70", 30 deg. 19'40.70") so 30 deg. 19'40.70" >
+# 2h01m18.7s = 2:01:19.  LMT Moscow = LMT St.Petersburg + 30m 2:01:19 + 0:30 =
+# 2:31:19 ...
 #
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Respublika Adygeya, Arkhangel'skaya oblast',
-# Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
-# Vologodskaya oblast', Voronezhskaya oblast',
-# Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
-# Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
-# Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
-# Respublika Kareliya, Respublika Komi,
-# Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
-# Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
-# Respublika Mordoviya, Moskva, Moskovskaya oblast',
-# Murmanskaya oblast', Nenetskij avtonomnyj okrug,
-# Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
-# Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
-# Ryazanskaya oblast', Sankt-Peterburg,
-# Respublika Severnaya Osetiya, Smolenskaya oblast',
-# Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
-# Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
-# Chechenskaya Respublika, Chuvashskaya oblast',
-# Yaroslavskaya oblast'
-Zone Europe/Moscow	 2:30:20 -	LMT	1880
-			 2:30	-	MMT	1916 Jul  3 # Moscow Mean Time
-			 2:30:48 Russia	%s	1919 Jul  1 2:00
+# From Paul Eggert (2014-07-08):
+# Milne does not list Moscow, but suggests that its time might be listed in
+# Résumés mensuels et annuels des observations météorologiques (1895).
+# Presumably this is OCLC 85825704, a journal published with parallel text in
+# Russian and French.  This source has not been located; go with Karpinsky.
+
+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
+			 3:00	Russia	%s	1921 Oct
 			 3:00	Russia	MSK/MSD	1922 Oct
 			 2:00	-	EET	1930 Jun 21
-			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
-			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
-			 3:00	Russia	MSK/MSD	2011 Mar 27 2:00s
-			 4:00	-	MSK
+			 3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
+			 2:00	Russia	EE%sT	1992 Jan 19  2:00s
+			 3:00	Russia	MSK/MSD	2011 Mar 27  2:00s
+			 4:00	-	MSK	2014 Oct 26  2:00s
+			 3:00	-	MSK
+
+
+# From Tim Parenti (2014-07-03):
+# Europe/Simferopol covers...
+# **	****	Crimea, Republic of
+# **	****	Sevastopol
+
+Zone Europe/Simferopol	 2:16:24 -	LMT	1880
+			 2:16	-	SMT	1924 May  2 # Simferopol Mean T
+			 2:00	-	EET	1930 Jun 21
+			 3:00	-	MSK	1941 Nov
+			 1:00	C-Eur	CE%sT	1944 Apr 13
+			 3:00	Russia	MSK/MSD	1990
+			 3:00	-	MSK	1990 Jul  1  2:00
+			 2:00	-	EET	1992
+# Central Crimea used Moscow time 1994/1997.
 #
-# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
-# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
-# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
-# others?  But we have no data.
+# From Paul Eggert (2006-03-22):
+# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
+# from Kiev to Moscow time sometime after the January 1994 elections.
+# Shanks (1999) says "date of change uncertain", but implies that it happened
+# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
+# 1994-09-25 03:00, but that can't be right.  For now, guess it
+# changed in May.
+			 2:00	E-Eur	EE%sT	1994 May
+# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
+			 3:00	E-Eur	MSK/MSD	1996 Mar 31  3:00s
+			 3:00	1:00	MSD	1996 Oct 27  3:00s
+# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
+# Assume it happened in March by not changing the clocks.
+			 3:00	Russia	MSK/MSD	1997
+			 3:00	-	MSK	1997 Mar lastSun  1:00u
+# From Alexander Krivenyshev (2014-03-17):
+# time change at 2:00 (2am) on March 30, 2014
+# http://vz.ru/news/2014/3/17/677464.html
+# From Paul Eggert (2014-03-30):
+# Simferopol and Sevastopol reportedly changed their central town clocks
+# late the previous day, but this appears to have been ceremonial
+# and the discrepancies are small enough to not worry about.
+			 2:00	EU	EE%sT	2014 Mar 30  2:00
+			 4:00	-	MSK	2014 Oct 26  2:00s
+			 3:00	-	MSK
+
+
+# From Tim Parenti (2014-07-03):
+# Europe/Volgograd covers...
+# 30	RU-AST	Astrakhan Oblast
+# 34	RU-VGG	Volgograd Oblast
+# 43	RU-KIR	Kirov Oblast
+# 64	RU-SAR	Saratov Oblast
+
+# From Paul Eggert (2006-05-09):
+# Shanks & Pottenger say Kirov is still at +0400 but Wikipedia says +0300.
+# Perhaps it switched after the others?  But we have no data.
+
 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	1989 Mar 26 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	VOL%sT	2011 Mar 27 2:00s
-			 4:00	-	VOLT
-#
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Samarskaya oblast', Udmyrtskaya respublika
-Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
+			 4:00	Russia	VOL%sT	1989 Mar 26  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	2011 Mar 27  2:00s
+			 4:00	-	MSK	2014 Oct 26  2:00s
+			 3:00	-	MSK
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Europe/Samara covers...
+# 18	RU-UD	Udmurt Republic
+# 63	RU-SAM	Samara Oblast
+
+# Byalokoz 1919 says Samara was 3:20:20.
+
+Zone Europe/Samara	 3:20:20 -	LMT	1919 Jul  1  2:00
 			 3:00	-	SAMT	1930 Jun 21
 			 4:00	-	SAMT	1935 Jan 27
-			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
-			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
-			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
-			 3:00	-	KUYT	1991 Oct 20 3:00
-			 4:00	Russia	SAM%sT	2010 Mar 28 2:00s # Samara Time
-			 3:00	Russia	SAM%sT	2011 Mar 27 2:00s
+			 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	-	KUYT	1991 Oct 20  3:00
+			 4:00	Russia	SAM%sT	2010 Mar 28  2:00s # Samara Time
+			 3:00	Russia	SAM%sT	2011 Mar 27  2:00s
 			 4:00	-	SAMT
 
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Asia/Yekaterinburg covers...
+# 02	RU-BA	Bashkortostan, Republic of
+# 90	RU-PER	Perm Krai
+# 45	RU-KGN	Kurgan Oblast
+# 56	RU-ORE	Orenburg Oblast
+# 66	RU-SVE	Sverdlovsk Oblast
+# 72	RU-TYU	Tyumen Oblast
+# 74	RU-CHE	Chelyabinsk Oblast
+# 86	RU-KHM	Khanty-Mansi Autonomous Okrug - Yugra
+# 89	RU-YAN	Yamalo-Nenets Autonomous Okrug
 #
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
-# Kurganskaya oblast', Orenburgskaya oblast', Permskaya oblast',
-# Sverdlovskaya oblast', Tyumenskaya oblast',
-# Khanty-Manskijskij avtonomnyj okrug, Chelyabinskaya oblast',
-# Yamalo-Nenetskij avtonomnyj okrug.
-Zone Asia/Yekaterinburg	 4:02:24 -	LMT	1919 Jul 15 4:00
+# Note: Effective 2005-12-01, (59) Perm Oblast and (81) Komi-Permyak
+# Autonomous Okrug merged to form (90, RU-PER) Perm Krai.
+
+# Milne says Yekaterinburg was 4:02:32.9; round to nearest.
+# Byalokoz 1919 says its provincial time was based on Perm, at 3:45:05.
+# Assume it switched on 1916-07-03, the time of the new standard.
+# The 1919 and 1930 transitions are from Shanks.
+
+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	# Yekaterinburg Time
-#
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Respublika Altaj, Altajskij kraj, Omskaya oblast'.
-Zone Asia/Omsk		 4:53:36 -	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
-#
+			 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
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Asia/Omsk covers...
+# 04	RU-AL	Altai Republic
+# 22	RU-ALT	Altai Krai
+# 55	RU-OMS	Omsk Oblast
+
+# 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
+
+
+# From Tim Parenti (2014-07-03):
+# Asia/Novosibirsk covers...
+# 54	RU-NVS	Novosibirsk Oblast
+# 70	RU-TOM	Tomsk Oblast
+
 # From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
 # not clear when it switched from +7 to +6.
-# Novosibirskaya oblast', Tomskaya oblast'.
-Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
+
+Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14  6:00
 			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
-			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
-			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
+			 7:00	Russia	NOV%sT	1991 Mar 31  2:00s
+			 6:00	Russia	NOV%sT	1992 Jan 19  2:00s
 			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
-			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
-			 7:00	-	NOVT
+			 6:00	Russia	NOV%sT	2011 Mar 27  2:00s
+			 7:00	-	NOVT	2014 Oct 26  2:00s
+			 6:00	-	NOVT
+
+
+# From Tim Parenti (2014-07-03):
+# Asia/Novokuznetsk covers...
+# 42	RU-KEM	Kemerovo Oblast
 
 # From Alexander Krivenyshev (2009-10-13):
 # Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
@@ -2319,14 +2509,10 @@ Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
 # time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
 #
 # Russian Government web site (Russian language)
-# 
 # http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
-# 
 # or Russian-English translation by WorldTimeZone.com with reference
 # map to local region and new Russia Time Zone map after March 28, 2010
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_russia03.html
-# 
 #
 # Thus, when Russia will switch to DST on the night of March 28, 2010
 # Kemerovo region (Kemerovo oblast') will not change the clock.
@@ -2334,152 +2520,319 @@ Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
 # As a result, Kemerovo oblast' will be in the same time zone as
 # Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
 
+# From Tim Parenti (2014-07-02), per Alexander Krivenyshev (2014-07-02):
+# The Kemerovo region will remain at UTC+7 through the 2014-10-26 change, thus
+# realigning itself with KRAT.
+
 Zone Asia/Novokuznetsk	 5:48:48 -	NMT	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	2010 Mar 28 2:00s
-			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
-			 7:00	-	NOVT # Novosibirsk/Novokuznetsk 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	2010 Mar 28  2:00s
+			 6:00	Russia	NOV%sT	2011 Mar 27  2:00s # Novosibirsk
+			 7:00	-	NOVT	2014 Oct 26  2:00s
+			 7:00	-	KRAT	# Krasnoyarsk Time
 
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Asia/Krasnoyarsk covers...
+# 17	RU-TY	Tuva Republic
+# 19	RU-KK	Khakassia, Republic of
+# 24	RU-KYA	Krasnoyarsk Krai
 #
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Krasnoyarskij kraj,
-# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
-# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
-Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
+# Note: Effective 2007-01-01, (88) Evenk Autonomous Okrug and (84) Taymyr
+# Autonomous Okrug were merged into (24, RU-KYA) Krasnoyarsk Krai.
+
+# 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
+			 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
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Asia/Irkutsk covers...
+# 03	RU-BU	Buryatia, Republic of
+# 38	RU-IRK	Irkutsk Oblast
 #
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Respublika Buryatiya, Irkutskaya oblast',
-# Ust'-Ordynskij Buryatskij avtonomnyj okrug.
-Zone Asia/Irkutsk	 6:57:20 -	LMT	1880
-			 6:57:20 -	IMT	1920 Jan 25 # Irkutsk Mean Time
+# Note: Effective 2008-01-01, (85) Ust-Orda Buryat Autonomous Okrug was
+# merged into (38, RU-IRK) Irkutsk Oblast.
+
+# Milne 1899 says Irkutsk was 6:57:15.
+# Byalokoz 1919 says Irkutsk was 6:57:05.
+# Go with Byalokoz.
+
+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
+			 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
+
+
+# From Tim Parenti (2014-07-06):
+# Asia/Chita covers...
+# 92	RU-ZAB	Zabaykalsky Krai
 #
-# From Oscar van Vlijmen (2003-10-18): [This region consists of]
-# Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
-# [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
+# Note: Effective 2008-03-01, (75) Chita Oblast and (80) Agin-Buryat
+# Autonomous Okrug merged to form (92, RU-ZAB) Zabaykalsky Krai.
 
-# From Oscar van Vlijmen (2009-11-29):
-# ...some regions of [Russia] were merged with others since 2005...
-# Some names were changed, no big deal, except for one instance: a new name.
-# YAK/YAKST: UTC+9 Zabajkal'skij kraj.
-
-# From Oscar van Vlijmen (2009-11-29):
-# The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
-# Verkhnevilyujskij, Vilyujskij, Gornyj,
-# Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
-# Namskij, Nyurbinskij, Olenyokskij, Olyokminskij,
-# Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
-# Churapchinskij, Eveno-Bytantajskij Natsional'nij.
-
-Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
+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
-#
-# From Oscar van Vlijmen (2003-10-18): [This region consists of]
-# Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
-# [parts of] Respublika Sakha (Yakutiya).
+			 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
 
-# From Oscar van Vlijmen (2009-11-29):
-# The Sakha districts are: Bulunskij, Verkhoyanskij, ... Ust'-Yanskij.
-Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
+# Asia/Yakutsk covers...
+# 28	RU-AMU	Amur Oblast
+#
+# ...and parts of (14, RU-SA) Sakha (Yakutia) Republic:
+# 14-02	****	Aldansky District
+# 14-04	****	Amginsky District
+# 14-05	****	Anabarsky District
+# 14-06	****	Bulunsky District
+# 14-07	****	Verkhnevilyuysky District
+# 14-10	****	Vilyuysky District
+# 14-11	****	Gorny District
+# 14-12	****	Zhigansky District
+# 14-13	****	Kobyaysky District
+# 14-14	****	Lensky District
+# 14-15	****	Megino-Kangalassky District
+# 14-16	****	Mirninsky District
+# 14-18	****	Namsky District
+# 14-19	****	Neryungrinsky District
+# 14-21	****	Nyurbinsky District
+# 14-23	****	Olenyoksky District
+# 14-24	****	Olyokminsky District
+# 14-26	****	Suntarsky District
+# 14-27	****	Tattinsky District
+# 14-29	****	Ust-Aldansky District
+# 14-32	****	Khangalassky District
+# 14-33	****	Churapchinsky District
+# 14-34	****	Eveno-Bytantaysky National District
+
+# From Tim Parenti (2014-07-03):
+# Our commentary seems to have lost mention of (14-19) Neryungrinsky District.
+# Since the surrounding districts of Sakha are all YAKT, assume this is, too.
+# Also assume its history has been the same as the rest of Asia/Yakutsk.
+
+# 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
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
+# Asia/Vladivostok covers...
+# 25	RU-PRI	Primorsky Krai
+# 27	RU-KHA	Khabarovsk Krai
+# 79	RU-YEV	Jewish Autonomous Oblast
+#
+# ...and parts of (14, RU-SA) Sakha (Yakutia) Republic:
+# 14-09	****	Verkhoyansky District
+# 14-31	****	Ust-Yansky District
+
+# Milne 1899 says Vladivostok was 8:47:33.5.
+# Byalokoz 1919 says Vladivostok was 8:47:31.
+# 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%sST	1992 Jan 19 2:00s
-			10:00	Russia	VLA%sT	2011 Mar 27 2:00s
-			11:00	-	VLAT
+			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
+
+
+# From Tim Parenti (2014-07-03):
+# Asia/Khandyga covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
+# 14-28	****	Tomponsky District
+# 14-30	****	Ust-Maysky District
 
 # From Arthur David Olson (2012-05-09):
 # Tomponskij and Ust'-Majskij switched from Vladivostok time to Yakutsk time
 # in 2011.
-#
+
 # From Paul Eggert (2012-11-25):
 # Shanks and Pottenger (2003) has Khandyga on Yakutsk time.
 # Make a wild guess that it switched to Vladivostok time in 2004.
 # 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	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
+			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
 
-#
-# Sakhalinskaya oblast'.
-# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
+
+# From Tim Parenti (2014-07-03):
+# Asia/Sakhalin covers...
+# 65	RU-SAK	Sakhalin Oblast
+# ...with the exception of:
+# 65-11	****	Severo-Kurilsky District (North Kuril Islands)
+
+# 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	-	CJT	1938
+			 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
-#
-# From Oscar van Vlijmen (2003-10-18): [This region consists of]
-# Magadanskaya oblast', Respublika Sakha (Yakutiya).
-# Probably also: Kuril Islands.
+			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
+
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
+# Asia/Magadan covers...
+# 49	RU-MAG	Magadan Oblast
+
+# From Tim Parenti (2014-07-06), per Alexander Krivenyshev (2014-07-02):
+# Magadan Oblast is moving from UTC+12 to UTC+10 on 2014-10-26; however,
+# several districts of Sakha Republic as well as Severo-Kurilsky District of
+# the Sakhalin Oblast (also known as the North Kuril Islands), represented
+# until now by Asia/Magadan, will instead move to UTC+11.  These regions will
+# need their own zone.
 
-# From Oscar van Vlijmen (2009-11-29):
-# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
-# Nizhnekolymskij, ... Srednekolymskij.
 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
+			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
+
+
+# From Tim Parenti (2014-07-06):
+# Asia/Srednekolymsk covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
+# 14-01	****	Abyysky District
+# 14-03	****	Allaikhovsky District
+# 14-08	****	Verkhnekolymsky District
+# 14-17	****	Momsky District
+# 14-20	****	Nizhnekolymsky District
+# 14-25	****	Srednekolymsky District
+#
+# ...and parts of (65, RU-SAK) Sakhalin Oblast:
+# 65-11	****	Severo-Kurilsky District (North Kuril Islands)
+
+# From Tim Parenti (2014-07-02):
+# Oymyakonsky District of Sakha Republic (represented by Ust-Nera), along with
+# most of Sakhalin Oblast (represented by Sakhalin) will be moving to UTC+10 on
+# 2014-10-26 to stay aligned with VLAT/SAKT; however, Severo-Kurilsky District
+# of the Sakhalin Oblast (also known as the North Kuril Islands, represented by
+# Severo-Kurilsk) will remain on UTC+11.
+
+# From Tim Parenti (2014-07-06):
+# Assume North Kuril Islands have history like Magadan before 2011-03-27.
+# There is a decent chance this is wrong, in which case a new zone
+# Asia/Severo-Kurilsk would become necessary.
+#
+# Srednekolymsk and Zyryanka are the most populous places amongst these
+# districts, but have very similar populations.  In fact, Wikipedia currently
+# lists them both as having 3528 people, exactly 1668 males and 1860 females
+# each!  (Yikes!)
+# http://en.wikipedia.org/w/?title=Srednekolymsky_District&oldid=603435276
+# http://en.wikipedia.org/w/?title=Verkhnekolymsky_District&oldid=594378493
+# Assume this is a mistake, albeit an amusing one.
+#
+# Looking at censuses, the populations of the two municipalities seem to have
+# fluctuated recently.  Zyryanka was more populous than Srednekolymsk in the
+# 1989 and 2002 censuses, but Srednekolymsk was more populous in the most
+# recent (2010) census, 3525 to 3170.  (See pages 195 and 197 of
+# http://www.gks.ru/free_doc/new_site/perepis2010/croc/Documents/Vol1/pub-01-05.pdf
+# 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
+
+
+# From Tim Parenti (2014-07-03):
+# Asia/Ust-Nera covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
+# 14-22	****	Oymyakonsky District
 
 # From Arthur David Olson (2012-05-09):
-# Ojmyakonskij and the Kuril Islands switched from
+# Ojmyakonskij [and the Kuril Islands] switched from
 # Magadan time to Vladivostok time in 2011.
+#
+# From Tim Parenti (2014-07-06), per Alexander Krivenyshev (2014-07-02):
+# It's unlikely that any of the Kuril Islands were involved in such a switch,
+# as the South and Middle Kurils have been on UTC+11 (SAKT) with the rest of
+# Sakhalin Oblast since at least 2011-09, and the North Kurils have been on
+# 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
+			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
 
-# From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
+
+# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
+# Asia/Kamchatka covers...
+# 91	RU-KAM	Kamchatka Krai
 #
-# The Zone name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
+# Note: Effective 2007-07-01, (41) Kamchatka Oblast and (82) Koryak
+# Autonomous Okrug merged to form (91, RU-KAM) Kamchatka Krai.
+
+# 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	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
-#
-# Chukotskij avtonomnyj okrug
+
+
+# From Tim Parenti (2014-07-03):
+# Asia/Anadyr covers...
+# 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
+			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
 
+
 # San Marino
 # See Europe/Rome.
 
@@ -2488,11 +2841,11 @@ Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
 Zone	Europe/Belgrade	1:22:00	-	LMT	1884
 			1:00	-	CET	1941 Apr 18 23:00
 			1:00	C-Eur	CE%sT	1945
-			1:00	-	CET	1945 May 8 2:00s
+			1:00	-	CET	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
-# Metod Kozelj reports that the legal date of
+# Metod Koželj reports that the legal date of
 # transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
-# Shanks & Pottenger don't give as much detail, so go with Kozelj.
+# Shanks & Pottenger don't give as much detail, so go with Koželj.
 			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 Link Europe/Belgrade Europe/Ljubljana	# Slovenia
@@ -2568,13 +2921,13 @@ Zone	Africa/Ceuta	-0:21:16 -	LMT	1901
 			 0:00	1:00	WEST	1918 Oct  7 23:00
 			 0:00	-	WET	1924
 			 0:00	Spain	WE%sT	1929
-			 0:00 SpainAfrica WE%sT 1984 Mar 16
+			 0:00 SpainAfrica WE%sT	1984 Mar 16
 			 1:00	-	CET	1986
 			 1:00	EU	CE%sT
 Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
-			-1:00	-	CANT	1946 Sep 30 1:00 # Canaries Time
-			 0:00	-	WET	1980 Apr  6 0:00s
-			 0:00	1:00	WEST	1980 Sep 28 0:00s
+			-1:00	-	CANT	1946 Sep 30  1:00 # Canaries T
+			 0:00	-	WET	1980 Apr  6  0:00s
+			 0:00	1:00	WEST	1980 Sep 28  0:00s
 			 0:00	EU	WE%sT
 # IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
 # Ignore this for now, as the Canaries are part of the EU.
@@ -2583,7 +2936,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
 
 # From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
 #
-# The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
+# The law "Svensk författningssamling 1878, no 14" about standard time in 1879:
 # From the beginning of 1879 (that is 01-01 00:00) the time for all
 # places in the country is "the mean solar time for the meridian at
 # three degrees, or twelve minutes of time, to the west of the
@@ -2594,7 +2947,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
 # national standard time as 01:00:14 ahead of GMT....
 #
 # About the beginning of CET in Sweden. The lawtext ("Svensk
-# forfattningssamling 1899, no 44") states, that "from the beginning
+# författningssamling 1899, no 44") states, that "from the beginning
 # of 1900... ... the same as the mean solar time for the meridian at
 # the distance of one hour of time from the meridian of the English
 # observatory at Greenwich, or at 12 minutes 14 seconds to the west
@@ -2602,7 +2955,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
 # 1899-06-16.  In short: At 1900-01-01 00:00:00 the new standard time
 # in Sweden is 01:00:00 ahead of GMT.
 #
-# 1916: The lawtext ("Svensk forfattningssamling 1916, no 124") states
+# 1916: The lawtext ("Svensk författningssamling 1916, no 124") states
 # that "1916-05-15 is considered to begin one hour earlier". It is
 # pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00....
 # Further the law says, that "1916-09-30 is considered to end one hour later".
@@ -2612,7 +2965,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
 # not available on the site (to my knowledge they are only available
 # in Swedish):  (type
 # "sommartid" without the quotes in the field "Fritext" and then click
-# the Sok-button).
+# the Sök-button).
 #
 # (2001-05-13):
 #
@@ -2627,9 +2980,9 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
-			1:00:14	-	SET	1900 Jan  1	# Swedish Time
+			1:00:14	-	SET	1900 Jan  1 # Swedish Time
 			1:00	-	CET	1916 May 14 23:00
-			1:00	1:00	CEST	1916 Oct  1 01:00
+			1:00	1:00	CEST	1916 Oct  1  1:00
 			1:00	-	CET	1980
 			1:00	EU	CE%sT
 
@@ -2637,7 +2990,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
 # From Howse:
 # By the end of the 18th century clocks and watches became commonplace
 # and their performance improved enormously.  Communities began to keep
-# mean time in preference to apparent time -- Geneva from 1780 ....
+# mean time in preference to apparent time - Geneva from 1780 ....
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 # From Whitman (who writes "Midnight?"):
 # Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
@@ -2653,7 +3006,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
 # to be wrong. This is now verified.
 #
 # I have found copies of the original ruling by the Swiss Federal
-# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
+# government, in 'Eidgenössische Gesetzessammlung 1941 and 1942' (Swiss
 # federal law collection)...
 #
 # DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
@@ -2672,7 +3025,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
 # night as an absolute novelty, because this was the first time that such
 # a thing had happened in Switzerland.
 #
-# I have also checked 1916, because one book source (Gabriel, Traite de
+# I have also checked 1916, because one book source (Gabriel, Traité de
 # l'heure dans le monde) claims that Switzerland had DST in 1916. This is
 # false, no official document could be found. Probably Gabriel got misled
 # by references to Germany, which introduced DST in 1916 for the first time.
@@ -2686,19 +3039,19 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
 # One further detail for Switzerland, which is probably out of scope for
 # most users of tzdata: The [Europe/Zurich zone] ...
 # describes all of Switzerland correctly, with the exception of
-# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
+# the Canton de Genève (Geneva, Genf). Between 1848 and 1894 Geneva did not
 # follow Bern Mean Time but kept its own local mean time.
 # To represent this, an extra zone would be needed.
 #
 # From Alois Treindl (2013-09-11):
 # The Federal regulations say
 # http://www.admin.ch/opc/de/classified-compilation/20071096/index.html
-# ... the meridian for Bern mean time ... is 7 degrees 26'22.50".
+# ... the meridian for Bern mean time ... is 7 degrees 26' 22.50".
 # Expressed in time, it is 0h29m45.5s.
 
 # From Pierre-Yves Berger (2013-09-11):
-# the "Circulaire du conseil federal" (December 11 1893)
-#  ...
+# the "Circulaire du conseil fédéral" (December 11 1893)
+# http://www.amtsdruckschriften.bar.admin.ch/viewOrigDoc.do?id=10071353
 # clearly states that the [1894-06-01] change should be done at midnight
 # but if no one is present after 11 at night, could be postponed until one
 # hour before the beginning of service.
@@ -2709,14 +3062,14 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
 # We can find no reliable source for Shanks's assertion that all of Switzerland
 # except Geneva switched to Bern Mean Time at 00:00 on 1848-09-12.  This book:
 #
-#	Jakob Messerli. Gleichmassig, punktlich, schnell: Zeiteinteilung und
+#	Jakob Messerli. Gleichmässig, pünktlich, schnell. Zeiteinteilung und
 #	Zeitgebrauch in der Schweiz im 19. Jahrhundert. Chronos, Zurich 1995,
 #	ISBN 3-905311-68-2, OCLC 717570797.
 #
 # suggests that the transition was more gradual, and that the Swiss did not
 # agree about civil time during the transition.  The timekeeping it gives the
 # most detail for is postal and telegraph time: here, federal legislation (the
-# "Bundesgesetz uber die Erstellung von elektrischen Telegraphen") passed on
+# "Bundesgesetz über die Erstellung von elektrischen Telegraphen") passed on
 # 1851-11-23, and an official implementation notice was published 1853-07-16
 # (Bundesblatt 1853, Bd. II, S. 859).  On p 72 Messerli writes that in
 # practice since July 1853 Bernese time was used in "all postal and telegraph
@@ -2730,7 +3083,7 @@ Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
 Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
-			0:29:46	-	BMT	1894 Jun # Bern Mean Time
+			0:29:46	-	BMT	1894 Jun    # Bern Mean Time
 			1:00	Swiss	CE%sT	1981
 			1:00	EU	CE%sT
 
@@ -2738,7 +3091,7 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
 
 # From Amar Devegowda (2007-01-03):
 # The time zone rules for Istanbul, Turkey have not been changed for years now.
-# ... The latest rules are available at -
+# ... The latest rules are available at:
 # http://www.timeanddate.com/worldclock/timezone.html?n=107
 # From Steffen Thorsen (2007-01-03):
 # I have been able to find press records back to 1996 which all say that
@@ -2763,8 +3116,7 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
 # (on a non-government server though) describing dates between 2002 and 2006:
 # http://www.alomaliye.com/bkk_2002_3769.htm
 
-# From Gökdeniz Karadağ (2011-03-10):
-#
+# From Gökdeniz Karadağ (2011-03-10):
 # According to the articles linked below, Turkey will change into summer
 # time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
 # This change is due to a nationwide exam on 27th.
@@ -2777,9 +3129,16 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
 # Turkish Local election....
 # http://www.sabah.com.tr/Ekonomi/2014/02/12/yaz-saatinde-onemli-degisiklik
 # ... so Turkey will move clocks forward one hour on March 31 at 3:00 a.m.
-# From Paul Eggert (2014-02-17):
-# Here is an English-language source:
-# http://www.worldbulletin.net/turkey/129016/turkey-switches-to-daylight-saving-time-march-31
+# From Randal L. Schwartz (2014-04-15):
+# Having landed on a flight from the states to Istanbul (via AMS) on March 31,
+# I can tell you that NOBODY (even the airlines) respected this timezone DST
+# change delay.  Maybe the word just didn't get out in time.
+# From Paul Eggert (2014-06-15):
+# The press reported massive confusion, as election officials obeyed the rule
+# change but cell phones (and airline baggage systems) did not.  See:
+# Kostidis M. Eventful elections in Turkey. Balkan News Agency
+# http://www.balkaneu.com/eventful-elections-turkey/ 2014-03-30.
+# I guess the best we can do is document the official time.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
@@ -2846,10 +3205,10 @@ Zone	Europe/Istanbul	1:55:52 -	LMT	1880
 			2:00	Turkey	EE%sT	1978 Oct 15
 			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
 			2:00	Turkey	EE%sT	2007
-			2:00	EU	EE%sT	2011 Mar 27 1:00u
-			2:00	-	EET	2011 Mar 28 1:00u
-			2:00	EU	EE%sT	2014 Mar 30 1:00u
-			2:00	-	EET	2014 Mar 31 1:00u
+			2:00	EU	EE%sT	2011 Mar 27  1:00u
+			2:00	-	EET	2011 Mar 28  1:00u
+			2:00	EU	EE%sT	2014 Mar 30  1:00u
+			2:00	-	EET	2014 Mar 31  1:00u
 			2:00	EU	EE%sT
 Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
 
@@ -2870,7 +3229,7 @@ Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
 # Bill number 8330 of MP from the Party of Regions Oleg Nadoshi got
 # approval from 266 deputies.
 #
-# Ukraine abolishes transter back to the winter time (in Russian)
+# Ukraine abolishes transfer back to the winter time (in Russian)
 # http://news.mail.ru/politics/6861560/
 #
 # The Ukrainians will no longer change the clock (in Russian)
@@ -2931,12 +3290,12 @@ Zone Europe/Kiev	2:02:04 -	LMT	1880
 			2:00	-	EET	1930 Jun 21
 			3:00	-	MSK	1941 Sep 20
 			1:00	C-Eur	CE%sT	1943 Nov  6
-			3:00	Russia	MSK/MSD	1990 Jul  1 2:00
-			2:00	1:00	EEST	1991 Sep 29 3:00
+			3:00	Russia	MSK/MSD	1990 Jul  1  2:00
+			2:00	1:00	EEST	1991 Sep 29  3:00
 			2:00	E-Eur	EE%sT	1995
 			2:00	EU	EE%sT
 # Ruthenia used CET 1990/1991.
-# "Uzhhorod" is the transliteration of the Ukrainian name, but
+# "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but
 # "Uzhgorod" is more common in English.
 Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
 			1:00	-	CET	1940
@@ -2944,8 +3303,8 @@ Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
 			1:00	1:00	CEST	1944 Oct 26
 			1:00	-	CET	1945 Jun 29
 			3:00	Russia	MSK/MSD	1990
-			3:00	-	MSK	1990 Jul  1 2:00
-			1:00	-	CET	1991 Mar 31 3:00
+			3:00	-	MSK	1990 Jul  1  2:00
+			1:00	-	CET	1991 Mar 31  3:00
 			2:00	-	EET	1992
 			2:00	E-Eur	EE%sT	1995
 			2:00	EU	EE%sT
@@ -2959,42 +3318,9 @@ Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
 			2:00	-	EET	1930 Jun 21
 			3:00	-	MSK	1941 Aug 25
 			1:00	C-Eur	CE%sT	1943 Oct 25
-			3:00	Russia	MSK/MSD	1991 Mar 31 2:00
+			3:00	Russia	MSK/MSD	1991 Mar 31  2:00
 			2:00	E-Eur	EE%sT	1995
 			2:00	EU	EE%sT
-# Central Crimea used Moscow time 1994/1997.
-Zone Europe/Simferopol	2:16:24 -	LMT	1880
-			2:16	-	SMT	1924 May  2 # Simferopol Mean T
-			2:00	-	EET	1930 Jun 21
-			3:00	-	MSK	1941 Nov
-			1:00	C-Eur	CE%sT	1944 Apr 13
-			3:00	Russia	MSK/MSD	1990
-			3:00	-	MSK	1990 Jul  1 2:00
-			2:00	-	EET	1992
-# From Paul Eggert (2006-03-22):
-# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
-# from Kiev to Moscow time sometime after the January 1994 elections.
-# Shanks (1999) says "date of change uncertain", but implies that it happened
-# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
-# 1994-09-25 03:00, but that can't be right.  For now, guess it
-# changed in May.
-			2:00	E-Eur	EE%sT	1994 May
-# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
-			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
-			3:00	1:00	MSD	1996 Oct 27 3:00s
-# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
-# Assume it happened in March by not changing the clocks.
-			3:00	Russia	MSK/MSD	1997
-			3:00	-	MSK	1997 Mar lastSun 1:00u
-# From Alexander Krivenyshev (2014-03-17):
-# time change at 2:00 (2am) on March 30, 2014
-# http://vz.ru/news/2014/3/17/677464.html
-# From Paul Eggert (2014-03-30):
-# Simferopol and Sevastopol reportedly changed their central town clocks
-# late the previous day, but this appears to have been ceremonial
-# and the discrepancies are small enough to not worry about.
-			2:00	EU	EE%sT	2014 Mar 30 2:00
-			4:00	-	MSK
 
 # Vatican City
 # See Europe/Rome.
@@ -3018,7 +3344,7 @@ Zone Europe/Simferopol	2:16:24 -	LMT	1880
 # ...
 #
 # ...the European time rules are...standardized since 1981, when
-# most European coun[tr]ies started DST.  Before that year, only
+# most European countries started DST.  Before that year, only
 # a few countries (UK, France, Italy) had DST, each according
 # to own national rules.  In 1981, however, DST started on
 # 'Apr firstSun', and not on 'Mar lastSun' as in the following
@@ -3026,7 +3352,7 @@ Zone Europe/Simferopol	2:16:24 -	LMT	1880
 # But also since 1981 there are some more national exceptions
 # than listed in 'europe': Switzerland, for example, joined DST
 # one year later, Denmark ended DST on 'Oct 1' instead of 'Sep
-# lastSun' in 1981---I don't know how they handle now.
+# lastSun' in 1981 - I don't know how they handle now.
 #
 # Finally, DST ist always from 'Apr 1' to 'Oct 1' in the
 # Soviet Union (as far as I know).
diff --git a/jdk/make/data/tzdata/factory b/jdk/make/data/tzdata/factory
index 813d99a1f1f..0a6041db07e 100644
--- a/jdk/make/data/tzdata/factory
+++ b/jdk/make/data/tzdata/factory
@@ -21,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
diff --git a/jdk/make/data/tzdata/iso3166.tab b/jdk/make/data/tzdata/iso3166.tab
index 28fb64b647e..63eadcbd0c5 100644
--- a/jdk/make/data/tzdata/iso3166.tab
+++ b/jdk/make/data/tzdata/iso3166.tab
@@ -26,21 +26,21 @@
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 #
-# From Paul Eggert (2013-05-27):
+# From Paul Eggert (2014-07-18):
+# This file contains a table of two-letter country codes.  Columns are
+# separated by a single tab.  Lines beginning with '#' are comments.
+# Although all text currently uses ASCII encoding, this is planned to
+# change to UTF-8 soon.  The columns of the table are as follows:
 #
-# This file contains a table with the following columns:
 # 1.  ISO 3166-1 alpha-2 country code, current as of
-#     ISO 3166-1 Newsletter VI-15 (2013-05-10).  See: Updates on ISO 3166
+#     ISO 3166-1 Newsletter VI-16 (2013-07-11).  See: Updates on ISO 3166
 #   http://www.iso.org/iso/home/standards/country_codes/updates_on_iso_3166.htm
 # 2.  The usual English name for the coded region,
 #     chosen so that alphabetic sorting of subsets produces helpful lists.
 #     This is not the same as the English name in the ISO 3166 tables.
 #
-# Columns are separated by a single tab.
 # The table is sorted by country code.
 #
-# Lines beginning with `#' are comments.
-#
 # This table is intended as an aid for users, to help them select time
 # zone data appropriate for their practical needs.  It is not intended
 # to take or endorse any position on legal or territorial claims.
diff --git a/jdk/make/data/tzdata/leapseconds b/jdk/make/data/tzdata/leapseconds
index b423135b942..d38abd6a4bd 100644
--- a/jdk/make/data/tzdata/leapseconds
+++ b/jdk/make/data/tzdata/leapseconds
@@ -21,7 +21,7 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# Allowance for leapseconds added to each timezone file.
+# Allowance for leap seconds added to each time zone file.
 
 # This file is in the public domain.
 
@@ -31,7 +31,7 @@
 # you should be able to pick up leap-seconds.list from a secondary NIST server.
 # For more about leap-seconds.list, please see
 # The NTP Timescale and Leap Seconds
-# .
+# http://www.eecis.udel.edu/~mills/leap.html
 
 # The International Earth Rotation Service periodically uses leap seconds
 # to keep UTC to within 0.9 s of UT1
diff --git a/jdk/make/data/tzdata/northamerica b/jdk/make/data/tzdata/northamerica
index dc0c2e92cff..0dc714aa92d 100644
--- a/jdk/make/data/tzdata/northamerica
+++ b/jdk/make/data/tzdata/northamerica
@@ -21,15 +21,15 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
 # also includes Central America and the Caribbean
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
 # From Paul Eggert (1999-03-22):
 # A reliable and entertaining source about time zones is
@@ -78,13 +78,13 @@
 #	to push people into bed earlier, and get them up earlier, to make
 #	them healthy, wealthy and wise in spite of themselves.
 #
-#	-- Robertson Davies, The diary of Samuel Marchbanks,
+#	 -- Robertson Davies, The diary of Samuel Marchbanks,
 #	   Clarke, Irwin (1947), XIX, Sunday
 #
 # For more about the first ten years of DST in the United States, see
-# Robert Garland's 
-# Ten years of daylight saving from the Pittsburgh standpoint
-# (Carnegie Library of Pittsburgh, 1927).
+# Robert Garland, Ten years of daylight saving from the Pittsburgh standpoint
+# (Carnegie Library of Pittsburgh, 1927).
+# http://www.clpgh.org/exhibit/dst.html
 #
 # Shanks says that DST was called "War Time" in the US in 1918 and 1919.
 # However, DST was imposed by the Standard Time Act of 1918, which
@@ -103,11 +103,11 @@
 # From Arthur David Olson (2000-09-25):
 # Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
 # In the introduction, Oboler spoke of "Eastern Peace Time."
-# An AltaVista search turned up
-# :
+# An AltaVista search turned up:
+# http://rowayton.org/rhs/hstaug45.html
 # "When the time is announced over the radio now, it is 'Eastern Peace
 # Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
-#  (August 1945) by way of confirmation.
+# (August 1945) by way of confirmation.
 
 # From Joseph Gallant citing
 # George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
@@ -205,7 +205,7 @@ Zone	PST8PDT		 -8:00	US	P%sT
 # USA  ALASKA STD    9 H  BEHIND UTC    MOST OF ALASKA     (AKST)
 # USA  ALASKA STD    8 H  BEHIND UTC    APR 3 - OCT 30 (AKDT)
 # USA  ALEUTIAN     10 H  BEHIND UTC    ISLANDS WEST OF 170W
-# USA  - " -         9 H  BEHIND UTC    APR 3 - OCT 30
+# USA    "           9 H  BEHIND UTC    APR 3 - OCT 30
 # USA  HAWAII       10 H  BEHIND UTC
 # USA  BERING       11 H  BEHIND UTC    SAMOA, MIDWAY
 
@@ -258,19 +258,19 @@ Zone	PST8PDT		 -8:00	US	P%sT
 # The following was signed into law on 2005-08-08.
 #
 # H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
-#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
+#   (a) Amendment.--Section 3(a) of the Uniform Time Act of 1966 (15
 #   U.S.C. 260a(a)) is amended--
-#     (1) by striking 'first Sunday of April' and inserting 'second
-#     Sunday of March'; and
-#     (2) by striking 'last Sunday of October' and inserting 'first
+#     (1) by striking "first Sunday of April" and inserting "second
+#     Sunday of March"; and
+#     (2) by striking "last Sunday of October" and inserting "first
 #     Sunday of November'.
-#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
+#   (b) Effective Date.--Subsection (a) shall take effect 1 year after the
 #   date of enactment of this Act or March 1, 2007, whichever is later.
-#   (c) Report to Congress- Not later than 9 months after the effective
+#   (c) Report to Congress.--Not later than 9 months after the effective
 #   date stated in subsection (b), the Secretary shall report to Congress
 #   on the impact of this section on energy consumption in the United
 #   States.
-#   (d) Right to Revert- Congress retains the right to revert the
+#   (d) Right to Revert.--Congress retains the right to revert the
 #   Daylight Saving Time back to the 2005 time schedules once the
 #   Department study is complete.
 
@@ -292,7 +292,7 @@ Zone	PST8PDT		 -8:00	US	P%sT
 
 # From Paul Eggert (2005-08-26):
 # According to today's Huntsville Times
-# 
+# http://www.al.com/news/huntsvilletimes/index.ssf?/base/news/1125047783228320.xml&coll=1
 # a few towns on Alabama's "eastern border with Georgia, such as Phenix City
 # in Russell County, Lanett in Chambers County and some towns in Lee County,
 # set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
@@ -347,15 +347,15 @@ Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
 			-6:00	US	C%sT	1920
-			-6:00	Chicago	C%sT	1936 Mar  1 2:00
-			-5:00	-	EST	1936 Nov 15 2:00
+			-6:00	Chicago	C%sT	1936 Mar  1  2:00
+			-5:00	-	EST	1936 Nov 15  2:00
 			-6:00	Chicago	C%sT	1942
 			-6:00	US	C%sT	1946
 			-6:00	Chicago	C%sT	1967
 			-6:00	US	C%sT
 # Oliver County, ND switched from mountain to central time on 1992-10-25.
 Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
-			-7:00	US	M%sT	1992 Oct 25 02:00
+			-7:00	US	M%sT	1992 Oct 25  2:00
 			-6:00	US	C%sT
 # Morton County, ND, switched from mountain to central time on
 # 2003-10-26, except for the area around Mandan which was already central time.
@@ -364,29 +364,26 @@ Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
 # Jones, Mellette, and Todd Counties in South Dakota;
 # but in practice these other counties were already observing central time.
 # See .
-Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
-			-7:00	US	M%sT	2003 Oct 26 02:00
+Zone America/North_Dakota/New_Salem -6:45:39 - LMT	1883 Nov 18 12:14:21
+			-7:00	US	M%sT	2003 Oct 26  2:00
 			-6:00	US	C%sT
 
 # From Josh Findley (2011-01-21):
 # ...it appears that Mercer County, North Dakota, changed from the
 # mountain time zone to the central time zone at the last transition from
 # daylight-saving to standard time (on Nov. 7, 2010):
-# 
 # http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm
-# 
-# 
 # http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html
-# 
 
 # From Andy Lipscomb (2011-01-24):
 # ...according to the Census Bureau, the largest city is Beulah (although
 # it's commonly referred to as Beulah-Hazen, with Hazen being the next
 # largest city in Mercer County).  Google Maps places Beulah's city hall
-# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07".
+# at 47 degrees 15' 51" N, 101 degrees 46' 40" W, which yields an offset
+# of 6h47'07".
 
-Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53
-			-7:00	US	M%sT	2010 Nov  7 2:00
+Zone America/North_Dakota/Beulah -6:47:07 - LMT	1883 Nov 18 12:12:53
+			-7:00	US	M%sT	2010 Nov  7  2:00
 			-6:00	US	C%sT
 
 # US mountain time, represented by Denver
@@ -448,15 +445,18 @@ Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
 # was destroyed in 1805 by a Yakutat-kon war party.)  However, there
 # were nearby inhabitants in some cases and for our purposes perhaps
 # it's best to simply use the official transition.
-#
 
-# From Steve Ferguson (2011-01-31):
-# The author lives in Alaska and many of the references listed are only
-# available to Alaskan residents.
+# From Paul Eggert (2014-07-18):
+# One opinion of the early-1980s turmoil in Alaska over time zones and
+# daylight saving time appeared as graffiti on a Juneau airport wall:
+# "Welcome to Juneau.  Please turn your watch back to the 19th century."
+# See: Turner W. Alaska's four time zones now two. NY Times 1983-11-01.
+# http://www.nytimes.com/1983/11/01/us/alaska-s-four-time-zones-now-two.html
 #
-# 
-# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
-# 
+# Steve Ferguson (2011-01-31) referred to the following source:
+# Norris F. Keeping time in Alaska: national directives, local response.
+# Alaska History 2001;16(1-2).
+# http://alaskahistoricalsociety.org/discover-alaska/glimpses-of-the-past/keeping-time-in-alaska/
 
 # From Arthur David Olson (2011-02-01):
 # Here's database-relevant material from the 2001 "Alaska History" article:
@@ -482,12 +482,10 @@ Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
 # From Arthur David Olson (2011-02-09):
 # I just spoke by phone with a staff member at the Metlakatla Indian
 # Community office (using contact information available at
-# 
 # http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
-# ).
 # It's shortly after 1:00 here on the east coast of the United States;
 # the staffer said it was shortly after 10:00 there. When I asked whether
-# that meant they were on Pacific time, they said no--they were on their
+# that meant they were on Pacific time, they said no - they were on their
 # own time. I asked about daylight saving; they said it wasn't used. I
 # did not inquire about practices in the past.
 
@@ -501,9 +499,9 @@ Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
 			 -8:00	-	PST	1942
 			 -8:00	US	P%sT	1946
 			 -8:00	-	PST	1969
-			 -8:00	US	P%sT	1980 Apr 27 2:00
-			 -9:00	US	Y%sT	1980 Oct 26 2:00
-			 -8:00	US	P%sT	1983 Oct 30 2:00
+			 -8:00	US	P%sT	1980 Apr 27  2:00
+			 -9:00	US	Y%sT	1980 Oct 26  2:00
+			 -8:00	US	P%sT	1983 Oct 30  2:00
 			 -9:00	US	Y%sT	1983 Nov 30
 			 -9:00	US	AK%sT
 Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
@@ -511,7 +509,7 @@ Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
 			 -8:00	-	PST	1942
 			 -8:00	US	P%sT	1946
 			 -8:00	-	PST	1969
-			 -8:00	US	P%sT	1983 Oct 30 2:00
+			 -8:00	US	P%sT	1983 Oct 30  2:00
 			 -9:00	US	Y%sT	1983 Nov 30
 			 -9:00	US	AK%sT
 Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
@@ -519,8 +517,8 @@ Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
 			 -8:00	-	PST	1942
 			 -8:00	US	P%sT	1946
 			 -8:00	-	PST	1969
-			 -8:00	US	P%sT	1983 Oct 30 2:00
-			 -8:00	-	MeST
+			 -8:00	US	P%sT	1983 Oct 30  2:00
+			 -8:00	-	PST
 Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
 			 -9:18:55 -	LMT	1900 Aug 20 12:00
 			 -9:00	-	YST	1942
@@ -535,7 +533,7 @@ Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
 			-10:00	US	CAT/CAPT 1946 # Peace
 			-10:00	-	CAT	1967 Apr
 			-10:00	-	AHST	1969
-			-10:00	US	AH%sT	1983 Oct 30 2:00
+			-10:00	US	AH%sT	1983 Oct 30  2:00
 			 -9:00	US	Y%sT	1983 Nov 30
 			 -9:00	US	AK%sT
 Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
@@ -544,7 +542,7 @@ Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
 			-11:00	US	N%sT	1946
 			-11:00	-	NST	1967 Apr
 			-11:00	-	BST	1969
-			-11:00	US	B%sT	1983 Oct 30 2:00
+			-11:00	US	B%sT	1983 Oct 30  2:00
 			 -9:00	US	Y%sT	1983 Nov 30
 			 -9:00	US	AK%sT
 Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
@@ -553,7 +551,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
 			-11:00	US	N%sT	1946
 			-11:00	-	NST	1967 Apr
 			-11:00	-	BST	1969
-			-11:00	US	B%sT	1983 Oct 30 2:00
+			-11:00	US	B%sT	1983 Oct 30  2:00
 			-10:00	US	AH%sT	1983 Nov 30
 			-10:00	US	HA%sT
 # The following switches don't quite make our 1970 cutoff.
@@ -571,7 +569,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
 #  Minutes of the Unalaska City Council Meeting, January 10, 1967:
 #  "Except for St. Paul and Akutan, Unalaska is the only important
 #  location not on Alaska Standard Time.  The following resolution was
-#  made by William Robinson and seconded by Henry Swanson:  Be it
+#  made by William Robinson and seconded by Henry Swanson: Be it
 #  resolved that the City of Unalaska hereby goes to Alaska Standard
 #  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
 #  January 14, Alaska Standard Time.)  This resolution was passed with
@@ -583,9 +581,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
 # "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
 # of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09,
 # the article is available at
-# 
 # http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf
-# 
 # and indicates that standard time was adopted effective noon, January
 # 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
 # saving for the period between the last Sunday of each April and the
@@ -606,7 +602,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
 # year, the standard time of this Territory shall be advanced one
 # hour...This Act shall take effect upon its approval. Approved this 26th
 # day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of
-# Hawaii." Page 172:  "Act 163...Act 90 of the Session Laws of 1933 is
+# Hawaii." Page 172: "Act 163...Act 90 of the Session Laws of 1933 is
 # hereby repealed...This Act shall take effect upon its approval, upon
 # which date the standard time of this Territory shall be restored to
 # that existing immediately prior to the taking effect of said Act 90.
@@ -616,14 +612,14 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
 # Note that 1933-05-21 was a Sunday.
 # We're left to guess the time of day when Act 163 was approved; guess noon.
 
-Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
-			-10:30	-	HST	1933 Apr 30 2:00 #Laws 1933
-			-10:30	1:00	HDT	1933 May 21 12:00 #Laws 1933+12
-			-10:30	-	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
-			-10:30	1:00	HDT	1945 Sep 30 2:00 #Schmitt&Cox+2
-			-10:30	-	HST	1947 Jun  8 2:00 #Schmitt&Cox+2
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00
+			-10:30	-	HST	1933 Apr 30  2:00
+			-10:30	1:00	HDT	1933 May 21 12:00
+			-10:30	-	HST	1942 Feb  9  2:00
+			-10:30	1:00	HDT	1945 Sep 30  2:00
+			-10:30	-	HST	1947 Jun  8  2:00
 			-10:00	-	HST
-
 Link Pacific/Honolulu Pacific/Johnston
 
 # Now we turn to US areas that have diverged from the consensus since 1970.
@@ -633,9 +629,9 @@ Link Pacific/Honolulu Pacific/Johnston
 # From Paul Eggert (2002-10-20):
 #
 # The information in the rest of this paragraph is derived from the
-# 
-# Daylight Saving Time web page (2002-01-23) maintained by the
-# Arizona State Library, Archives and Public Records.
+# Daylight Saving Time web page
+#  (2002-01-23)
+# maintained by the Arizona State Library, Archives and Public Records.
 # Between 1944-01-01 and 1944-04-01 the State of Arizona used standard
 # time, but by federal law railroads, airlines, bus lines, military
 # personnel, and some engaged in interstate commerce continued to
@@ -649,10 +645,11 @@ Link Pacific/Honolulu Pacific/Johnston
 # Shanks says the 1944 experiment came to an end on 1944-03-17.
 # Go with the Arizona State Library instead.
 
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
-			-7:00	US	M%sT	1944 Jan  1 00:01
-			-7:00	-	MST	1944 Apr  1 00:01
-			-7:00	US	M%sT	1944 Oct  1 00:01
+			-7:00	US	M%sT	1944 Jan  1  0:01
+			-7:00	-	MST	1944 Apr  1  0:01
+			-7:00	US	M%sT	1944 Oct  1  0:01
 			-7:00	-	MST	1967
 			-7:00	US	M%sT	1968 Mar 21
 			-7:00	-	MST
@@ -676,24 +673,22 @@ Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
 #
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
-			-8:00	US	P%sT	1923 May 13 2:00
+			-8:00	US	P%sT	1923 May 13  2:00
 			-7:00	US	M%sT	1974
-			-7:00	-	MST	1974 Feb  3 2:00
+			-7:00	-	MST	1974 Feb  3  2:00
 			-7:00	US	M%sT
 
 # Indiana
 #
 # For a map of Indiana's time zone regions, see:
-# 
-# What time is it in Indiana?
-#  (2006-03-01)
+# http://en.wikipedia.org/wiki/Time_in_Indiana
 #
 # From Paul Eggert (2007-08-17):
 # Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
 # with the following exceptions:
 #
 # - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
-#   Vandenburgh, and Warrick counties have been like America/Chicago.
+#   Vanderburgh, and Warrick counties have been like America/Chicago.
 #
 # - Dearborn and Ohio counties have been like America/New_York.
 #
@@ -712,22 +707,16 @@ Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
 # that they would be ambiguous if we left them at the 'America' level.
 # So we reluctantly put them all in a subdirectory 'America/Indiana'.
 
-# From Paul Eggert (2005-08-16):
-# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
-
-# From Nathan Stratton Treadway (2006-03-30):
-# http://www.dot.gov/affairs/dot0406.htm [3705 B]
-# From Deborah Goldsmith (2006-01-18):
-# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
-# From Paul Eggert (2006-01-20):
-# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
+# From Paul Eggert (2014-06-26):
+# https://www.federalregister.gov/articles/2006/01/20/06-563/standard-time-zone-boundary-in-the-state-of-indiana
+# says "DOT is relocating the time zone boundary in Indiana to move Starke,
 # Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
 # Eastern Time Zone to the Central Time Zone.... The effective date of
-# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
+# this rule is 2 a.m. EST Sunday, April 2, 2006, which is the
 # changeover date from standard time to Daylight Saving Time."
-# Strictly speaking, this means the affected counties will change their
-# clocks twice that night, but this obviously is in error.  The intent
-# is that 01:59:59 EST be followed by 02:00:00 CDT.
+# Strictly speaking, this meant the affected counties changed their
+# clocks twice that night, but this obviously was in error.  The intent
+# was that 01:59:59 EST be followed by 02:00:00 CDT.
 
 # From Gwillim Law (2007-02-10):
 # The Associated Press has been reporting that Pulaski County, Indiana is
@@ -739,13 +728,13 @@ Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
 Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
 Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
+Zone America/Indiana/Indianapolis -5:44:38 - LMT	1883 Nov 18 12:15:22
 			-6:00	US	C%sT	1920
 			-6:00 Indianapolis C%sT	1942
 			-6:00	US	C%sT	1946
-			-6:00 Indianapolis C%sT	1955 Apr 24 2:00
-			-5:00	-	EST	1957 Sep 29 2:00
-			-6:00	-	CST	1958 Apr 27 2:00
+			-6:00 Indianapolis C%sT	1955 Apr 24  2:00
+			-5:00	-	EST	1957 Sep 29  2:00
+			-6:00	-	CST	1958 Apr 27  2:00
 			-5:00	-	EST	1969
 			-5:00	US	E%sT	1971
 			-5:00	-	EST	2006
@@ -761,10 +750,10 @@ Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
 			-6:00	US	C%sT	1951
-			-6:00	Marengo	C%sT	1961 Apr 30 2:00
+			-6:00	Marengo	C%sT	1961 Apr 30  2:00
 			-5:00	-	EST	1969
-			-5:00	US	E%sT	1974 Jan  6 2:00
-			-6:00	1:00	CDT	1974 Oct 27 2:00
+			-5:00	US	E%sT	1974 Jan  6  2:00
+			-6:00	1:00	CDT	1974 Oct 27  2:00
 			-5:00	US	E%sT	1976
 			-5:00	-	EST	2006
 			-5:00	US	E%sT
@@ -785,11 +774,11 @@ Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
 			-6:00	US	C%sT	1946
-			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
+			-6:00 Vincennes	C%sT	1964 Apr 26  2:00
 			-5:00	-	EST	1969
 			-5:00	US	E%sT	1971
-			-5:00	-	EST	2006 Apr  2 2:00
-			-6:00	US	C%sT	2007 Nov  4 2:00
+			-5:00	-	EST	2006 Apr  2  2:00
+			-6:00	US	C%sT	2007 Nov  4  2:00
 			-5:00	US	E%sT
 #
 # Perry County, Indiana, switched from eastern to central time in April 2006.
@@ -806,10 +795,10 @@ Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
 			-6:00	US	C%sT	1946
-			-6:00 Perry	C%sT	1964 Apr 26 2:00
+			-6:00 Perry	C%sT	1964 Apr 26  2:00
 			-5:00	-	EST	1969
 			-5:00	US	E%sT	1971
-			-5:00	-	EST	2006 Apr  2 2:00
+			-5:00	-	EST	2006 Apr  2  2:00
 			-6:00	US	C%sT
 #
 # Pike County, Indiana moved from central to eastern time in 1977,
@@ -822,11 +811,11 @@ Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
 			-6:00	US	C%sT	1955
-			-6:00	Pike	C%sT	1965 Apr 25 2:00
-			-5:00	-	EST	1966 Oct 30 2:00
-			-6:00	US	C%sT	1977 Oct 30 2:00
-			-5:00	-	EST	2006 Apr  2 2:00
-			-6:00	US	C%sT	2007 Nov  4 2:00
+			-6:00	Pike	C%sT	1965 Apr 25  2:00
+			-5:00	-	EST	1966 Oct 30  2:00
+			-6:00	US	C%sT	1977 Oct 30  2:00
+			-5:00	-	EST	2006 Apr  2  2:00
+			-6:00	US	C%sT	2007 Nov  4  2:00
 			-5:00	US	E%sT
 #
 # Starke County, Indiana moved from central to eastern time in 1991,
@@ -844,10 +833,10 @@ Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
 			-6:00	US	C%sT	1947
-			-6:00	Starke	C%sT	1962 Apr 29 2:00
-			-5:00	-	EST	1963 Oct 27 2:00
-			-6:00	US	C%sT	1991 Oct 27 2:00
-			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	Starke	C%sT	1962 Apr 29  2:00
+			-5:00	-	EST	1963 Oct 27  2:00
+			-6:00	US	C%sT	1991 Oct 27  2:00
+			-5:00	-	EST	2006 Apr  2  2:00
 			-6:00	US	C%sT
 #
 # Pulaski County, Indiana, switched from eastern to central time in
@@ -860,17 +849,17 @@ Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
 			-6:00	US	C%sT	1946
-			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
+			-6:00	Pulaski	C%sT	1961 Apr 30  2:00
 			-5:00	-	EST	1969
 			-5:00	US	E%sT	1971
-			-5:00	-	EST	2006 Apr  2 2:00
-			-6:00	US	C%sT	2007 Mar 11 2:00
+			-5:00	-	EST	2006 Apr  2  2:00
+			-6:00	US	C%sT	2007 Mar 11  2:00
 			-5:00	US	E%sT
 #
 # Switzerland County, Indiana, did not observe DST from 1973 through 2005.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
-			-6:00	US	C%sT	1954 Apr 25 2:00
+			-6:00	US	C%sT	1954 Apr 25  2:00
 			-5:00	-	EST	1969
 			-5:00	US	E%sT	1973
 			-5:00	-	EST	2006
@@ -891,18 +880,17 @@ Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
 			-6:00	US	C%sT	1921
 			-6:00 Louisville C%sT	1942
 			-6:00	US	C%sT	1946
-			-6:00 Louisville C%sT	1961 Jul 23 2:00
+			-6:00 Louisville C%sT	1961 Jul 23  2:00
 			-5:00	-	EST	1968
-			-5:00	US	E%sT	1974 Jan  6 2:00
-			-6:00	1:00	CDT	1974 Oct 27 2:00
+			-5:00	US	E%sT	1974 Jan  6  2:00
+			-6:00	1:00	CDT	1974 Oct 27  2:00
 			-5:00	US	E%sT
 #
 # Wayne County, Kentucky
 #
-# From
-# 
-# Lake Cumberland LIFE
-#  (1999-01-29) via WKYM-101.7:
+# From Lake Cumberland LIFE
+# http://www.lake-cumberland.com/life/archive/news990129time.shtml
+# (1999-01-29) via WKYM-101.7:
 # Clinton County has joined Wayne County in asking the DoT to change from
 # the Central to the Eastern time zone....  The Wayne County government made
 # the same request in December.  And while Russell County officials have not
@@ -919,9 +907,8 @@ Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
 #
 # From Paul Eggert (2001-07-16):
 # The final rule was published in the
-# 
-# Federal Register 65, 160 (2000-08-17), page 50154-50158.
-# 
+# Federal Register 65, 160 (2000-08-17), pp 50154-50158.
+# http://frwebgate.access.gpo.gov/cgi-bin/getdoc.cgi?dbname=2000_register&docid=fr17au00-22
 #
 Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
 			-6:00	US	C%sT	1946
@@ -946,9 +933,8 @@ Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
 # See America/North_Dakota/Center for the Oliver County, ND change.
 # West Wendover, NV officially switched from Pacific to mountain time on
 # 1999-10-31.  See the
-# 
-# Federal Register 64, 203 (1999-10-21), page 56705-56707.
-# 
+# Federal Register 64, 203 (1999-10-21), pp 56705-56707.
+# http://frwebgate.access.gpo.gov/cgi-bin/getdoc.cgi?dbname=1999_register&docid=fr21oc99-15
 # However, the Federal Register says that West Wendover already operated
 # on mountain time, and the rule merely made this official;
 # hence a separate tz entry is not needed.
@@ -986,12 +972,12 @@ Rule	Detroit	1967	only	-	Jun	14	2:00	1:00	D
 Rule	Detroit	1967	only	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Detroit	-5:32:11 -	LMT	1905
-			-6:00	-	CST	1915 May 15 2:00
+			-6:00	-	CST	1915 May 15  2:00
 			-5:00	-	EST	1942
 			-5:00	US	E%sT	1946
 			-5:00	Detroit	E%sT	1973
 			-5:00	US	E%sT	1975
-			-5:00	-	EST	1975 Apr 27 2:00
+			-5:00	-	EST	1975 Apr 27  2:00
 			-5:00	US	E%sT
 #
 # Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
@@ -1004,8 +990,8 @@ Rule Menominee	1966	only	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 			-6:00	US	C%sT	1946
-			-6:00 Menominee	C%sT	1969 Apr 27 2:00
-			-5:00	-	EST	1973 Apr 29 2:00
+			-6:00 Menominee	C%sT	1969 Apr 27  2:00
+			-5:00	-	EST	1973 Apr 29  2:00
 			-6:00	US	C%sT
 
 # Navassa
@@ -1042,9 +1028,9 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 #	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
 #	which I found in the UCLA library.
 #
-#	
 #	William Willett, The Waste of Daylight, 19th edition
-#	 (1914-03)
+#	
+#	[PDF] (1914-03)
 #
 #	Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
 #	.
@@ -1053,11 +1039,11 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 
 # Canada
 
-# From Alain LaBont (1994-11-14):
+# From Alain LaBonté (1994-11-14):
 # I post here the time zone abbreviations standardized in Canada
 # for both English and French in the CAN/CSA-Z234.4-89 standard....
 #
-#	UTC	Standard time	Daylight savings time
+#	UTC	Standard time	Daylight saving time
 #	offset	French	English	French	English
 #	-2:30	-	-	HAT	NDT
 #	-3	-	-	HAA	ADT
@@ -1070,7 +1056,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 #	-9	HNY	YST	-	-
 #
 #	HN: Heure Normale	ST: Standard Time
-#	HA: Heure Avance	DT: Daylight saving Time
+#	HA: Heure Avancée	DT: Daylight saving Time
 #
 #	A: de l'Atlantique	Atlantic
 #	C: du Centre		Central
@@ -1085,7 +1071,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 # From Paul Eggert (1994-11-22):
 # Alas, this sort of thing must be handled by localization software.
 
-# Unless otherwise specified, the data for Canada are all from Shanks
+# Unless otherwise specified, the data entries for Canada are all from Shanks
 # & Pottenger.
 
 # From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
@@ -1134,15 +1120,15 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 
 # From Paul Eggert (2006-04-25):
 # H. David Matthews and Mary Vincent's map
-# 
 # "It's about TIME", _Canadian Geographic_ (September-October 1998)
-#  contains detailed boundaries for regions observing nonstandard
+# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
+# contains detailed boundaries for regions observing nonstandard
 # time and daylight saving time arrangements in Canada circa 1998.
 #
-# INMS, the Institute for National Measurement Standards in Ottawa, has 
+# INMS, the Institute for National Measurement Standards in Ottawa, has
 # information about standard and daylight saving time zones in Canada.
-#  (updated periodically).
+# http://inms-ienm.nrc-cnrc.gc.ca/en/time_services/daylight_saving_e.php
+# (updated periodically).
 # Its unofficial information is often taken from Matthews and Vincent.
 
 # From Paul Eggert (2006-06-27):
@@ -1151,9 +1137,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
 
 # From Chris Walton (2011-12-01)
 # In the first of Tammy Hardwick's articles
-# 
 # http://www.ilovecreston.com/?p=articles&t=spec&ar=260
-# 
 # she quotes the Friday November 1/1918 edition of the Creston Review.
 # The quote includes these two statements:
 # 'Sunday the CPR went back to the old system of time...'
@@ -1221,9 +1205,7 @@ Rule	StJohns	1960	1986	-	Oct	lastSun	2:00	0	S
 # Time to Standard Time and from Standard Time to Daylight Savings Time
 # now occurs at 2:00AM.
 # ...
-# 
 # http://www.assembly.nl.ca/legislation/sr/annualstatutes/2011/1106.chp.htm
-# 
 # ...
 # MICHAEL PELLEY  |  Manager of Enterprise Architecture - Solution Delivery
 # Office of the Chief Information Officer
@@ -1259,7 +1241,7 @@ Zone America/Goose_Bay	-4:01:40 -	LMT	1884 # Happy Valley-Goose Bay
 			-3:30	-	NST	1936
 			-3:30	StJohns	N%sT	1942 May 11
 			-3:30	Canada	N%sT	1946
-			-3:30	StJohns	N%sT	1966 Mar 15 2:00
+			-3:30	StJohns	N%sT	1966 Mar 15  2:00
 			-4:00	StJohns	A%sT	2011 Nov
 			-4:00	Canada	A%sT
 
@@ -1320,7 +1302,7 @@ Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
 Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
 			-4:00	Halifax	A%sT	1918
 			-4:00	Canada	A%sT	1919
-			-4:00	Halifax	A%sT	1942 Feb  9 2:00s
+			-4:00	Halifax	A%sT	1942 Feb  9  2:00s
 			-4:00	Canada	A%sT	1946
 			-4:00	Halifax	A%sT	1974
 			-4:00	Canada	A%sT
@@ -1379,7 +1361,7 @@ Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
 # meridian is supposed to observe AST, but residents as far east as
 # Natashquan use EST/EDT, and residents east of Natashquan use AST.
 # The Quebec department of justice writes in
-# "The situation in Minganie and Basse-Cote-Nord"
+# "The situation in Minganie and Basse-Côte-Nord"
 # http://www.justice.gouv.qc.ca/english/publications/generale/temps-minganie-a.htm
 # that the coastal strip from just east of Natashquan to Blanc-Sablon
 # observes Atlantic standard time all year round.
@@ -1387,7 +1369,6 @@ Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
 # says this common practice was codified into law as of 2007.
 # For lack of better info, guess this practice began around 1970, contra to
 # Shanks & Pottenger who have this region observing AST/ADT.
-# for post-1970 data America/Puerto_Rico.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
@@ -1401,18 +1382,10 @@ Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
 Rule	Mont	1924	only	-	May	17	2:00	1:00	D
 Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
 Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
-# The 1927-to-1937 rules can be expressed more simply as
-# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
-# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
-# The rules below avoid use of 24:00
-# (which pre-1998 versions of zic cannot handle).
-Rule	Mont	1927	only	-	May	1	0:00	1:00	D
-Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
-Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
-Rule	Mont	1932	only	-	May	1	0:00	1:00	D
-Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
-Rule	Mont	1933	only	-	Oct	1	0:00	0	S
-Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
+Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
+Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
+Rule	Mont	1938	1940	-	Apr	lastSun	0:00	1:00	D
+Rule	Mont	1938	1939	-	Sep	lastSun	0:00	0	S
 Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
 Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
 Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
@@ -1426,7 +1399,7 @@ Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
 Zone America/Montreal	-4:54:16 -	LMT	1884
 			-5:00	Mont	E%sT	1918
 			-5:00	Canada	E%sT	1919
-			-5:00	Mont	E%sT	1942 Feb  9 2:00s
+			-5:00	Mont	E%sT	1942 Feb  9  2:00s
 			-5:00	Canada	E%sT	1946
 			-5:00	Mont	E%sT	1974
 			-5:00	Canada	E%sT
@@ -1448,7 +1421,7 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
 # have already done so.  In Orillia DST was to run until Saturday,
 # 1912-08-31 (no time mentioned), but it was met with considerable
 # hostility from certain segments of the public, and was revoked after
-# only two weeks -- I copied it as Saturday, 1912-07-07, 22:00, but
+# only two weeks - I copied it as Saturday, 1912-07-07, 22:00, but
 # presumably that should be -07-06.  (1912-06-19, -07-12; also letters
 # earlier in June).
 #
@@ -1458,10 +1431,8 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
 # Mark Brader writes that an article in the 1997-10-14 Toronto Star
 # says that Atikokan, Ontario currently does not observe DST,
 # but will vote on 11-10 whether to use EST/EDT.
-# He also writes that the
-# 
-# Ontario Time Act (1990, Chapter T.9)
-# 
+# He also writes that the Ontario Time Act (1990, Chapter T.9)
+# http://www.gov.on.ca/MBS/english/publications/statregs/conttext.html
 # says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
 # Officially Atikokan is therefore on CST/CDT, and most likely this report
 # concerns a non-official time observed as a matter of local practice.
@@ -1540,9 +1511,7 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
 # The Journal of The Royal Astronomical Society of Canada,
 # volume 26, number 2 (February 1932) and, as of 2010-07-17,
 # was available at
-# 
 # http://adsabs.harvard.edu/full/1932JRASC..26...49S
-# 
 #
 # It includes the text below (starting on page 57):
 #
@@ -1553,26 +1522,26 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
 # ing in 1930. The information for the province of Quebec is definite,
 # for the other provinces only approximate:
 #
-# 	Province	Daylight saving time used
+#	Province	Daylight saving time used
 # Prince Edward Island	Not used.
 # Nova Scotia		In Halifax only.
 # New Brunswick		In St. John only.
 # Quebec		In the following places:
-# 			Montreal	Lachine
-# 			Quebec		Mont-Royal
-# 			Levis		Iberville
-# 			St. Lambert	Cap de la Madeleine
-# 			Verdun		Loretteville
-# 			Westmount	Richmond
-# 			Outremont	St. Jerome
-# 			Longueuil	Greenfield Park
-# 			Arvida		Waterloo
-# 			Chambly-Canton	Beaulieu
-# 			Melbourne	La Tuque
-# 			St. Theophile	Buckingham
+#			Montreal	Lachine
+#			Quebec		Mont-Royal
+#			Lévis		Iberville
+#			St. Lambert	Cap de la Madelèine
+#			Verdun		Loretteville
+#			Westmount	Richmond
+#			Outremont	St. Jérôme
+#			Longueuil	Greenfield Park
+#			Arvida		Waterloo
+#			Chambly-Canton	Beaulieu
+#			Melbourne	La Tuque
+#			St. Théophile	Buckingham
 # Ontario		Used generally in the cities and towns along
-# 			the southerly part of the province. Not
-# 			used in the northwesterlhy part.
+#			the southerly part of the province. Not
+#			used in the northwesterly part.
 # Manitoba		Not used.
 # Saskatchewan		In Regina only.
 # Alberta		Not used.
@@ -1641,7 +1610,7 @@ Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Toronto	-5:17:32 -	LMT	1895
 			-5:00	Canada	E%sT	1919
-			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
+			-5:00	Toronto	E%sT	1942 Feb  9  2:00s
 			-5:00	Canada	E%sT	1946
 			-5:00	Toronto	E%sT	1974
 			-5:00	Canada	E%sT
@@ -1654,16 +1623,16 @@ Zone America/Thunder_Bay -5:57:00 -	LMT	1895
 			-5:00	Canada	E%sT
 Zone America/Nipigon	-5:53:04 -	LMT	1895
 			-5:00	Canada	E%sT	1940 Sep 29
-			-5:00	1:00	EDT	1942 Feb  9 2:00s
+			-5:00	1:00	EDT	1942 Feb  9  2:00s
 			-5:00	Canada	E%sT
 Zone America/Rainy_River -6:18:16 -	LMT	1895
 			-6:00	Canada	C%sT	1940 Sep 29
-			-6:00	1:00	CDT	1942 Feb  9 2:00s
+			-6:00	1:00	CDT	1942 Feb  9  2:00s
 			-6:00	Canada	C%sT
 Zone America/Atikokan	-6:06:28 -	LMT	1895
 			-6:00	Canada	C%sT	1940 Sep 29
-			-6:00	1:00	CDT	1942 Feb  9 2:00s
-			-6:00	Canada	C%sT	1945 Sep 30 2:00
+			-6:00	1:00	CDT	1942 Feb  9  2:00s
+			-6:00	Canada	C%sT	1945 Sep 30  2:00
 			-5:00	-	EST
 
 
@@ -1676,7 +1645,7 @@ Zone America/Atikokan	-6:06:28 -	LMT	1895
 # the first Sunday of April of each year and two o'clock Central
 # Standard Time in the morning of the last Sunday of October next
 # following, one hour in advance of Central Standard Time."...
-# I believe that the English legislation [of the old time act] had =
+# I believe that the English legislation [of the old time act] had
 # been assented to (March 22, 1967)....
 # Also, as far as I can tell, there was no order-in-council varying
 # the time of Daylight Saving Time for 2005 and so the provisions of
@@ -1799,12 +1768,12 @@ Rule	Swift	1959	only	-	Oct	lastSun	2:00	0	S
 Rule	Swift	1960	1961	-	Sep	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Regina	-6:58:36 -	LMT	1905 Sep
-			-7:00	Regina	M%sT	1960 Apr lastSun 2:00
+			-7:00	Regina	M%sT	1960 Apr lastSun  2:00
 			-6:00	-	CST
 Zone America/Swift_Current -7:11:20 -	LMT	1905 Sep
-			-7:00	Canada	M%sT	1946 Apr lastSun 2:00
+			-7:00	Canada	M%sT	1946 Apr lastSun  2:00
 			-7:00	Regina	M%sT	1950
-			-7:00	Swift	M%sT	1972 Apr lastSun 2:00
+			-7:00	Swift	M%sT	1972 Apr lastSun  2:00
 			-6:00	-	CST
 
 
@@ -1854,9 +1823,7 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
 # Earlier this year I stumbled across a detailed article about the time
 # keeping history of Creston; it was written by Tammy Hardwick who is the
 # manager of the Creston & District Museum. The article was written in May 2009.
-# 
 # http://www.ilovecreston.com/?p=articles&t=spec&ar=260
-# 
 # According to the article, Creston has not changed its clocks since June 1918.
 # i.e. Creston has been stuck on UTC-7 for 93 years.
 # Dawson Creek, on the other hand, changed its clocks as recently as April 1972.
@@ -1864,18 +1831,16 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
 # Unfortunately the exact date for the time change in June 1918 remains
 # unknown and will be difficult to ascertain.  I e-mailed Tammy a few months
 # ago to ask if Sunday June 2 was a reasonable guess.  She said it was just
-# as plausible as any other date (in June).  She also said that after writing the
-# article she had discovered another time change in 1916; this is the subject
-# of another article which she wrote in October 2010.
-# 
+# as plausible as any other date (in June).  She also said that after writing
+# the article she had discovered another time change in 1916; this is the
+# subject of another article which she wrote in October 2010.
 # http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56
-# 
 
 # Here is a summary of the three clock change events in Creston's history:
 # 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7)
 # Exact date unknown
 # 2. Oct 1916: switch to Pacific Standard Time (GMT-8)
-# Exact date in October unknown;  Sunday October 1 is a reasonable guess.
+# Exact date in October unknown; Sunday October 1 is a reasonable guess.
 # 3. June 1918: switch to Pacific Daylight Time (GMT-7)
 # Exact date in June unknown; Sunday June 2 is a reasonable guess.
 # note#1:
@@ -1888,9 +1853,7 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
 # There is no guarantee that Creston will remain on Mountain Standard Time
 # (UTC-7) forever.
 # The subject was debated at least once this year by the town Council.
-# 
 # http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html
-# 
 
 # During a period WWII, summer time (Daylight saying) was mandatory in Canada.
 # In Creston, that was handled by shifting the area to PST (-8:00) then applying
@@ -1917,7 +1880,7 @@ Zone America/Vancouver	-8:12:28 -	LMT	1884
 			-8:00	Canada	P%sT
 Zone America/Dawson_Creek -8:00:56 -	LMT	1884
 			-8:00	Canada	P%sT	1947
-			-8:00	Vanc	P%sT	1972 Aug 30 2:00
+			-8:00	Vanc	P%sT	1972 Aug 30  2:00
 			-7:00	-	MST
 Zone America/Creston	-7:46:04 -	LMT	1884
 			-7:00	-	MST	1916 Oct 1
@@ -1944,18 +1907,17 @@ Zone America/Creston	-7:46:04 -	LMT	1884
 
 # From Rives McDow (1999-09-04):
 # Nunavut ... moved ... to incorporate the whole territory into one time zone.
-# 
 # Nunavut moves to single time zone Oct. 31
-# 
+# http://www.nunatsiaq.com/nunavut/nvt90903_13.html
 #
 # From Antoine Leca (1999-09-06):
 # We then need to create a new timezone for the Kitikmeot region of Nunavut
 # to differentiate it from the Yellowknife region.
 
 # From Paul Eggert (1999-09-20):
-# 
 # Basic Facts: The New Territory
-#  (1999) reports that Pangnirtung operates on eastern time,
+# http://www.nunavut.com/basicfacts/english/basicfacts_1territory.html
+# (1999) reports that Pangnirtung operates on eastern time,
 # and that Coral Harbour does not observe DST.  We don't know when
 # Pangnirtung switched to eastern time; we'll guess 1995.
 
@@ -1983,8 +1945,8 @@ Zone America/Creston	-7:46:04 -	LMT	1884
 # the current state of affairs.
 
 # From Michaela Rodrigue, writing in the
-# 
-# Nunatsiaq News (1999-11-19):
+# Nunatsiaq News (1999-11-19):
+# http://www.nunatsiaq.com/archives/nunavut991130/nvt91119_17.html
 # Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
 # central - or Nunavut time - for government offices, and eastern time
 # for municipal offices and schools....  Igloolik [was similar but then]
@@ -2002,10 +1964,8 @@ Zone America/Creston	-7:46:04 -	LMT	1884
 # Central Time and Southampton Island [in the Central zone] is not
 # required to use daylight savings.
 
-# From
-# 
-# Nunavut now has two time zones
-#  (2000-11-10):
+# From 
+# Nunavut now has two time zones (2000-11-10):
 # The Nunavut government would allow its employees in Kugluktuk and
 # Cambridge Bay to operate on central time year-round, putting them
 # one hour behind the rest of Nunavut for six months during the winter.
@@ -2096,9 +2056,7 @@ Zone America/Creston	-7:46:04 -	LMT	1884
 # used to be the mayor of Resolute Bay and he apparently owns half the
 # businesses including "South Camp Inn." This website has some info on
 # Aziz:
-# 
 # http://www.uphere.ca/node/493
-# 
 #
 # I sent Aziz an e-mail asking when Resolute Bay had stopped using
 # Eastern Standard Time.
@@ -2136,47 +2094,47 @@ Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 # aka Panniqtuuq
 Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
-			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
-			-5:00	Canada	E%sT	1999 Oct 31 2:00
-			-6:00	Canada	C%sT	2000 Oct 29 2:00
+			-4:00	NT_YK	A%sT	1995 Apr Sun>=1  2:00
+			-5:00	Canada	E%sT	1999 Oct 31  2:00
+			-6:00	Canada	C%sT	2000 Oct 29  2:00
 			-5:00	Canada	E%sT
 # formerly Frobisher Bay
 Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
-			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
-			-6:00	Canada	C%sT	2000 Oct 29 2:00
+			-5:00	NT_YK	E%sT	1999 Oct 31  2:00
+			-6:00	Canada	C%sT	2000 Oct 29  2:00
 			-5:00	Canada	E%sT
 # aka Qausuittuq
 Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
-			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
-			-5:00	-	EST	2001 Apr  1 3:00
-			-6:00	Canada	C%sT	2006 Oct 29 2:00
-			-5:00	-	EST	2007 Mar 11 3:00
+			-6:00	NT_YK	C%sT	2000 Oct 29  2:00
+			-5:00	-	EST	2001 Apr  1  3:00
+			-6:00	Canada	C%sT	2006 Oct 29  2:00
+			-5:00	-	EST	2007 Mar 11  3:00
 			-6:00	Canada	C%sT
 # aka Kangiqiniq
 Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
-			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
-			-5:00	-	EST	2001 Apr  1 3:00
+			-6:00	NT_YK	C%sT	2000 Oct 29  2:00
+			-5:00	-	EST	2001 Apr  1  3:00
 			-6:00	Canada	C%sT
 # aka Iqaluktuuttiaq
 Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
-			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
-			-6:00	Canada	C%sT	2000 Oct 29 2:00
-			-5:00	-	EST	2000 Nov  5 0:00
-			-6:00	-	CST	2001 Apr  1 3:00
+			-7:00	NT_YK	M%sT	1999 Oct 31  2:00
+			-6:00	Canada	C%sT	2000 Oct 29  2:00
+			-5:00	-	EST	2000 Nov  5  0:00
+			-6:00	-	CST	2001 Apr  1  3:00
 			-7:00	Canada	M%sT
 Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
 			-7:00	NT_YK	M%sT	1980
 			-7:00	Canada	M%sT
 Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
-			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
+			-8:00	NT_YK	P%sT	1979 Apr lastSun  2:00
 			-7:00	NT_YK	M%sT	1980
 			-7:00	Canada	M%sT
 Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
-			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
+			-9:00	NT_YK	Y%sT	1966 Jul  1  2:00
 			-8:00	NT_YK	P%sT	1980
 			-8:00	Canada	P%sT
 Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
-			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
+			-9:00	NT_YK	Y%sT	1973 Oct 28  0:00
 			-8:00	NT_YK	P%sT	1980
 			-8:00	Canada	P%sT
 
@@ -2188,9 +2146,8 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # From Paul Eggert (2001-03-05):
 # The Investigation and Analysis Service of the
 # Mexican Library of Congress (MLoC) has published a
-# 
 # history of Mexican local time (in Spanish)
-# .
+# http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/
 #
 # Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
 # (In all cases we go with the MLoC.)
@@ -2235,9 +2192,8 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # -------------- End Forwarded Message --------------
 # From Paul Eggert (1996-06-12):
 # For an English translation of the decree, see
-# 
 # "Diario Oficial: Time Zone Changeover" (1996-01-04).
-# 
+# http://mexico-travel.com/extra/timezone_eng.html
 
 # From Rives McDow (1998-10-08):
 # The State of Quintana Roo has reverted back to central STD and DST times
@@ -2249,7 +2205,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # savings time so as to stay on the same time zone as the southern part of
 # Arizona year round.
 
-# From Jesper Norgaard, translating
+# From Jesper Nørgaard, translating
 #  (2001-01-17):
 # In Oaxaca, the 55.000 teachers from the Section 22 of the National
 # Syndicate of Education Workers, refuse to apply daylight saving each
@@ -2262,7 +2218,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
 # that Summer Time will be reduced from seven to five months, starting
 # this year....
-# 
+# http://www.publico.com.mx/scripts/texto3.asp?action=pagina&pag=21&pos=p&secc=naci&date=01/17/2001
 # [translated], says "summer time will ... take effect on the first Sunday
 # in May, and end on the last Sunday of September.
 
@@ -2270,23 +2226,22 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # The 2001-01-24 traditional Washington Post contained the page one
 # story "Timely Issue Divides Mexicans."...
 # http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
-# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
+# ... Mexico City Mayor López Obrador "...is threatening to keep
 # Mexico City and its 20 million residents on a different time than
-# the rest of the country..." In particular, Lopez Obrador would abolish
+# the rest of the country..." In particular, López Obrador would abolish
 # observation of Daylight Saving Time.
 
-# 
 # Official statute published by the Energy Department
-#  (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
-# and Sonora with no DST.  This was reported by Jesper Norgaard (2001-02-03).
+# http://www.conae.gob.mx/ahorro/decretohorver2001.html#decre
+# (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
+# and Sonora with no DST.  This was reported by Jesper Nørgaard (2001-02-03).
 
 # From Paul Eggert (2001-03-03):
 #
-# 
+# http://www.latimes.com/news/nation/20010303/t000018766.html
 # James F. Smith writes in today's LA Times
-# 
 # * Sonora will continue to observe standard time.
-# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
+# * Last week Mexico City's mayor Andrés Manuel López Obrador decreed that
 #   the Federal District will not adopt DST.
 # * 4 of 16 district leaders announced they'll ignore the decree.
 # * The decree does not affect federal-controlled facilities including
@@ -2294,7 +2249,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 #
 # For now we'll assume that the Federal District will bow to federal rules.
 
-# From Jesper Norgaard (2001-04-01):
+# From Jesper Nørgaard (2001-04-01):
 # I found some references to the Mexican application of daylight
 # saving, which modifies what I had already sent you, stating earlier
 # that a number of northern Mexican states would go on daylight
@@ -2303,7 +2258,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # saving all year) will follow the original decree of president
 # Vicente Fox, starting daylight saving May 6, 2001 and ending
 # September 30, 2001.
-# References: "Diario de Monterrey" 
+# References: "Diario de Monterrey" 
 # Palabra  (2001-03-31)
 
 # From Reuters (2001-09-04):
@@ -2315,7 +2270,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # standard time. "This is so residents of the Federal District are not
 # subject to unexpected time changes," a statement from the court said.
 
-# From Jesper Norgaard Welen (2002-03-12):
+# From Jesper Nørgaard Welen (2002-03-12):
 # ... consulting my local grocery store(!) and my coworkers, they all insisted
 # that a new decision had been made to reinstate US style DST in Mexico....
 # http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
@@ -2329,48 +2284,36 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
 # > the United States.
 # Now this has passed both the Congress and the Senate, so starting from
 # 2010, some border regions will be the same:
-# 
 # http://www.signonsandiego.com/news/2009/dec/28/clocks-will-match-both-sides-border/
-# 
-# 
 # http://www.elmananarey.com/diario/noticia/nacional/noticias/empatan_horario_de_frontera_con_eu/621939
-# 
 # (Spanish)
 #
 # Could not find the new law text, but the proposed law text changes are here:
-# 
 # http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/20091210-V.pdf
-# 
 # (Gaceta Parlamentaria)
 #
 # There is also a list of the votes here:
-# 
 # http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/V2-101209.html
-# 
 #
 # Our page:
-# 
 # http://www.timeanddate.com/news/time/north-mexico-dst-change.html
-# 
 
 # From Arthur David Olson (2010-01-20):
 # The page
-# 
 # http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010
-# 
 # includes this text:
 # En los municipios fronterizos de Tijuana y Mexicali en Baja California;
-# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
-# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
-# Tamaulipas, la aplicación de este horario estacional surtirá efecto
-# desde las dos horas del segundo domingo de marzo y concluirá a las dos
+# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
+# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
+# Tamaulipas, la aplicación de este horario estacional surtirá efecto
+# desde las dos horas del segundo domingo de marzo y concluirá a las dos
 # horas del primer domingo de noviembre.
 # En los municipios fronterizos que se encuentren ubicados en la franja
-# fronteriza norte en el territorio comprendido entre la línea
-# internacional y la línea paralela ubicada a una distancia de veinte
-# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
-# interior del país, la aplicación de este horario estacional surtirá
-# efecto desde las dos horas del segundo domingo de marzo y concluirá a
+# fronteriza norte en el territorio comprendido entre la línea
+# internacional y la línea paralela ubicada a una distancia de veinte
+# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
+# interior del país, la aplicación de este horario estacional surtirá
+# efecto desde las dos horas del segundo domingo de marzo y concluirá a
 # las dos horas del primer domingo de noviembre.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
@@ -2389,39 +2332,39 @@ Rule	Mexico	2001	only	-	Sep	lastSun	2:00	0	S
 Rule	Mexico	2002	max	-	Apr	Sun>=1	2:00	1:00	D
 Rule	Mexico	2002	max	-	Oct	lastSun	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-# Quintana Roo
+# Quintana Roo; represented by Cancún
 Zone America/Cancun	-5:47:04 -	LMT	1922 Jan  1  0:12:56
 			-6:00	-	CST	1981 Dec 23
 			-5:00	Mexico	E%sT	1998 Aug  2  2:00
 			-6:00	Mexico	C%sT
-# Campeche, Yucatan
+# Campeche, Yucatán; represented by Mérida
 Zone America/Merida	-5:58:28 -	LMT	1922 Jan  1  0:01:32
 			-6:00	-	CST	1981 Dec 23
 			-5:00	-	EST	1982 Dec  2
 			-6:00	Mexico	C%sT
-# Coahuila, Durango, Nuevo Leon, Tamaulipas (near US border)
+# Coahuila, Durango, Nuevo León, Tamaulipas (near US border)
 Zone America/Matamoros	-6:40:00 -	LMT	1921 Dec 31 23:20:00
 			-6:00	-	CST	1988
 			-6:00	US	C%sT	1989
 			-6:00	Mexico	C%sT	2010
 			-6:00	US	C%sT
-# Coahuila, Durango, Nuevo Leon, Tamaulipas (away from US border)
+# Coahuila, Durango, Nuevo León, Tamaulipas (away from US border)
 Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
 			-6:00	-	CST	1988
 			-6:00	US	C%sT	1989
 			-6:00	Mexico	C%sT
 # Central Mexico
-Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1 0:23:24
+Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1  0:23:24
 			-7:00	-	MST	1927 Jun 10 23:00
 			-6:00	-	CST	1930 Nov 15
 			-7:00	-	MST	1931 May  1 23:00
 			-6:00	-	CST	1931 Oct
 			-7:00	-	MST	1932 Apr  1
-			-6:00	Mexico	C%sT	2001 Sep 30 02:00
+			-6:00	Mexico	C%sT	2001 Sep 30  2:00
 			-6:00	-	CST	2002 Feb 20
 			-6:00	Mexico	C%sT
 # Chihuahua (near US border)
-Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
+Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan  1  0:02:20
 			-7:00	-	MST	1927 Jun 10 23:00
 			-6:00	-	CST	1930 Nov 15
 			-7:00	-	MST	1931 May  1 23:00
@@ -2429,7 +2372,7 @@ Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
 			-7:00	-	MST	1932 Apr  1
 			-6:00	-	CST	1996
 			-6:00	Mexico	C%sT	1998
-			-6:00	-	CST	1998 Apr Sun>=1 3:00
+			-6:00	-	CST	1998 Apr Sun>=1  3:00
 			-7:00	Mexico	M%sT	2010
 			-7:00	US	M%sT
 # Chihuahua (away from US border)
@@ -2441,7 +2384,7 @@ Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
 			-7:00	-	MST	1932 Apr  1
 			-6:00	-	CST	1996
 			-6:00	Mexico	C%sT	1998
-			-6:00	-	CST	1998 Apr Sun>=1 3:00
+			-6:00	-	CST	1998 Apr Sun>=1  3:00
 			-7:00	Mexico	M%sT
 # Sonora
 Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
@@ -2457,42 +2400,33 @@ Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
 			-7:00	-	MST
 
 # From Alexander Krivenyshev (2010-04-21):
-# According to news, Bahía de Banderas (Mexican state of Nayarit)
+# According to news, Bahía de Banderas (Mexican state of Nayarit)
 # changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
 # share the same time zone as nearby city Puerto Vallarta, Jalisco).
 #
 # (Spanish)
-# Bahía de Banderas homologa su horario al del centro del
-# país, a partir de este domingo
-# 
+# Bahía de Banderas homologa su horario al del centro del
+# país, a partir de este domingo
 # http://www.nayarit.gob.mx/notes.asp?id=20748
-# 
 #
-# Bahía de Banderas homologa su horario con el del Centro del
-# País
-# 
-# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
-# 
+# Bahía de Banderas homologa su horario con el del Centro del
+# País
+# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50
 #
 # (English)
-# Puerto Vallarta and Bahía de Banderas: One Time Zone
-# 
+# Puerto Vallarta and Bahía de Banderas: One Time Zone
 # http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
-# 
-#
-# or
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
-# 
 #
 # "Mexico's Senate approved the amendments to the Mexican Schedule System that
-# will allow Bahía de Banderas and Puerto Vallarta to share the same time
+# will allow Bahía de Banderas and Puerto Vallarta to share the same time
 # zone ..."
 # Baja California Sur, Nayarit, Sinaloa
 
 # From Arthur David Olson (2010-05-01):
 # Use "Bahia_Banderas" to keep the name to fourteen characters.
 
+# Mazatlán
 Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
 			-7:00	-	MST	1927 Jun 10 23:00
 			-6:00	-	CST	1930 Nov 15
@@ -2504,6 +2438,7 @@ Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
 			-8:00	-	PST	1970
 			-7:00	Mexico	M%sT
 
+# Bahía de Banderas
 Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
 			-7:00	-	MST	1927 Jun 10 23:00
 			-6:00	-	CST	1930 Nov 15
@@ -2513,7 +2448,7 @@ Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
 			-6:00	-	CST	1942 Apr 24
 			-7:00	-	MST	1949 Jan 14
 			-8:00	-	PST	1970
-			-7:00	Mexico	M%sT	2010 Apr 4 2:00
+			-7:00	Mexico	M%sT	2010 Apr  4  2:00
 			-6:00	Mexico	C%sT
 
 # Baja California (near US border)
@@ -2560,7 +2495,7 @@ Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
 # America/Tijuana only in that it did not observe DST from 1976
 # through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
 # Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
-# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
+# that the 1987 OAG says "Only Ensenada, Mexicali, San Felipe and
 # Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
 # DST-observance was a town-by-town matter back then.  This concerns
 # data after 1970 so most likely there should be at least one Zone
@@ -2573,7 +2508,7 @@ Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
 ###############################################################################
 
 # Anguilla
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # Antigua and Barbuda
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -2609,8 +2544,8 @@ Rule	Barb	1978	1980	-	Apr	Sun>=15	2:00	1:00	D
 Rule	Barb	1979	only	-	Sep	30	2:00	0	S
 Rule	Barb	1980	only	-	Sep	25	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Barbados	-3:58:29 -	LMT	1924		# Bridgetown
-			-3:58:29 -	BMT	1932	  # Bridgetown Mean Time
+Zone America/Barbados	-3:58:29 -	LMT	1924 # Bridgetown
+			-3:58:29 -	BMT	1932 # Bridgetown Mean Time
 			-4:00	Barb	A%sT
 
 # Belize
@@ -2640,20 +2575,20 @@ Zone	America/Belize	-5:52:48 -	LMT	1912 Apr
 # http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Atlantic/Bermuda	-4:19:18 -	LMT	1930 Jan  1 2:00    # Hamilton
-			-4:00	-	AST	1974 Apr 28 2:00
+Zone Atlantic/Bermuda	-4:19:18 -	LMT	1930 Jan  1  2:00 # Hamilton
+			-4:00	-	AST	1974 Apr 28  2:00
 			-4:00	Canada	A%sT	1976
 			-4:00	US	A%sT
 
 # Cayman Is
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	America/Cayman	-5:25:32 -	LMT	1890		# Georgetown
-			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
+Zone	America/Cayman	-5:25:32 -	LMT	1890     # Georgetown
+			-5:07:11 -	KMT	1912 Feb # Kingston Mean Time
 			-5:00	-	EST
 
 # Costa Rica
 
-# Milne gives -5:36:13.3 as San Jose mean time; round to nearest.
+# Milne gives -5:36:13.3 as San José mean time; round to nearest.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
@@ -2663,10 +2598,10 @@ Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
 # go with Shanks & Pottenger.
 Rule	CR	1991	only	-	Jul	 1	0:00	0	S
 Rule	CR	1992	only	-	Mar	15	0:00	0	S
-# There are too many San Joses elsewhere, so we'll use 'Costa Rica'.
+# There are too many San Josés elsewhere, so we'll use 'Costa Rica'.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
-			-5:36:13 -	SJMT	1921 Jan 15 # San Jose Mean Time
+Zone America/Costa_Rica	-5:36:13 -	LMT	1890        # San José
+			-5:36:13 -	SJMT	1921 Jan 15 # San José Mean Time
 			-6:00	CR	C%sT
 # Coco
 # no information; probably like America/Costa_Rica
@@ -2685,8 +2620,8 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # During the game, play-by-play announcer Jim Hunter noted that
 # "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
 # Time today."  (The "two hour" remark referred to losing one hour of
-# sleep on 1999-03-28--when the announcers were in Cuba as it switched
-# to DST--and one more hour on 1999-04-04--when the announcers will have
+# sleep on 1999-03-28 - when the announcers were in Cuba as it switched
+# to DST - and one more hour on 1999-04-04 - when the announcers will have
 # returned to Baltimore, which switches on that date.)
 
 # From Steffen Thorsen (2013-11-11):
@@ -2708,16 +2643,16 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # adjustment in Cuba.  We will stay in daylight saving time:
 # http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
 
-# From Jesper Norgaard Welen (2006-10-21):
+# From Jesper Nørgaard Welen (2006-10-21):
 # An article in GRANMA INTERNACIONAL claims that Cuba will end
 # the 3 years of permanent DST next weekend, see
 # http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
 # "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
-# watches should be set back one hour -- going back to 00:00 hours -- returning
+# watches should be set back one hour - going back to 00:00 hours - returning
 # to the normal schedule....
 
 # From Paul Eggert (2007-03-02):
-# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
+# , dated yesterday,
 # says Cuban clocks will advance at midnight on March 10.
 # For lack of better information, assume Cuba will use US rules,
 # except that it switches at midnight standard time as usual.
@@ -2731,10 +2666,10 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
 # http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
 #
-# From Alex Kryvenishev (2007-10-25):
+# From Alex Krivenyshev (2007-10-25):
 # Here is also article from Granma (Cuba):
 #
-# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
+# Regirá el Horario Normal desde el próximo domingo 28 de octubre
 # http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
 #
 # http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
@@ -2742,23 +2677,18 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # From Arthur David Olson (2008-03-09):
 # I'm in Maryland which is now observing United States Eastern Daylight
 # Time. At 9:44 local time I used RealPlayer to listen to
-# 
 # http://media.enet.cu/radioreloj
-# , a Cuban information station, and heard
+# a Cuban information station, and heard
 # the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
 # indicating that Cuba is still on standard time.
 
 # From Steffen Thorsen (2008-03-12):
 # It seems that Cuba will start DST on Sunday, 2007-03-16...
 # It was announced yesterday, according to this source (in Spanish):
-# 
 # http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
-# 
 #
 # Some more background information is posted here:
-# 
 # http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
-# 
 #
 # The article also says that Cuba has been observing DST since 1963,
 # while Shanks (and tzdata) has 1965 as the first date (except in the
@@ -2768,18 +2698,14 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # change some historic records as well.
 #
 # One example:
-# 
 # http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
-# 
 
-# From Jesper Norgaard Welen (2008-03-13):
+# From Jesper Nørgaard Welen (2008-03-13):
 # The Cuban time change has just been confirmed on the most authoritative
 # web site, the Granma.  Please check out
-# 
 # http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
-# 
 #
-# Basically as expected after Steffen Thorsens information, the change
+# Basically as expected after Steffen Thorsen's information, the change
 # will take place midnight between Saturday and Sunday.
 
 # From Arthur David Olson (2008-03-12):
@@ -2790,18 +2716,14 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
 # not on midnight March 14 / March 15 as previously thought.
 #
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
 # (in Spanish)
-# 
 
 # From Arthur David Olson (2009-03-09)
 # I listened over the Internet to
-# 
 # http://media.enet.cu/readioreloj
-# 
 # this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
-# the time was announced as "diez cinco"--the same time as here, indicating
+# the time was announced as "diez cinco" - the same time as here, indicating
 # that has indeed switched to DST. Assume second Sunday from 2009 forward.
 
 # From Steffen Thorsen (2011-03-08):
@@ -2810,42 +2732,30 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
 # changed at all).
 #
 # Source:
-# 
 # http://granma.co.cu/2011/03/08/nacional/artic01.html
-# 
 #
 # Our info:
-# 
 # http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
-# 
 #
 # From Steffen Thorsen (2011-10-30)
 # Cuba will end DST two weeks later this year. Instead of going back
 # tonight, it has been delayed to 2011-11-13 at 01:00.
 #
 # One source (Spanish)
-# 
 # http://www.radioangulo.cu/noticias/cuba/17105-cuba-restablecera-el-horario-del-meridiano-de-greenwich.html
-# 
 #
 # Our page:
-# 
 # http://www.timeanddate.com/news/time/cuba-time-changes-2011.html
-# 
 #
 # From Steffen Thorsen (2012-03-01)
 # According to Radio Reloj, Cuba will start DST on Midnight between March
 # 31 and April 1.
 #
 # Radio Reloj has the following info (Spanish):
-# 
 # http://www.radioreloj.cu/index.php/noticias-radio-reloj/71-miscelaneas/7529-cuba-aplicara-el-horario-de-verano-desde-el-1-de-abril
-# 
 #
 # Our info on it:
-# 
 # http://www.timeanddate.com/news/time/cuba-starts-dst-2012.html
-# 
 
 # From Steffen Thorsen (2012-11-03):
 # Radio Reloj and many other sources report that Cuba is changing back
@@ -2901,7 +2811,7 @@ Zone	America/Havana	-5:29:28 -	LMT	1890
 			-5:00	Cuba	C%sT
 
 # Dominica
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # Dominican Republic
 
@@ -2934,8 +2844,8 @@ Rule	DR	1972	1974	-	Jan	21	0:00	0	S
 Zone America/Santo_Domingo -4:39:36 -	LMT	1890
 			-4:40	-	SDMT	1933 Apr  1 12:00 # S. Dom. MT
 			-5:00	DR	E%sT	1974 Oct 27
-			-4:00	-	AST	2000 Oct 29 02:00
-			-5:00	US	E%sT	2000 Dec  3 01:00
+			-4:00	-	AST	2000 Oct 29  2:00
+			-5:00	US	E%sT	2000 Dec  3  1:00
 			-4:00	-	AST
 
 # El Salvador
@@ -2946,20 +2856,20 @@ Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
 # There are too many San Salvadors elsewhere, so use America/El_Salvador
 # instead of America/San_Salvador.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
+Zone America/El_Salvador -5:56:48 -	LMT	1921 # San Salvador
 			-6:00	Salv	C%sT
 
 # Grenada
 # Guadeloupe
-# St Barthelemy
+# St Barthélemy
 # St Martin (French part)
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # Guatemala
 #
 # From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
 # Diario Co Latino, at
-# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
+# ,
 # says in an article dated 2006-04-19 that the Guatemalan government had
 # decided on that date to advance official time by 60 minutes, to lessen the
 # impact of the elevated cost of oil....  Daylight saving time will last from
@@ -2967,7 +2877,7 @@ Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
 # From Paul Eggert (2006-06-22):
 # The Ministry of Energy and Mines, press release CP-15/2006
 # (2006-04-19), says DST ends at 24:00.  See
-# .
+# http://www.sieca.org.gt/Sitio_publico/Energeticos/Doc/Medidas/Cambio_Horario_Nac_190406.pdf
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
@@ -2984,11 +2894,10 @@ Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
 
 # Haiti
 # From Gwillim Law (2005-04-15):
-# Risto O. Nykanen wrote me that Haiti is now on DST.
-# I searched for confirmation, and I found a
-#  press release
+# Risto O. Nykänen wrote me that Haiti is now on DST.
+# I searched for confirmation, and I found a press release
 # on the Web page of the Haitian Consulate in Chicago (2005-03-31),
-# .  Translated from French, it says:
+# .  Translated from French, it says:
 #
 #  "The Prime Minister's Communication Office notifies the public in general
 #   and the press in particular that, following a decision of the Interior
@@ -3065,14 +2974,14 @@ Zone America/Port-au-Prince -4:49:20 -	LMT	1890
 #  that Manuel Zelaya, the president
 # of Honduras, refused to back down on this.
 
-# From Jesper Norgaard Welen (2006-08-08):
+# From Jesper Nørgaard Welen (2006-08-08):
 # It seems that Honduras has returned from DST to standard time this Monday at
 # 00:00 hours (prolonging Sunday to 25 hours duration).
 # http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
 
 # From Paul Eggert (2006-08-08):
-# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
-# .
+# Also see Diario El Heraldo, The country returns to standard time (2006-08-08).
+# http://www.elheraldo.hn/nota.php?nid=54941&sec=12
 # It mentions executive decree 18-2006.
 
 # From Steffen Thorsen (2006-08-17):
@@ -3100,22 +3009,22 @@ Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
 # unspecified official document, and says "This time is used throughout the
 # island".  Go with Milne.  Round to the nearest second as required by zic.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	America/Jamaica	-5:07:11 -	LMT	1890		# Kingston
+Zone	America/Jamaica	-5:07:11 -	LMT	1890        # Kingston
 			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
-			-5:00	-	EST	1974 Apr 28 2:00
+			-5:00	-	EST	1974 Apr 28  2:00
 			-5:00	US	E%sT	1984
 			-5:00	-	EST
 
 # Martinique
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
-			-4:04:20 -	FFMT	1911 May     # Fort-de-France MT
+Zone America/Martinique	-4:04:20 -      LMT	1890        # Fort-de-France
+			-4:04:20 -	FFMT	1911 May    # Fort-de-France MT
 			-4:00	-	AST	1980 Apr  6
 			-4:00	1:00	ADT	1980 Sep 28
 			-4:00	-	AST
 
 # Montserrat
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # Nicaragua
 #
@@ -3138,27 +3047,27 @@ Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
 # From Gwillim Law (2005-04-21):
 # The Associated Press story on the time change, which can be found at
 # http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
-# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
+# and elsewhere, says (fifth paragraph, translated from Spanish): "The last
 # time that a change of clocks was applied to save energy was in the year 2000
-# during the Arnoldo Aleman administration."...
+# during the Arnoldo Alemán administration."...
 # The northamerica file says that Nicaragua has been on UTC-6 continuously
 # since December 1998.  I wasn't able to find any details of Nicaraguan time
 # changes in 2000.  Perhaps a note could be added to the northamerica file, to
 # the effect that we have indirect evidence that DST was observed in 2000.
 #
-# From Jesper Norgaard Welen (2005-11-02):
+# From Jesper Nørgaard Welen (2005-11-02):
 # Nicaragua left DST the 2005-10-02 at 00:00 (local time).
 # http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
 # (2005-09-26)
 #
-# From Jesper Norgaard Welen (2006-05-05):
+# From Jesper Nørgaard Welen (2006-05-05):
 # http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
 # (my informal translation)
-# By order of the president of the republic, Enrique Bolanos, Nicaragua
+# By order of the president of the republic, Enrique Bolaños, Nicaragua
 # advanced by sixty minutes their official time, yesterday at 2 in the
-# morning, and will stay that way until 30.th. of september.
+# morning, and will stay that way until 30th of September.
 #
-# From Jesper Norgaard Welen (2006-09-30):
+# From Jesper Nørgaard Welen (2006-09-30):
 # http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
 # My informal translation runs:
 # The natural sun time is restored in all the national territory, in that the
@@ -3176,7 +3085,7 @@ Zone	America/Managua	-5:45:08 -	LMT	1890
 			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
 			-6:00	-	CST	1973 May
 			-5:00	-	EST	1975 Feb 16
-			-6:00	Nic	C%sT	1992 Jan  1 4:00
+			-6:00	Nic	C%sT	1992 Jan  1  4:00
 			-5:00	-	EST	1992 Sep 24
 			-6:00	-	CST	1993
 			-5:00	-	EST	1997
@@ -3185,36 +3094,36 @@ Zone	America/Managua	-5:45:08 -	LMT	1890
 # Panama
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	America/Panama	-5:18:08 -	LMT	1890
-			-5:19:36 -	CMT	1908 Apr 22   # Colon Mean Time
+			-5:19:36 -	CMT	1908 Apr 22 # Colón Mean Time
 			-5:00	-	EST
 
 # Puerto Rico
 # There are too many San Juans elsewhere, so we'll use 'Puerto_Rico'.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
+Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00 # San Juan
 			-4:00	-	AST	1942 May  3
 			-4:00	US	A%sT	1946
 			-4:00	-	AST
 
 # St Kitts-Nevis
 # St Lucia
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # St Pierre and Miquelon
 # There are too many St Pierres elsewhere, so we'll use 'Miquelon'.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
+Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15 # St Pierre
 			-4:00	-	AST	1980 May
 			-3:00	-	PMST	1987 # Pierre & Miquelon Time
 			-3:00	Canada	PM%sT
 
 # St Vincent and the Grenadines
-# See 'southamerica'.
+# See America/Port_of_Spain.
 
 # Turks and Caicos
 #
 # From Chris Dunn in
-# 
+# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=415007
 # (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
 # daylight saving dates for time changes have been adjusted to match
 # the recent U.S. change of dates.
@@ -3227,21 +3136,23 @@ Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
 # Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
 # indicating that the normal ET rules are followed.
 #
-# From Paul Eggert (2006-05-01):
-# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
-# says they switch at midnight.  Go with Shanks & Pottenger.
+# From Paul Eggert (2014-08-19):
+# The 2014-08-13 Cabinet meeting decided to stay on UTC-4 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 on 2014-11-02 at 02:00.
 #
-# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
-Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
-Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
-Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
-Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Grand_Turk	-4:44:32 -	LMT	1890
-			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
-			-5:00	TC	E%sT
+			-5:07:11 -	KMT	1912 Feb # Kingston Mean Time
+			-5:00	-	EST	1979
+			-5:00	US	E%sT	2014 Nov  2  2:00
+			-4:00	-	AST
 
 # British Virgin Is
 # Virgin Is
-# See 'southamerica'.
+# See America/Port_of_Spain.
+
+
+# Local Variables:
+# coding: utf-8
+# End:
diff --git a/jdk/make/data/tzdata/pacificnew b/jdk/make/data/tzdata/pacificnew
index 09000c3457a..9b9257a45fe 100644
--- a/jdk/make/data/tzdata/pacificnew
+++ b/jdk/make/data/tzdata/pacificnew
@@ -21,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
diff --git a/jdk/make/data/tzdata/southamerica b/jdk/make/data/tzdata/southamerica
index 02bf3bb6332..398ec0e4f06 100644
--- a/jdk/make/data/tzdata/southamerica
+++ b/jdk/make/data/tzdata/southamerica
@@ -21,13 +21,13 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
-# This data is by no means authoritative; if you think you know better,
+# This file is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
-# tz@iana.org for general use in the future).
+# tz@iana.org for general use in the future).  For more, please see
+# the file CONTRIBUTING in the tz distribution.
 
 # From Paul Eggert (2006-03-22):
 # A good source for time zone historical data outside the U.S. is
@@ -35,8 +35,8 @@
 # San Diego: ACS Publications, Inc. (2003).
 #
 # For data circa 1899, a common source is:
-# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
-# .
+# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
+# http://www.jstor.org/stable/1774359
 #
 # Gwillim Law writes that a good source
 # for recent time zone data is the International Air Transport
@@ -53,24 +53,24 @@
 #	I suggest the use of _Summer time_ instead of the more cumbersome
 #	_daylight-saving time_.  _Summer time_ seems to be in general use
 #	in Europe and South America.
-#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
+#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
 #	H L Mencken, _The American Language: Supplement I_ (1960), p 466
 #
 # Earlier editions of these tables also used the North American style
 # for time zones in Brazil, but this was incorrect, as Brazilians say
-# "summer time".  Reinaldo Goulart, a Sao Paulo businessman active in
+# "summer time".  Reinaldo Goulart, a São Paulo businessman active in
 # the railroad sector, writes (1999-07-06):
 #	The subject of time zones is currently a matter of discussion/debate in
-#	Brazil.  Let's say that "the Brasilia time" is considered the
-#	"official time" because Brasilia is the capital city.
-#	The other three time zones are called "Brasilia time "minus one" or
+#	Brazil.  Let's say that "the Brasília time" is considered the
+#	"official time" because Brasília is the capital city.
+#	The other three time zones are called "Brasília time "minus one" or
 #	"plus one" or "plus two".  As far as I know there is no such
 #	name/designation as "Eastern Time" or "Central Time".
 # So I invented the following (English-language) abbreviations for now.
 # Corrections are welcome!
 #		std	dst
 #	-2:00	FNT	FNST	Fernando de Noronha
-#	-3:00	BRT	BRST	Brasilia
+#	-3:00	BRT	BRST	Brasília
 #	-4:00	AMT	AMST	Amazon
 #	-5:00	ACT	ACST	Acre
 
@@ -84,7 +84,7 @@
 # Argentina: first Sunday in October to first Sunday in April since 1976.
 # Double Summer time from 1969 to 1974.  Switches at midnight.
 
-# From U. S. Naval Observatory (1988-01-199):
+# From U. S. Naval Observatory (1988-01-19):
 # ARGENTINA           3 H BEHIND   UTC
 
 # From Hernan G. Otero (1995-06-26):
@@ -118,7 +118,7 @@ Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
 # From Hernan G. Otero (1995-06-26):
 # These corrections were contributed by InterSoft Argentina S.A.,
 # obtaining the data from the:
-# Talleres de Hidrografia Naval Argentina
+# Talleres de Hidrografía Naval Argentina
 # (Argentine Naval Hydrography Institute)
 Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
 Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
@@ -140,13 +140,13 @@ Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
 Rule	Arg	2000	only	-	Mar	3	0:00	0	-
 #
 # From Peter Gradelski via Steffen Thorsen (2000-03-01):
-# We just checked with our Sao Paulo office and they say the government of
+# We just checked with our São Paulo office and they say the government of
 # Argentina decided not to become one of the countries that go on or off DST.
 # So Buenos Aires should be -3 hours from GMT at all times.
 #
-# From Fabian L. Arce Jofre (2000-04-04):
+# From Fabián L. Arce Jofré (2000-04-04):
 # The law that claimed DST for Argentina was derogated by President Fernando
-# de la Rua on March 2, 2000, because it would make people spend more energy
+# de la Rúa on March 2, 2000, because it would make people spend more energy
 # in the winter time, rather than less.  The change took effect on March 3.
 #
 # From Mariano Absatz (2001-06-06):
@@ -179,15 +179,13 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
 # that Argentina will use DST next year as well, from October to
 # March, although exact rules are not given.
 #
-# From Jesper Norgaard Welen (2007-12-26)
+# From Jesper Nørgaard Welen (2007-12-26)
 # The last hurdle of Argentina DST is over, the proposal was approved in
-# the lower chamber too (Deputados) with a vote 192 for and 2 against.
+# the lower chamber too (Diputados) with a vote 192 for and 2 against.
 # By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
 # the original scanned proposal, where the dates and the zero hours are
 # clear and unambiguous...This is the article about final approval:
-# 
 # http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
-# 
 #
 # From Paul Eggert (2007-12-22):
 # For dates after mid-2008, the following rules are my guesses and
@@ -197,13 +195,8 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
 # As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
 # Argentina will start DST on Sunday October 19, 2008.
 #
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
-# 
-# OR
-# 
 # http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
-# 
 
 # From Rodrigo Severo (2008-10-06):
 # Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
@@ -212,48 +205,39 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
 # Hi, there is a problem with timezone-data-2008e and maybe with
 # timezone-data-2008f
 # Argentinian law [Number] 25.155 is no longer valid.
-# 
 # http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
-# 
 # The new one is law [Number] 26.350
-# 
 # http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
-# 
 # So there is no summer time in Argentina for now.
 
 # From Mariano Absatz (2008-10-20):
-# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
-# From 2008-10-19 until 2009-03-15
-# 
+# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST
+# in Argentina from 2008-10-19 until 2009-03-15.
 # http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
-# 
 #
-# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
-# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
-# and Tierra del Fuego
-# 
+
+# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer
+# 2008/2009: Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La
+# Pampa, Neuquén, Rio Negro, Chubut, Santa Cruz and Tierra del Fuego
 # http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
-# 
 #
-# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
-# it will not apply DST either (even when it was not included in Decree 1705/2008)
-# 
+# Press release 235 dated Saturday October 18th, from the Government of the
+# Province of Jujuy saying it will not apply DST either (even when it was not
+# included in Decree 1705/2008).
 # http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
-# 
 
 # From fullinet (2009-10-18):
 # As announced in
-# 
 # http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
-# 
-# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
+# (an official .gob.ar) under title: "Sin Cambio de Hora"
+# (English: "No hour change").
 #
-# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
-# oficial, decision que estaba en estudio para su implementacion el
-# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
-# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
-# la modificacion del huso horario, ya que 2009 nos encuentra con
-# crecimiento en la produccion y distribucion energetica."
+# "Por el momento, el Gobierno Nacional resolvió no modificar la hora
+# oficial, decisión que estaba en estudio para su implementación el
+# domingo 18 de octubre. Desde el Ministerio de Planificación se anunció
+# que la Argentina hoy, en estas condiciones meteorológicas, no necesita
+# la modificación del huso horario, ya que 2009 nos encuentra con
+# crecimiento en la producción y distribución energética."
 
 Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
 Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
@@ -267,10 +251,10 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # It's Law No. 7,210.  This change is due to a public power emergency, so for
 # now we'll assume it's for this year only.
 #
-# From Paul Eggert (2006-03-22):
-# 
-# Hora de verano para la Republica Argentina (2003-06-08)
-#  says that standard time in Argentina from 1894-10-31
+# From Paul Eggert (2014-08-09):
+# Hora de verano para la República Argentina
+# http://buenasiembra.com.ar/esoterismo/astrologia/hora-de-verano-de-la-republica-argentina-27.html
+# says that standard time in Argentina from 1894-10-31
 # to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
 # over Shanks & Pottenger.
 #
@@ -285,10 +269,10 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # time in October 17th.
 #
 # Catamarca, Chubut, La Rioja, San Juan, San Luis, Santa Cruz,
-# Tierra del Fuego, Tucuman.
+# Tierra del Fuego, Tucumán.
 #
 # From Mariano Absatz (2004-06-14):
-# ... this weekend, the Province of Tucuman decided it'd go back to UTC-03:00
+# ... this weekend, the Province of Tucumán decided it'd go back to UTC-03:00
 # yesterday midnight (that is, at 24:00 Saturday 12th), since the people's
 # annoyance with the change is much higher than the power savings obtained....
 #
@@ -323,49 +307,38 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # Here are articles that Argentina Province San Luis is planning to end DST
 # as earlier as upcoming Monday January 21, 2008 or February 2008:
 #
-# Provincia argentina retrasa reloj y marca diferencia con resto del pais
+# Provincia argentina retrasa reloj y marca diferencia con resto del país
 # (Argentine Province delayed clock and mark difference with the rest of the
 # country)
-# 
 # http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
-# 
 #
 # Es inminente que en San Luis atrasen una hora los relojes
 # (It is imminent in San Luis clocks one hour delay)
-# 
-# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
-# 
-#
-# 
+# http://www.lagaceta.com.ar/nota/253414/Economia/Es-inminente-que-en-San-Luis-atrasen-una-hora-los-relojes.html
 # http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
-# 
 
-# From Jesper Norgaard Welen (2008-01-18):
+# From Jesper Nørgaard Welen (2008-01-18):
 # The page of the San Luis provincial government
-# 
 # http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
-# 
 # confirms what Alex Krivenyshev has earlier sent to the tz
 # emailing list about that San Luis plans to return to standard
 # time much earlier than the rest of the country. It also
 # confirms that upon request the provinces San Juan and Mendoza
 # refused to follow San Luis in this change.
 #
-# The change is supposed to take place Monday the 21.st at 0:00
+# The change is supposed to take place Monday the 21st at 0:00
 # hours. As far as I understand it if this goes ahead, we need
 # a new timezone for San Luis (although there are also documented
 # independent changes in the southamerica file of San Luis in
 # 1990 and 1991 which has not been confirmed).
 
-# From Jesper Norgaard Welen (2008-01-25):
+# From Jesper Nørgaard Welen (2008-01-25):
 # Unfortunately the below page has become defunct, about the San Luis
 # time change. Perhaps because it now is part of a group of pages "Most
 # important pages of 2008."
 #
 # You can use
-# 
 # http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
-# 
 # instead it seems. Or use "Buscador" from the main page of the San Luis
 # government, and fill in "huso" and click OK, and you will get 3 pages
 # from which the first one is identical to the above.
@@ -385,9 +358,9 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # back in 2004, when these provinces changed to UTC-4 for a few days, I
 # mailed them personally and never got an answer).
 
-# From Paul Eggert (2008-06-30):
-# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
-# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
+# From Paul Eggert (2014-08-12):
+# Unless otherwise specified, data entries are from Shanks & Pottenger through
+# 1992, from the IATA otherwise.  As noted below, Shanks & Pottenger say that
 # America/Cordoba split into 6 subregions during 1991/1992, one of which
 # was America/San_Luis, but we haven't verified this yet so for now we'll
 # keep America/Cordoba a single region rather than splitting it into the
@@ -399,14 +372,9 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # to utc-04:00 until the second Saturday in October...
 #
 # The press release is at
-# 
 # http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
-# 
-# (I couldn't find the decree, but
-# 
-# www.sanluis.gov.ar
-# 
-# is the official page for the Province Government).
+# (I couldn't find the decree, but www.sanluis.gov.ar
+# is the official page for the Province Government.)
 #
 # There's also a note in only one of the major national papers ...
 # http://www.lanacion.com.ar/nota.asp?nota_id=1107912
@@ -423,9 +391,7 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # ...the Province of San Luis is a case in itself.
 #
 # The Law at
-# 
 # is ambiguous because establishes a calendar from the 2nd Sunday in
 # October at 0:00 thru the 2nd Saturday in March at 24:00 and the
 # complement of that starting on the 2nd Sunday of March at 0:00 and
@@ -454,19 +420,15 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # ...
 
 # From Alexander Krivenyshev (2010-04-09):
-# According to news reports from El Diario de la Republica Province San
+# According to news reports from El Diario de la República Province San
 # Luis, Argentina (standard time UTC-04) will keep Daylight Saving Time
-# after April 11, 2010--will continue to have same time as rest of
+# after April 11, 2010 - will continue to have same time as rest of
 # Argentina (UTC-3) (no DST).
 #
-# Confirmaron la prórroga del huso horario de verano (Spanish)
-# 
+# Confirmaron la prórroga del huso horario de verano (Spanish)
 # http://www.eldiariodelarepublica.com/index.php?option=com_content&task=view&id=29383&Itemid=9
-# 
 # or (some English translation):
-# 
 # http://www.worldtimezone.com/dst_news/dst_news_argentina08.html
-# 
 
 # From Mariano Absatz (2010-04-12):
 # yes...I can confirm this...and given that San Luis keeps calling
@@ -478,7 +440,7 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # Perhaps San Luis operates on the legal fiction that it is at UTC-4
 # with perpetual summer time, but ordinary usage typically seems to
 # just say it's at UTC-3; 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
 # offsets, only tm_isdst and the time zone abbreviations.  One minor
@@ -486,20 +448,20 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
 # setting for time stamps past 2038.
 
 # From Paul Eggert (2013-02-21):
-# Milne says Cordoba time was -4:16:48.2.  Round to the nearest second.
+# Milne says Córdoba time was -4:16:48.2.  Round to the nearest second.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 #
 # Buenos Aires (BA), Capital Federal (CF),
-Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
-			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+Zone America/Argentina/Buenos_Aires -3:53:48 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
 			-4:00	-	ART	1930 Dec
 			-4:00	Arg	AR%sT	1969 Oct  5
 			-3:00	Arg	AR%sT	1999 Oct  3
 			-4:00	Arg	AR%sT	2000 Mar  3
 			-3:00	Arg	AR%sT
 #
-# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
+# Córdoba (CB), Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN),
 # Chaco (CC), Formosa (FM), Santiago del Estero (SE)
 #
 # Shanks & Pottenger also make the following claims, which we haven't verified:
@@ -519,7 +481,7 @@ Zone America/Argentina/Cordoba -4:16:48 - LMT	1894 Oct 31
 			-4:00	Arg	AR%sT	2000 Mar  3
 			-3:00	Arg	AR%sT
 #
-# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
+# Salta (SA), La Pampa (LP), Neuquén (NQ), Rio Negro (RN)
 Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
 			-4:16:48 -	CMT	1920 May
 			-4:00	-	ART	1930 Dec
@@ -531,7 +493,7 @@ Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
 			-3:00	Arg	AR%sT	2008 Oct 18
 			-3:00	-	ART
 #
-# Tucuman (TM)
+# Tucumán (TM)
 Zone America/Argentina/Tucuman -4:20:52 - LMT	1894 Oct 31
 			-4:16:48 -	CMT	1920 May
 			-4:00	-	ART	1930 Dec
@@ -642,8 +604,8 @@ Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
 			-3:00	-	ART
 #
 # Santa Cruz (SC)
-Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
-			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
 			-4:00	-	ART	1930 Dec
 			-4:00	Arg	AR%sT	1969 Oct  5
 			-3:00	Arg	AR%sT	1999 Oct  3
@@ -653,9 +615,9 @@ Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
 			-3:00	Arg	AR%sT	2008 Oct 18
 			-3:00	-	ART
 #
-# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
-Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
-			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+# Tierra del Fuego, Antártida e Islas del Atlántico Sur (TF)
+Zone America/Argentina/Ushuaia -4:33:12 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
 			-4:00	-	ART	1930 Dec
 			-4:00	Arg	AR%sT	1969 Oct  5
 			-3:00	Arg	AR%sT	1999 Oct  3
@@ -686,13 +648,13 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 
 # From IATA SSIM (1996-02):
 # _Only_ the following states in BR1 observe DST: Rio Grande do Sul (RS),
-# Santa Catarina (SC), Parana (PR), Sao Paulo (SP), Rio de Janeiro (RJ),
-# Espirito Santo (ES), Minas Gerais (MG), Bahia (BA), Goias (GO),
+# Santa Catarina (SC), Paraná (PR), São Paulo (SP), Rio de Janeiro (RJ),
+# Espírito Santo (ES), Minas Gerais (MG), Bahia (BA), Goiás (GO),
 # Distrito Federal (DF), Tocantins (TO), Sergipe [SE] and Alagoas [AL].
 # [The last three states are new to this issue of the IATA SSIM.]
 
 # From Gwillim Law (1996-10-07):
-# Geography, history (Tocantins was part of Goias until 1989), and other
+# Geography, history (Tocantins was part of Goiás until 1989), and other
 # sources of time zone information lead me to believe that AL, SE, and TO were
 # always in BR1, and so the only change was whether or not they observed DST....
 # The earliest issue of the SSIM I have is 2/91.  Each issue from then until
@@ -706,16 +668,14 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 # However, some conclusions can be drawn from another IATA manual: the Airline
 # Coding Directory, which lists close to 400 airports in Brazil.  For each
 # airport it gives a time zone which is coded to the SSIM.  From that
-# information, I'm led to conclude that the states of Amapa (AP), Ceara (CE),
-# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
-# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
+# information, I'm led to conclude that the states of Amapá (AP), Ceará (CE),
+# Maranhão (MA), Paraíba (PR), Pernambuco (PE), Piauí (PI), and Rio Grande do
+# Norte (RN), and the eastern part of Pará (PA) are all in BR1 without DST.
 
 # From Marcos Tadeu (1998-09-27):
-# 
-# Brazilian official page
-# 
+# Brazilian official page 
 
-# From Jesper Norgaard (2000-11-03):
+# From Jesper Nørgaard (2000-11-03):
 # [For an official list of which regions in Brazil use which time zones, see:]
 # http://pcdsh01.on.br/Fusbr.htm
 # http://pcdsh01.on.br/Fusbrhv.htm
@@ -748,13 +708,13 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 
 # From Paul Schulze (2008-06-24):
 # ...by law number 11.662 of April 24, 2008 (published in the "Diario
-# Oficial da Uniao"...) in Brazil there are changes in the timezones,
+# Oficial da União"...) in Brazil there are changes in the timezones,
 # effective today (00:00am at June 24, 2008) as follows:
 #
-# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
+# a) The timezone UTC+5 is extinguished, with all the Acre state and the
 # part of the Amazonas state that had this timezone now being put to the
 # timezone UTC+4
-# b) The whole Para state now is put at timezone UTC+3, instead of just
+# b) The whole Pará state now is put at timezone UTC+3, instead of just
 # part of it, as was before.
 #
 # This change follows a proposal of senator Tiao Viana of Acre state, that
@@ -767,13 +727,11 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 
 # From Rodrigo Severo (2008-06-24):
 # Just correcting the URL:
-# 
 # https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=do&secao=1&pagina=1&data=25/04/2008
-# 
 #
 # As a result of the above Decree I believe the America/Rio_Branco
 # timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
-# be created to represent the...west side of the Para State. I
+# be created to represent the...west side of the Pará State. I
 # suggest this new timezone be called Santarem as the most
 # important/populated city in the affected area.
 #
@@ -782,19 +740,16 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 
 # From Alex Krivenyshev (2008-06-24):
 # This is a quick reference page for New and Old Brazil Time Zones map.
-# 
 # http://www.worldtimezone.com/brazil-time-new-old.php
-# 
 #
-# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
-# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
-# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
+# - 4 time zones replaced by 3 time zones - eliminating time zone UTC-05
+# (state Acre and the part of the Amazonas will be UTC/GMT-04) - western
+# part of Par state is moving to one timezone UTC-03 (from UTC-04).
 
 # From Paul Eggert (2002-10-10):
 # The official decrees referenced below are mostly taken from
-# 
-# Decretos sobre o Horario de Verao no Brasil
-# .
+# Decretos sobre o Horário de Verão no Brasil.
+# http://pcdsh01.on.br/DecHV.html
 
 # From Steffen Thorsen (2008-08-29):
 # As announced by the government and many newspapers in Brazil late
@@ -806,25 +761,17 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 # It has not yet been posted to http://pcdsh01.on.br/DecHV.html
 #
 # An official page about it:
-# 
 # http://www.mme.gov.br/site/news/detail.do?newsId=16722
-# 
 # Note that this link does not always work directly, but must be accessed
 # by going to
-# 
 # http://www.mme.gov.br/first
-# 
 #
 # One example link that works directly:
-# 
 # http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
 # (Portuguese)
-# 
 #
 # We have a written a short article about it as well:
-# 
 # http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
-# 
 #
 # From Alexander Krivenyshev (2011-10-04):
 # State Bahia will return to Daylight savings time this year after 8 years off.
@@ -832,17 +779,12 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 # television station in Salvador.
 
 # In Portuguese:
-# 
 # http://g1.globo.com/bahia/noticia/2011/10/governador-jaques-wagner-confirma-horario-de-verao-na-bahia.html
-#  and
-# 
 # http://noticias.terra.com.br/brasil/noticias/0,,OI5390887-EI8139,00-Bahia+volta+a+ter+horario+de+verao+apos+oito+anos.html
-# 
 
 # From Guilherme Bernardes Rodrigues (2011-10-07):
 # There is news in the media, however there is still no decree about it.
-# I just send a e-mail to Zulmira Brandao at
-# http://pcdsh01.on.br/ the
+# I just send a e-mail to Zulmira Brandao at http://pcdsh01.on.br/ the
 # official agency about time in Brazil, and she confirmed that the old rule is
 # still in force.
 
@@ -854,9 +796,7 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 #
 # DECRETO No- 7.584, DE 13 DE OUTUBRO DE 2011
 # Link :
-# 
 # http://www.in.gov.br/visualiza/index.jsp?data=13/10/2011&jornal=1000&pagina=6&totalArquivos=6
-# 
 
 # From Kelley Cook (2012-10-16):
 # The governor of state of Bahia in Brazil announced on Thursday that
@@ -884,42 +824,42 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
 # For now, assume western Amazonas will change as well.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-# Decree 20,466 (1931-10-01)
-# Decree 21,896 (1932-01-10)
+# Decree 20,466  (1931-10-01)
+# Decree 21,896  (1932-01-10)
 Rule	Brazil	1931	only	-	Oct	 3	11:00	1:00	S
 Rule	Brazil	1932	1933	-	Apr	 1	 0:00	0	-
 Rule	Brazil	1932	only	-	Oct	 3	 0:00	1:00	S
-# Decree 23,195 (1933-10-10)
+# Decree 23,195  (1933-10-10)
 # revoked DST.
-# Decree 27,496 (1949-11-24)
-# Decree 27,998 (1950-04-13)
+# Decree 27,496  (1949-11-24)
+# Decree 27,998  (1950-04-13)
 Rule	Brazil	1949	1952	-	Dec	 1	 0:00	1:00	S
 Rule	Brazil	1950	only	-	Apr	16	 1:00	0	-
 Rule	Brazil	1951	1952	-	Apr	 1	 0:00	0	-
-# Decree 32,308 (1953-02-24)
+# Decree 32,308  (1953-02-24)
 Rule	Brazil	1953	only	-	Mar	 1	 0:00	0	-
-# Decree 34,724 (1953-11-30)
+# Decree 34,724  (1953-11-30)
 # revoked DST.
-# Decree 52,700 (1963-10-18)
+# Decree 52,700  (1963-10-18)
 # established DST from 1963-10-23 00:00 to 1964-02-29 00:00
 # in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
-# Decree 53,071 (1963-12-03)
+# Decree 53,071  (1963-12-03)
 # extended the above decree to all of the national territory on 12-09.
 Rule	Brazil	1963	only	-	Dec	 9	 0:00	1:00	S
-# Decree 53,604 (1964-02-25)
+# Decree 53,604  (1964-02-25)
 # extended summer time by one day to 1964-03-01 00:00 (start of school).
 Rule	Brazil	1964	only	-	Mar	 1	 0:00	0	-
-# Decree 55,639 (1965-01-27)
+# Decree 55,639  (1965-01-27)
 Rule	Brazil	1965	only	-	Jan	31	 0:00	1:00	S
 Rule	Brazil	1965	only	-	Mar	31	 0:00	0	-
-# Decree 57,303 (1965-11-22)
+# Decree 57,303  (1965-11-22)
 Rule	Brazil	1965	only	-	Dec	 1	 0:00	1:00	S
-# Decree 57,843 (1966-02-18)
+# Decree 57,843  (1966-02-18)
 Rule	Brazil	1966	1968	-	Mar	 1	 0:00	0	-
 Rule	Brazil	1966	1967	-	Nov	 1	 0:00	1:00	S
-# Decree 63,429 (1968-10-15)
+# Decree 63,429  (1968-10-15)
 # revoked DST.
-# Decree 91,698 (1985-09-27)
+# Decree 91,698  (1985-09-27)
 Rule	Brazil	1985	only	-	Nov	 2	 0:00	1:00	S
 # Decree 92,310 (1986-01-21)
 # Decree 92,463 (1986-03-13)
@@ -927,42 +867,42 @@ Rule	Brazil	1986	only	-	Mar	15	 0:00	0	-
 # Decree 93,316 (1986-10-01)
 Rule	Brazil	1986	only	-	Oct	25	 0:00	1:00	S
 Rule	Brazil	1987	only	-	Feb	14	 0:00	0	-
-# Decree 94,922 (1987-09-22)
+# Decree 94,922  (1987-09-22)
 Rule	Brazil	1987	only	-	Oct	25	 0:00	1:00	S
 Rule	Brazil	1988	only	-	Feb	 7	 0:00	0	-
-# Decree 96,676 (1988-09-12)
+# Decree 96,676  (1988-09-12)
 # except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
 Rule	Brazil	1988	only	-	Oct	16	 0:00	1:00	S
 Rule	Brazil	1989	only	-	Jan	29	 0:00	0	-
-# Decree 98,077 (1989-08-21)
+# Decree 98,077  (1989-08-21)
 # with the same exceptions
 Rule	Brazil	1989	only	-	Oct	15	 0:00	1:00	S
 Rule	Brazil	1990	only	-	Feb	11	 0:00	0	-
-# Decree 99,530 (1990-09-17)
+# Decree 99,530  (1990-09-17)
 # adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
 # Decree 99,629 (1990-10-19) adds BA, MT.
 Rule	Brazil	1990	only	-	Oct	21	 0:00	1:00	S
 Rule	Brazil	1991	only	-	Feb	17	 0:00	0	-
-# Unnumbered decree (1991-09-25)
+# Unnumbered decree  (1991-09-25)
 # adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
 Rule	Brazil	1991	only	-	Oct	20	 0:00	1:00	S
 Rule	Brazil	1992	only	-	Feb	 9	 0:00	0	-
-# Unnumbered decree (1992-10-16)
+# Unnumbered decree  (1992-10-16)
 # adopted by same states.
 Rule	Brazil	1992	only	-	Oct	25	 0:00	1:00	S
 Rule	Brazil	1993	only	-	Jan	31	 0:00	0	-
-# Decree 942 (1993-09-28)
+# Decree 942  (1993-09-28)
 # adopted by same states, plus AM.
-# Decree 1,252 (1994-09-22;
+# Decree 1,252  (1994-09-22;
 # web page corrected 2004-01-07) adopted by same states, minus AM.
-# Decree 1,636 (1995-09-14)
+# Decree 1,636  (1995-09-14)
 # adopted by same states, plus MT and TO.
-# Decree 1,674 (1995-10-13)
+# Decree 1,674  (1995-10-13)
 # adds AL, SE.
 Rule	Brazil	1993	1995	-	Oct	Sun>=11	 0:00	1:00	S
 Rule	Brazil	1994	1995	-	Feb	Sun>=15	 0:00	0	-
 Rule	Brazil	1996	only	-	Feb	11	 0:00	0	-
-# Decree 2,000 (1996-09-04)
+# Decree 2,000  (1996-09-04)
 # adopted by same states, minus AL, SE.
 Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
 Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
@@ -975,53 +915,51 @@ Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
 #
 # Decree 2,317 (1997-09-04), adopted by same states.
 Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
-# Decree 2,495
+# Decree 2,495 
 # (1998-02-10)
 Rule	Brazil	1998	only	-	Mar	 1	 0:00	0	-
-# Decree 2,780 (1998-09-11)
+# Decree 2,780  (1998-09-11)
 # adopted by the same states as before.
 Rule	Brazil	1998	only	-	Oct	11	 0:00	1:00	S
 Rule	Brazil	1999	only	-	Feb	21	 0:00	0	-
-# Decree 3,150
+# Decree 3,150 
 # (1999-08-23) adopted by same states.
-# Decree 3,188 (1999-09-30)
+# Decree 3,188  (1999-09-30)
 # adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
 Rule	Brazil	1999	only	-	Oct	 3	 0:00	1:00	S
 Rule	Brazil	2000	only	-	Feb	27	 0:00	0	-
-# Decree 3,592 (2000-09-06)
+# Decree 3,592  (2000-09-06)
 # adopted by the same states as before.
-# Decree 3,630 (2000-10-13)
+# Decree 3,630  (2000-10-13)
 # repeals DST in PE and RR, effective 2000-10-15 00:00.
-# Decree 3,632 (2000-10-17)
+# Decree 3,632  (2000-10-17)
 # repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
-# Decree 3,916
+# Decree 3,916 
 # (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
 Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
 Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
 # Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
-# 4,399
+# 4,399 
 Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
 # Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
-# 4,844
+# 4,844 
 Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
 # Decree 5,223 (2004-10-01) reestablishes DST in MT.
-# 5,223
+# 5,223 
 Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
-# Decree 5,539 (2005-09-19),
+# Decree 5,539  (2005-09-19),
 # adopted by the same states as before.
 Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
-# Decree 5,920 (2006-10-03),
+# Decree 5,920  (2006-10-03),
 # adopted by the same states as before.
 Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
 Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
-# Decree 6,212 (2007-09-26),
+# Decree 6,212  (2007-09-26),
 # adopted by the same states as before.
 Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
 # From Frederico A. C. Neves (2008-09-10):
 # According to this decree
-# 
 # http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
-# 
 # [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
 # 3rd Feb Sunday. There is an exception on the return date when this is
 # the Carnival Sunday then the return date will be the next Sunday...
@@ -1056,29 +994,29 @@ Zone America/Noronha	-2:09:40 -	LMT	1914
 			-2:00	Brazil	FN%sT	2002 Oct  1
 			-2:00	-	FNT
 # Other Atlantic islands have no permanent settlement.
-# These include Trindade and Martin Vaz (administratively part of ES),
-# Atol das Rocas (RN), and Penedos de Sao Pedro e Sao Paulo (PE).
+# These include Trindade and Martim Vaz (administratively part of ES),
+# Rocas Atoll (RN), and the St Peter and St Paul Archipelago (PE).
 # Fernando de Noronha was a separate territory from 1942-09-02 to 1989-01-01;
 # it also included the Penedos.
 #
-# Amapa (AP), east Para (PA)
-# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
-# The division between east and west Para is the river Xingu.
+# Amapá (AP), east Pará (PA)
+# East Pará includes Belém, Marabá, Serra Norte, and São Félix do Xingu.
+# The division between east and west Pará is the river Xingu.
 # In the north a very small part from the river Javary (now Jari I guess,
-# the border with Amapa) to the Amazon, then to the Xingu.
+# the border with Amapá) to the Amazon, then to the Xingu.
 Zone America/Belem	-3:13:56 -	LMT	1914
 			-3:00	Brazil	BR%sT	1988 Sep 12
 			-3:00	-	BRT
 #
-# west Para (PA)
-# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
+# west Pará (PA)
+# West Pará includes Altamira, Óbidos, Prainha, Oriximiná, and Santarém.
 Zone America/Santarem	-3:38:48 -	LMT	1914
 			-4:00	Brazil	AM%sT	1988 Sep 12
-			-4:00	-	AMT	2008 Jun 24 00:00
+			-4:00	-	AMT	2008 Jun 24  0:00
 			-3:00	-	BRT
 #
-# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
-# Paraiba (PB)
+# Maranhão (MA), Piauí (PI), Ceará (CE), Rio Grande do Norte (RN),
+# Paraíba (PB)
 Zone America/Fortaleza	-2:34:00 -	LMT	1914
 			-3:00	Brazil	BR%sT	1990 Sep 17
 			-3:00	-	BRT	1999 Sep 30
@@ -1125,11 +1063,11 @@ Zone America/Bahia	-2:34:04 -	LMT	1914
 			-3:00	Brazil	BR%sT	2012 Oct 21
 			-3:00	-	BRT
 #
-# Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
-# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
+# Goiás (GO), Distrito Federal (DF), Minas Gerais (MG),
+# Espírito Santo (ES), Rio de Janeiro (RJ), São Paulo (SP), Paraná (PR),
 # Santa Catarina (SC), Rio Grande do Sul (RS)
 Zone America/Sao_Paulo	-3:06:28 -	LMT	1914
-			-3:00	Brazil	BR%sT	1963 Oct 23 00:00
+			-3:00	Brazil	BR%sT	1963 Oct 23  0:00
 			-3:00	1:00	BRST	1964
 			-3:00	Brazil	BR%sT
 #
@@ -1143,7 +1081,7 @@ Zone America/Cuiaba	-3:44:20 -	LMT	1914
 			-4:00	-	AMT	2004 Oct  1
 			-4:00	Brazil	AM%sT
 #
-# Rondonia (RO)
+# Rondônia (RO)
 Zone America/Porto_Velho -4:15:36 -	LMT	1914
 			-4:00	Brazil	AM%sT	1988 Sep 12
 			-4:00	-	AMT
@@ -1155,7 +1093,7 @@ Zone America/Boa_Vista	-4:02:40 -	LMT	1914
 			-4:00	Brazil	AM%sT	2000 Oct 15
 			-4:00	-	AMT
 #
-# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
+# east Amazonas (AM): Boca do Acre, Jutaí, Manaus, Floriano Peixoto
 # The great circle line from Tabatinga to Porto Acre divides
 # east from west Amazonas.
 Zone America/Manaus	-4:00:04 -	LMT	1914
@@ -1165,19 +1103,19 @@ Zone America/Manaus	-4:00:04 -	LMT	1914
 			-4:00	-	AMT
 #
 # west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
-#	Eirunepe, Envira, Ipixuna
+#	Eirunepé, Envira, Ipixuna
 Zone America/Eirunepe	-4:39:28 -	LMT	1914
 			-5:00	Brazil	AC%sT	1988 Sep 12
 			-5:00	-	ACT	1993 Sep 28
 			-5:00	Brazil	AC%sT	1994 Sep 22
-			-5:00	-	ACT	2008 Jun 24 00:00
+			-5:00	-	ACT	2008 Jun 24  0:00
 			-4:00	-	AMT	2013 Nov 10
 			-5:00	-	ACT
 #
 # Acre (AC)
 Zone America/Rio_Branco	-4:31:12 -	LMT	1914
 			-5:00	Brazil	AC%sT	1988 Sep 12
-			-5:00	-	ACT	2008 Jun 24 00:00
+			-5:00	-	ACT	2008 Jun 24  0:00
 			-4:00	-	AMT	2013 Nov 10
 			-5:00	-	ACT
 
@@ -1198,66 +1136,54 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
 # From Oscar van Vlijmen (2006-10-08):
 # http://www.horaoficial.cl/cambio.htm
 
-# From Jesper Norgaard Welen (2006-10-08):
+# From Jesper Nørgaard Welen (2006-10-08):
 # I think that there are some obvious mistakes in the suggested link
 # from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
 # ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
 # (they should have been 1990-09-15 and 1990-09-16 respectively), but
 # anyhow it clears up some doubts too.
 
-# From Paul Eggert (2006-12-27):
-# The following data for Chile and America/Santiago are from
+# From Paul Eggert (2014-08-12):
+# The following data entries for Chile and America/Santiago are from
 #  (2006-09-20), transcribed by
-# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
+# Jesper Nørgaard Welen.  The data entries for Pacific/Easter are from Shanks
 # & Pottenger, except with DST transitions after 1932 cloned from
-# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
+# America/Santiago.  The pre-1980 Pacific/Easter data entries are dubious,
 # but we have no other source.
 
-# From German Poo-Caaman~o (2008-03-03):
+# From Germán Poo-Caamaño (2008-03-03):
 # Due to drought, Chile extends Daylight Time in three weeks.  This
 # is one-time change (Saturday 3/29 at 24:00 for America/Santiago
 # and Saturday 3/29 at 22:00 for Pacific/Easter)
 # The Supreme Decree is located at
-# 
 # http://www.shoa.cl/servicios/supremo316.pdf
-# 
 # and the instructions for 2008 are located in:
-# 
 # http://www.horaoficial.cl/cambio.htm
-# .
 
-# From Jose Miguel Garrido (2008-03-05):
+# From José Miguel Garrido (2008-03-05):
 # ...
 # You could see the announces of the change on
-# 
 # http://www.shoa.cl/noticias/2008/04hora/hora.htm
-# .
 
 # From Angel Chiang (2010-03-04):
 # Subject: DST in Chile exceptionally extended to 3 April due to earthquake
-# 
 # http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
-# 
 # (in Spanish, last paragraph).
 #
 # This is breaking news. There should be more information available later.
 
-# From Arthur Daivd Olson (2010-03-06):
+# From Arthur David Olson (2010-03-06):
 # Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
 
-# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
+# From Glenn Eychaner (2011-03-02):
 # It appears that the Chilean government has decided to postpone the
 # change from summer time to winter time again, by three weeks to April
 # 2nd:
-# 
 # http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
-# 
 #
 # This is not yet reflected in the official "cambio de hora" site, but
 # probably will be soon:
-# 
 # http://www.horaoficial.cl/cambio.htm
-# 
 
 # From Arthur David Olson (2011-03-02):
 # The emol.com article mentions a water shortage as the cause of the
@@ -1265,9 +1191,7 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
 
 # From Glenn Eychaner (2011-03-28):
 # The article:
-# 
 # http://diario.elmercurio.com/2011/03/28/_portada/_portada/noticias/7565897A-CA86-49E6-9E03-660B21A4883E.htm?id=3D{7565897A-CA86-49E6-9E03-660B21A4883E}
-# 
 #
 # In English:
 # Chile's clocks will go back an hour this year on the 7th of May instead
@@ -1298,7 +1222,7 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
 # start date is 2013-09-08 00:00....
 # http://www.gob.cl/informa/2013/02/15/gobierno-anuncia-fechas-de-cambio-de-hora-para-el-ano-2013.htm
 
-# From Jose Miguel Garrido (2014-02-19):
+# From José Miguel Garrido (2014-02-19):
 # Today appeared in the Diario Oficial a decree amending the time change
 # dates to 2014.
 # DST End: last Saturday of April 2014 (Sun 27 Apr 2014 03:00 UTC)
@@ -1352,7 +1276,7 @@ Rule	Chile	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
 # (1996-09) says 1998-03-08.  Ignore these.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Santiago	-4:42:46 -	LMT	1890
-			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
+			-4:42:46 -	SMT	1910        # Santiago Mean Time
 			-5:00	-	CLT	1916 Jul  1 # Chile Time
 			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
 			-4:00	-	CLT	1919 Jul  1 # Chile Time
@@ -1361,16 +1285,16 @@ Zone America/Santiago	-4:42:46 -	LMT	1890
 			-4:00	Chile	CL%sT
 Zone Pacific/Easter	-7:17:44 -	LMT	1890
 			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
-			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
+			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter Time
 			-6:00	Chile	EAS%sT
 #
-# Sala y Gomez Island is like Pacific/Easter.
-# Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
-# San Felix, and Antarctic bases, are like America/Santiago.
+# Salas y Gómez Island is uninhabited.
+# Other Chilean locations, including Juan Fernández Is, Desventuradas Is,
+# and Antarctic bases, are like America/Santiago.
 
 # Colombia
 
-# Milne gives 4:56:16.4 for Bogota time in 1899; round to nearest.  He writes,
+# Milne gives 4:56:16.4 for Bogotá time in 1899; round to nearest.  He writes,
 # "A variation of fifteen minutes in the public clocks of Bogota is not rare."
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
@@ -1378,37 +1302,37 @@ Rule	CO	1992	only	-	May	 3	0:00	1:00	S
 Rule	CO	1993	only	-	Apr	 4	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	America/Bogota	-4:56:16 -	LMT	1884 Mar 13
-			-4:56:16 -	BMT	1914 Nov 23 # Bogota Mean Time
+			-4:56:16 -	BMT	1914 Nov 23 # Bogotá Mean Time
 			-5:00	CO	CO%sT	# Colombia Time
 # Malpelo, Providencia, San Andres
 # no information; probably like America/Bogota
 
-# Curacao
+# Curaçao
 
-# Milne gives 4:35:46.9 for Curacao mean time; round to nearest.
+# Milne gives 4:35:46.9 for Curaçao mean time; round to nearest.
 #
 # From Paul Eggert (2006-03-22):
 # Shanks & Pottenger say that The Bottom and Philipsburg have been at
 # -4:00 since standard time was introduced on 1912-03-02; and that
 # Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
 # 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
-# Saba Island has been like Curacao.
+# Saba Island has been like Curaçao.
 # This all predates our 1970 cutoff, though.
 #
-# By July 2007 Curacao and St Maarten are planned to become
+# By July 2007 Curaçao and St Maarten are planned to become
 # associated states within the Netherlands, much like Aruba;
 # Bonaire, Saba and St Eustatius would become directly part of the
 # Netherlands as Kingdom Islands.  This won't affect their time zones
 # though, as far as we know.
 #
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	America/Curacao	-4:35:47 -	LMT	1912 Feb 12	# Willemstad
+Zone	America/Curacao	-4:35:47 -	LMT	1912 Feb 12 # Willemstad
 			-4:30	-	ANT	1965 # Netherlands Antilles Time
 			-4:00	-	AST
 
 # From Arthur David Olson (2011-06-15):
 # use links for places with new iso3166 codes.
-# The name "Lower Prince's Quarter" is both longer than fourteen charaters
+# The name "Lower Prince's Quarter" is both longer than fourteen characters
 # and contains an apostrophe; use "Lower_Princes" below.
 
 Link	America/Curacao	America/Lower_Princes	# Sint Maarten
@@ -1416,7 +1340,7 @@ Link	America/Curacao	America/Kralendijk	# Caribbean Netherlands
 
 # Ecuador
 #
-# Milne says the Sentral and South American Telegraph Company used -5:24:15.
+# Milne says the Central and South American Telegraph Company used -5:24:15.
 #
 # From Paul Eggert (2007-03-04):
 # Apparently Ecuador had a failed experiment with DST in 1992.
@@ -1427,10 +1351,10 @@ Link	America/Curacao	America/Kralendijk	# Caribbean Netherlands
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Guayaquil	-5:19:20 -	LMT	1890
 			-5:14:00 -	QMT	1931 # Quito Mean Time
-			-5:00	-	ECT	     # Ecuador Time
+			-5:00	-	ECT	# Ecuador Time
 Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
 			-5:00	-	ECT	1986
-			-6:00	-	GALT	     # Galapagos Time
+			-6:00	-	GALT	# Galápagos Time
 
 # Falklands
 
@@ -1439,7 +1363,7 @@ Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
 # the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
 
 # From Falkland Islands Government Office, London (2001-01-22)
-# via Jesper Norgaard:
+# via Jesper Nørgaard:
 # ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
 # April 2001 and advance one hour to summer time at 2 am on Sunday 2
 # September.  It is anticipated that the clocks will revert back at 2
@@ -1488,9 +1412,7 @@ Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
 # daylight saving time.
 #
 # One source:
-# 
 # http://www.falklandnews.com/public/story.cfm?get=5914&source=3
-# 
 #
 # We have gotten this confirmed by a clerk of the legislative assembly:
 # Normally the clocks revert to Local Mean Time (UTC/GMT -4 hours) on the
@@ -1531,10 +1453,10 @@ Rule	Falk	2001	2010	-	Apr	Sun>=15	2:00	0	-
 Rule	Falk	2001	2010	-	Sep	Sun>=1	2:00	1:00	S
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
-			-3:51:24 -	SMT	1912 Mar 12  # Stanley Mean Time
-			-4:00	Falk	FK%sT	1983 May     # Falkland Is Time
+			-3:51:24 -	SMT	1912 Mar 12 # Stanley Mean Time
+			-4:00	Falk	FK%sT	1983 May    # Falkland Is Time
 			-3:00	Falk	FK%sT	1985 Sep 15
-			-4:00	Falk	FK%sT	2010 Sep 5 02:00
+			-4:00	Falk	FK%sT	2010 Sep  5  2:00
 			-3:00	-	FKST
 
 # French Guiana
@@ -1545,7 +1467,7 @@ Zone America/Cayenne	-3:29:20 -	LMT	1911 Jul
 
 # Guyana
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
+Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar    # Georgetown
 			-3:45	-	GBGT	1966 May 26 # Br Guiana Time
 			-3:45	-	GYT	1975 Jul 31 # Guyana Time
 			-3:00	-	GYT	1991
@@ -1555,8 +1477,8 @@ Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
 # Paraguay
 #
 # From Paul Eggert (2006-03-22):
-# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
-# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
+# Shanks & Pottenger say that spring transitions are 01:00 -> 02:00,
+# and autumn transitions are 00:00 -> 23:00.  Go with pre-1999
 # editions of Shanks, and with the IATA, who say transitions occur at 00:00.
 #
 # From Waldemar Villamayor-Venialbo (2013-09-20):
@@ -1582,9 +1504,8 @@ Rule	Para	1996	only	-	Mar	 1	0:00	0	-
 # (10-01).
 #
 # Translated by Gwillim Law (2001-02-27) from
-# 
-# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
-# :
+# Noticias, a daily paper in Asunción, Paraguay (2000-10-01):
+# http://www.diarionoticias.com.py/011000/nacional/naciona1.htm
 # Starting at 0:00 today, the clock will be set forward 60 minutes, in
 # fulfillment of Decree No. 7,273 of the Executive Power....  The time change
 # system has been operating for several years.  Formerly there was a separate
@@ -1605,21 +1526,18 @@ Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
 Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
 Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
 #
-# From Jesper Norgaard Welen (2005-01-02):
+# From Jesper Nørgaard Welen (2005-01-02):
 # There are several sources that claim that Paraguay made
 # a timezone rule change in autumn 2004.
 # From Steffen Thorsen (2005-01-05):
 # Decree 1,867 (2004-03-05)
-# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
-# 
+# From Carlos Raúl Perasso via Jesper Nørgaard Welen (2006-10-13)
+# http://www.presidencia.gov.py/decretos/D1867.pdf
 Rule	Para	2004	2009	-	Oct	Sun>=15	0:00	1:00	S
 Rule	Para	2005	2009	-	Mar	Sun>=8	0:00	0	-
-# From Carlos Raul Perasso (2010-02-18):
-# By decree number 3958 issued yesterday (
-# 
+# From Carlos Raúl Perasso (2010-02-18):
+# By decree number 3958 issued yesterday
 # http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
-# 
-# )
 # Paraguay changes its DST schedule, postponing the March rule to April and
 # modifying the October date. The decree reads:
 # ...
@@ -1635,25 +1553,25 @@ Rule	Para	2010	2012	-	Apr	Sun>=8	0:00	0	-
 # Paraguay will end DST on 2013-03-24 00:00....
 # http://www.ande.gov.py/interna.php?id=1075
 #
-# From Carlos Raul Perasso (2013-03-15):
+# From Carlos Raúl Perasso (2013-03-15):
 # The change in Paraguay is now final.  Decree number 10780
 # http://www.presidencia.gov.py/uploads/pdf/presidencia-3b86ff4b691c79d4f5927ca964922ec74772ce857c02ca054a52a37b49afc7fb.pdf
-# From Carlos Raul Perasso (2014-02-28):
+# From Carlos Raúl Perasso (2014-02-28):
 # Decree 1264 can be found at:
 # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf
 Rule	Para	2013	max	-	Mar	Sun>=22	0:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Asuncion	-3:50:40 -	LMT	1890
-			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
-			-4:00	-	PYT	1972 Oct # Paraguay Time
+			-3:50:40 -	AMT	1931 Oct 10 # Asunción Mean Time
+			-4:00	-	PYT	1972 Oct    # Paraguay Time
 			-3:00	-	PYT	1974 Apr
 			-4:00	Para	PY%sT
 
 # Peru
 #
-# 
-# From Evelyn C. Leeper via Mark Brader (2003-10-26):
+# From Evelyn C. Leeper via Mark Brader (2003-10-26)
+# :
 # When we were in Peru in 1985-1986, they apparently switched over
 # sometime between December 29 and January 3 while we were on the Amazon.
 #
@@ -1679,7 +1597,7 @@ Zone	America/Lima	-5:08:12 -	LMT	1890
 
 # South Georgia
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
+Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890 # Grytviken
 			-2:00	-	GST	# South Georgia Time
 
 # South Sandwich Is
@@ -1689,9 +1607,9 @@ Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Paramaribo	-3:40:40 -	LMT	1911
 			-3:40:52 -	PMT	1935     # Paramaribo Mean Time
-			-3:40:36 -	PMT	1945 Oct # The capital moved?
+			-3:40:36 -	PMT	1945 Oct    # The capital moved?
 			-3:30	-	NEGT	1975 Nov 20 # Dutch Guiana Time
-			-3:30	-	SRT	1984 Oct # Suriname Time
+			-3:30	-	SRT	1984 Oct    # Suriname Time
 			-3:00	-	SRT
 
 # Trinidad and Tobago
@@ -1706,7 +1624,7 @@ Link America/Port_of_Spain America/Grenada
 Link America/Port_of_Spain America/Guadeloupe
 Link America/Port_of_Spain America/Marigot	# St Martin (French part)
 Link America/Port_of_Spain America/Montserrat
-Link America/Port_of_Spain America/St_Barthelemy
+Link America/Port_of_Spain America/St_Barthelemy # St Barthélemy
 Link America/Port_of_Spain America/St_Kitts	# St Kitts & Nevis
 Link America/Port_of_Spain America/St_Lucia
 Link America/Port_of_Spain America/St_Thomas	# Virgin Islands (US)
@@ -1765,7 +1683,7 @@ Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
 Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
 Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
 # From Eduardo Cota (2004-09-20):
-# The uruguayan government has decreed a change in the local time....
+# The Uruguayan government has decreed a change in the local time....
 # http://www.presidencia.gub.uy/decretos/2004091502.htm
 Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
 # From Steffen Thorsen (2005-03-11):
@@ -1779,14 +1697,14 @@ Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
 # 02:00 local time, official time in Uruguay will be at GMT -2.
 Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
 Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
-# From Jesper Norgaard Welen (2006-09-06):
+# From Jesper Nørgaard Welen (2006-09-06):
 # http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
 Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
 Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
-			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
-			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
+			-3:44:44 -	MMT	1920 May  1 # Montevideo MT
+			-3:30	Uruguay	UY%sT	1942 Dec 14 # Uruguay Time
 			-3:00	Uruguay	UY%sT
 
 # Venezuela
@@ -1794,14 +1712,14 @@ Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
 # From John Stainforth (2007-11-28):
 # ... the change for Venezuela originally expected for 2007-12-31 has
 # been brought forward to 2007-12-09.  The official announcement was
-# published today in the "Gaceta Oficial de la Republica Bolivariana
-# de Venezuela, numero 38.819" (official document for all laws or
+# published today in the "Gaceta Oficial de la República Bolivariana
+# de Venezuela, número 38.819" (official document for all laws or
 # resolution publication)
 # http://www.globovision.com/news.php?nid=72208
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	America/Caracas	-4:27:44 -	LMT	1890
 			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
-			-4:30	-	VET	1965	     # Venezuela Time
-			-4:00	-	VET	2007 Dec  9 03:00
+			-4:30	-	VET	1965        # Venezuela Time
+			-4:00	-	VET	2007 Dec  9  3:00
 			-4:30	-	VET
diff --git a/jdk/make/data/tzdata/systemv b/jdk/make/data/tzdata/systemv
index f909f9c76db..c7b9a888e88 100644
--- a/jdk/make/data/tzdata/systemv
+++ b/jdk/make/data/tzdata/systemv
@@ -21,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# 
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
diff --git a/jdk/make/data/tzdata/zone.tab b/jdk/make/data/tzdata/zone.tab
index 7cec627fd95..45351ca8486 100644
--- a/jdk/make/data/tzdata/zone.tab
+++ b/jdk/make/data/tzdata/zone.tab
@@ -21,39 +21,27 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# TZ zone descriptions
+# tz zone descriptions (deprecated version)
 #
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 #
-# From Paul Eggert (2013-08-14):
+# From Paul Eggert (2014-07-31):
+# This file is intended as a backward-compatibility aid for older programs.
+# New programs should use zone1970.tab.  This file is like zone1970.tab (see
+# zone1970.tab's comments), but with the following additional restrictions:
 #
-# This file contains a table where each row stands for an area that is
-# the intersection of a region identified by a country code and of a
-# zone where civil clocks have agreed since 1970.  The columns of the
-# table are as follows:
+# 1.  This file contains only ASCII characters.
+# 2.  The first data column contains exactly one country code.
 #
-# 1.  ISO 3166 2-character country code.  See the file 'iso3166.tab'.
-# 2.  Latitude and longitude of the area's principal location
-#     in ISO 6709 sign-degrees-minutes-seconds format,
-#     either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS,
-#     first latitude (+ is north), then longitude (+ is east).
-# 3.  Zone name used in value of TZ environment variable.
-#     Please see the 'Theory' file for how zone names are chosen.
-#     If multiple zones overlap a country, each has a row in the
-#     table, with column 1 being duplicated.
-# 4.  Comments; present if and only if the country has multiple rows.
-#
-# Columns are separated by a single tab.
-# The table is sorted first by country, then an order within the country that
-# (1) makes some geographical sense, and
-# (2) puts the most populous areas first, where that does not contradict (1).
-#
-# Lines beginning with '#' are comments.
+# Because of (2), each row stands for an area that is the intersection
+# of a region identified by a country code and of a zone where civil
+# clocks have agreed since 1970; this is a narrower definition than
+# that of zone1970.tab.
 #
 # This table is intended as an aid for users, to help them select time
-# zone data appropriate for their practical needs.  It is not intended
-# to take or endorse any position on legal or territorial claims.
+# zone data entries appropriate for their practical needs.  It is not
+# intended to take or endorse any position on legal or territorial claims.
 #
 #country-
 #code	coordinates	TZ			comments
@@ -72,7 +60,7 @@ AQ	-6736+06253	Antarctica/Mawson	Mawson Station, Holme Bay
 AQ	-6835+07758	Antarctica/Davis	Davis Station, Vestfold Hills
 AQ	-6617+11031	Antarctica/Casey	Casey Station, Bailey Peninsula
 AQ	-7824+10654	Antarctica/Vostok	Vostok Station, Lake Vostok
-AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Terre Adelie
+AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Adelie Land
 AQ	-690022+0393524	Antarctica/Syowa	Syowa Station, E Ongul I
 AQ	-720041+0023206	Antarctica/Troll	Troll Station, Queen Maud Land
 AR	-3436-05827	America/Argentina/Buenos_Aires	Buenos Aires (BA, CF)
@@ -151,7 +139,7 @@ CA	+4901-08816	America/Nipigon	Eastern Time - Ontario & Quebec - places that did
 CA	+4823-08915	America/Thunder_Bay	Eastern Time - Thunder Bay, Ontario
 CA	+6344-06828	America/Iqaluit	Eastern Time - east Nunavut - most locations
 CA	+6608-06544	America/Pangnirtung	Eastern Time - Pangnirtung, Nunavut
-CA	+744144-0944945	America/Resolute	Central Standard Time - Resolute, Nunavut
+CA	+744144-0944945	America/Resolute	Central Time - Resolute, Nunavut
 CA	+484531-0913718	America/Atikokan	Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut
 CA	+624900-0920459	America/Rankin_Inlet	Central Time - central Nunavut
 CA	+4953-09709	America/Winnipeg	Central Time - Manitoba & west Ontario
@@ -176,13 +164,10 @@ CH	+4723+00832	Europe/Zurich
 CI	+0519-00402	Africa/Abidjan
 CK	-2114-15946	Pacific/Rarotonga
 CL	-3327-07040	America/Santiago	most locations
-CL	-2709-10926	Pacific/Easter	Easter Island & Sala y Gomez
+CL	-2709-10926	Pacific/Easter	Easter Island
 CM	+0403+00942	Africa/Douala
-CN	+3114+12128	Asia/Shanghai	east China - Beijing, Guangdong, Shanghai, etc.
-CN	+4545+12641	Asia/Harbin	Heilongjiang (except Mohe), Jilin
-CN	+2934+10635	Asia/Chongqing	central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc.
-CN	+4348+08735	Asia/Urumqi	most of Tibet & Xinjiang
-CN	+3929+07559	Asia/Kashgar	west Tibet & Xinjiang
+CN	+3114+12128	Asia/Shanghai	Beijing Time
+CN	+4348+08735	Asia/Urumqi	Xinjiang Time
 CO	+0436-07405	America/Bogota
 CR	+0956-08405	America/Costa_Rica
 CU	+2308-08222	America/Havana
@@ -364,24 +349,26 @@ RE	-2052+05528	Indian/Reunion
 RO	+4426+02606	Europe/Bucharest
 RS	+4450+02030	Europe/Belgrade
 RU	+5443+02030	Europe/Kaliningrad	Moscow-01 - Kaliningrad
-RU	+5545+03735	Europe/Moscow	Moscow+00 - west Russia
-RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
-RU	+5312+05009	Europe/Samara	Moscow+00 - Samara, Udmurtia
+RU	+554521+0373704	Europe/Moscow	Moscow+00 - west Russia
 RU	+4457+03406	Europe/Simferopol	Moscow+00 - Crimea
+RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
+RU	+5312+05009	Europe/Samara	Moscow+00 (Moscow+01 after 2014-10-26) - Samara, Udmurtia
 RU	+5651+06036	Asia/Yekaterinburg	Moscow+02 - Urals
 RU	+5500+07324	Asia/Omsk	Moscow+03 - west Siberia
 RU	+5502+08255	Asia/Novosibirsk	Moscow+03 - Novosibirsk
-RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 - Novokuznetsk
+RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 (Moscow+04 after 2014-10-26) - Kemerovo
 RU	+5601+09250	Asia/Krasnoyarsk	Moscow+04 - Yenisei River
 RU	+5216+10420	Asia/Irkutsk	Moscow+05 - Lake Baikal
+RU	+5203+11328	Asia/Chita	Moscow+06 (Moscow+05 after 2014-10-26) - Zabaykalsky
 RU	+6200+12940	Asia/Yakutsk	Moscow+06 - Lena River
 RU	+623923+1353314	Asia/Khandyga	Moscow+06 - Tomponsky, Ust-Maysky
 RU	+4310+13156	Asia/Vladivostok	Moscow+07 - Amur River
 RU	+4658+14242	Asia/Sakhalin	Moscow+07 - Sakhalin Island
 RU	+643337+1431336	Asia/Ust-Nera	Moscow+07 - Oymyakonsky
-RU	+5934+15048	Asia/Magadan	Moscow+08 - Magadan
-RU	+5301+15839	Asia/Kamchatka	Moscow+08 - Kamchatka
-RU	+6445+17729	Asia/Anadyr	Moscow+08 - Bering Sea
+RU	+5934+15048	Asia/Magadan	Moscow+08 (Moscow+07 after 2014-10-26) - Magadan
+RU	+6728+15343	Asia/Srednekolymsk	Moscow+08 - E Sakha, N Kuril Is
+RU	+5301+15839	Asia/Kamchatka	Moscow+08 (Moscow+09 after 2014-10-26) - Kamchatka
+RU	+6445+17729	Asia/Anadyr	Moscow+08 (Moscow+09 after 2014-10-26) - Bering Sea
 RW	-0157+03004	Africa/Kigali
 SA	+2438+04643	Asia/Riyadh
 SB	-0932+16012	Pacific/Guadalcanal
@@ -448,13 +435,13 @@ US	+394421-1045903	America/Denver	Mountain Time
 US	+433649-1161209	America/Boise	Mountain Time - south Idaho & east Oregon
 US	+332654-1120424	America/Phoenix	Mountain Standard Time - Arizona (except Navajo)
 US	+340308-1181434	America/Los_Angeles	Pacific Time
+US	+550737-1313435	America/Metlakatla	Pacific Standard Time - Annette Island, Alaska
 US	+611305-1495401	America/Anchorage	Alaska Time
 US	+581807-1342511	America/Juneau	Alaska Time - Alaska panhandle
 US	+571035-1351807	America/Sitka	Alaska Time - southeast Alaska panhandle
 US	+593249-1394338	America/Yakutat	Alaska Time - Alaska panhandle neck
 US	+643004-1652423	America/Nome	Alaska Time - west Alaska
 US	+515248-1763929	America/Adak	Aleutian Islands
-US	+550737-1313435	America/Metlakatla	Metlakatla Time - Annette Island
 US	+211825-1575130	Pacific/Honolulu	Hawaii
 UY	-3453-05611	America/Montevideo
 UZ	+3940+06648	Asia/Samarkand	west Uzbekistan
diff --git a/jdk/src/java.base/share/classes/java/lang/Integer.java b/jdk/src/java.base/share/classes/java/lang/Integer.java
index 94b0aff7970..d22ce9bef35 100644
--- a/jdk/src/java.base/share/classes/java/lang/Integer.java
+++ b/jdk/src/java.base/share/classes/java/lang/Integer.java
@@ -592,37 +592,6 @@ public final class Integer extends Number implements Comparable {
         }
     }
 
-    /**
-     * Parses the {@link CharSequence} argument as a signed {@code int} in the
-     * specified {@code radix}, beginning at the specified {@code beginIndex}
-     * and extending to the end of the sequence.
-     *
-     * 

The method does not take steps to guard against the - * {@code CharSequence} being mutated while parsing. - * - * @param s the {@code CharSequence} containing the {@code int} - * representation to be parsed - * @param radix the radix to be used while parsing {@code s}. - * @param beginIndex the beginning index, inclusive. - * @return the signed {@code int} represented by the subsequence in - * the specified radix. - * @throws NullPointerException if {@code s} is null. - * @throws IndexOutOfBoundsException if {@code beginIndex} is - * negative, or if {@code beginIndex} is greater than - * {@code s.length()}. - * @throws NumberFormatException if the {@code CharSequence} does not - * contain a parsable {@code int} in the specified - * {@code radix}, or if {@code radix} is either smaller than - * {@link java.lang.Character#MIN_RADIX} or larger than - * {@link java.lang.Character#MAX_RADIX}. - * @since 1.9 - */ - public static int parseInt(CharSequence s, int radix, int beginIndex) - throws NumberFormatException { - // forces an implicit null check of s - return parseInt(s, radix, beginIndex, s.length()); - } - /** * Parses the {@link CharSequence} argument as a signed {@code int} in the * specified {@code radix}, beginning at the specified {@code beginIndex} @@ -633,9 +602,9 @@ public final class Integer extends Number implements Comparable { * * @param s the {@code CharSequence} containing the {@code int} * representation to be parsed - * @param radix the radix to be used while parsing {@code s}. * @param beginIndex the beginning index, inclusive. * @param endIndex the ending index, exclusive. + * @param radix the radix to be used while parsing {@code s}. * @return the signed {@code int} represented by the subsequence in * the specified radix. * @throws NullPointerException if {@code s} is null. @@ -650,7 +619,7 @@ public final class Integer extends Number implements Comparable { * {@link java.lang.Character#MAX_RADIX}. * @since 1.9 */ - public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex) + public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { s = Objects.requireNonNull(s); @@ -690,7 +659,7 @@ public final class Integer extends Number implements Comparable { int result = 0; while (i < endIndex) { // Accumulating negatively avoids surprises near MAX_VALUE - int digit = Character.digit(s.charAt(i++), radix); + int digit = Character.digit(s.charAt(i), radix); if (digit < 0 || result < multmin) { throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i); @@ -700,6 +669,7 @@ public final class Integer extends Number implements Comparable { throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i); } + i++; result -= digit; } return negative ? result : -result; @@ -805,37 +775,6 @@ public final class Integer extends Number implements Comparable { } } - /** - * Parses the {@link CharSequence} argument as an unsigned {@code int} in - * the specified {@code radix}, beginning at the specified - * {@code beginIndex} and extending to the end of the sequence. - * - *

The method does not take steps to guard against the - * {@code CharSequence} being mutated while parsing. - * - * @param s the {@code CharSequence} containing the unsigned - * {@code int} representation to be parsed - * @param radix the radix to be used while parsing {@code s}. - * @param beginIndex the beginning index, inclusive. - * @return the unsigned {@code int} represented by the subsequence in - * the specified radix. - * @throws NullPointerException if {@code s} is null. - * @throws IndexOutOfBoundsException if {@code beginIndex} is - * negative, or if {@code beginIndex} is greater than - * {@code s.length()}. - * @throws NumberFormatException if the {@code CharSequence} does not - * contain a parsable unsigned {@code int} in the specified - * {@code radix}, or if {@code radix} is either smaller than - * {@link java.lang.Character#MIN_RADIX} or larger than - * {@link java.lang.Character#MAX_RADIX}. - * @since 1.9 - */ - public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex) - throws NumberFormatException { - // forces an implicit null check of s - return parseUnsignedInt(s, radix, beginIndex, s.length()); - } - /** * Parses the {@link CharSequence} argument as an unsigned {@code int} in * the specified {@code radix}, beginning at the specified @@ -846,9 +785,9 @@ public final class Integer extends Number implements Comparable { * * @param s the {@code CharSequence} containing the unsigned * {@code int} representation to be parsed - * @param radix the radix to be used while parsing {@code s}. * @param beginIndex the beginning index, inclusive. * @param endIndex the ending index, exclusive. + * @param radix the radix to be used while parsing {@code s}. * @return the unsigned {@code int} represented by the subsequence in * the specified radix. * @throws NullPointerException if {@code s} is null. @@ -863,7 +802,7 @@ public final class Integer extends Number implements Comparable { * {@link java.lang.Character#MAX_RADIX}. * @since 1.9 */ - public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex, int endIndex) + public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { s = Objects.requireNonNull(s); @@ -881,9 +820,9 @@ public final class Integer extends Number implements Comparable { } else { if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits (radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits - return parseInt(s, radix, start, start + len); + return parseInt(s, start, start + len, radix); } else { - long ell = Long.parseLong(s, radix, start, start + len); + long ell = Long.parseLong(s, start, start + len, radix); if ((ell & 0xffff_ffff_0000_0000L) == 0) { return (int) ell; } else { diff --git a/jdk/src/java.base/share/classes/java/lang/Long.java b/jdk/src/java.base/share/classes/java/lang/Long.java index 76caa77fac7..bcf33fccff8 100644 --- a/jdk/src/java.base/share/classes/java/lang/Long.java +++ b/jdk/src/java.base/share/classes/java/lang/Long.java @@ -604,37 +604,6 @@ public final class Long extends Number implements Comparable { } } - /** - * Parses the {@link CharSequence} argument as a signed {@code long} in - * the specified {@code radix}, beginning at the specified {@code beginIndex} - * and extending to the end of the sequence. - * - *

The method does not take steps to guard against the - * {@code CharSequence} being mutated while parsing. - * - * @param s the {@code CharSequence} containing the {@code long} - * representation to be parsed - * @param radix the radix to be used while parsing {@code s}. - * @param beginIndex the beginning index, inclusive. - * @return the signed {@code long} represented by the subsequence in - * the specified radix. - * @throws NullPointerException if {@code s} is null. - * @throws IndexOutOfBoundsException if {@code beginIndex} is - * negative, or if {@code beginIndex} is greater than - * {@code s.length()}. - * @throws NumberFormatException if the {@code CharSequence} does not - * contain a parsable {@code long} in the specified - * {@code radix}, or if {@code radix} is either smaller than - * {@link java.lang.Character#MIN_RADIX} or larger than - * {@link java.lang.Character#MAX_RADIX}. - * @since 1.9 - */ - public static long parseLong(CharSequence s, int radix, int beginIndex) - throws NumberFormatException { - // forces a null check of s - return parseLong(s, radix, beginIndex, s.length()); - } - /** * Parses the {@link CharSequence} argument as a signed {@code long} in * the specified {@code radix}, beginning at the specified @@ -645,9 +614,9 @@ public final class Long extends Number implements Comparable { * * @param s the {@code CharSequence} containing the {@code long} * representation to be parsed - * @param radix the radix to be used while parsing {@code s}. * @param beginIndex the beginning index, inclusive. * @param endIndex the ending index, exclusive. + * @param radix the radix to be used while parsing {@code s}. * @return the signed {@code long} represented by the subsequence in * the specified radix. * @throws NullPointerException if {@code s} is null. @@ -662,7 +631,7 @@ public final class Long extends Number implements Comparable { * {@link java.lang.Character#MAX_RADIX}. * @since 1.9 */ - public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex) + public static long parseLong(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { s = Objects.requireNonNull(s); @@ -702,7 +671,7 @@ public final class Long extends Number implements Comparable { long result = 0; while (i < endIndex) { // Accumulating negatively avoids surprises near MAX_VALUE - int digit = Character.digit(s.charAt(i++), radix); + int digit = Character.digit(s.charAt(i), radix); if (digit < 0 || result < multmin) { throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i); @@ -712,6 +681,7 @@ public final class Long extends Number implements Comparable { throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i); } + i++; result -= digit; } return negative ? result : -result; @@ -811,7 +781,7 @@ public final class Long extends Number implements Comparable { } // No need for range checks on len due to testing above. - long first = parseLong(s, radix, 0, len - 1); + long first = parseLong(s, 0, len - 1, radix); int second = Character.digit(s.charAt(len - 1), radix); if (second < 0) { throw new NumberFormatException("Bad digit at end of " + s); @@ -880,37 +850,6 @@ public final class Long extends Number implements Comparable { } } - /** - * Parses the {@link CharSequence} argument as an unsigned {@code long} in - * the specified {@code radix}, beginning at the specified - * {@code beginIndex} and extending to the end of the sequence. - * - *

The method does not take steps to guard against the - * {@code CharSequence} being mutated while parsing. - * - * @param s the {@code CharSequence} containing the unsigned - * {@code long} representation to be parsed - * @param radix the radix to be used while parsing {@code s}. - * @param beginIndex the beginning index, inclusive. - * @return the unsigned {@code long} represented by the subsequence in - * the specified radix. - * @throws NullPointerException if {@code s} is null. - * @throws IndexOutOfBoundsException if {@code beginIndex} is - * negative, or if {@code beginIndex} is greater than - * {@code s.length()}. - * @throws NumberFormatException if the {@code CharSequence} does not - * contain a parsable unsigned {@code long} in the specified - * {@code radix}, or if {@code radix} is either smaller than - * {@link java.lang.Character#MIN_RADIX} or larger than - * {@link java.lang.Character#MAX_RADIX}. - * @since 1.9 - */ - public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex) - throws NumberFormatException { - // forces a null check of s - return parseUnsignedLong(s, radix, beginIndex, s.length()); - } - /** * Parses the {@link CharSequence} argument as an unsigned {@code long} in * the specified {@code radix}, beginning at the specified @@ -921,9 +860,9 @@ public final class Long extends Number implements Comparable { * * @param s the {@code CharSequence} containing the unsigned * {@code long} representation to be parsed - * @param radix the radix to be used while parsing {@code s}. * @param beginIndex the beginning index, inclusive. * @param endIndex the ending index, exclusive. + * @param radix the radix to be used while parsing {@code s}. * @return the unsigned {@code long} represented by the subsequence in * the specified radix. * @throws NullPointerException if {@code s} is null. @@ -938,7 +877,7 @@ public final class Long extends Number implements Comparable { * {@link java.lang.Character#MAX_RADIX}. * @since 1.9 */ - public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex, int endIndex) + public static long parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { s = Objects.requireNonNull(s); @@ -955,11 +894,11 @@ public final class Long extends Number implements Comparable { } else { if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits - return parseLong(s, radix, start, start + len); + return parseLong(s, start, start + len, radix); } // No need for range checks on end due to testing above. - long first = parseLong(s, radix, start, start + len - 1); + long first = parseLong(s, start, start + len - 1, radix); int second = Character.digit(s.charAt(start + len - 1), radix); if (second < 0) { throw new NumberFormatException("Bad digit at end of " + diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index ce673fba2d4..00f57044624 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -2119,7 +2119,7 @@ public final class String * @since 1.5 */ public boolean contains(CharSequence s) { - return indexOf(s.toString()) > -1; + return indexOf(s.toString()) >= 0; } /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index f860c77e5e2..74f53e47906 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -50,31 +50,31 @@ import jdk.internal.org.objectweb.asm.Type; * * All bound arguments are encapsulated in dedicated species. */ -/* non-public */ abstract class BoundMethodHandle extends MethodHandle { +/*non-public*/ abstract class BoundMethodHandle extends MethodHandle { - /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) { + /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) { super(type, form); + assert(speciesData() == speciesData(form)); } // // BMH API and internals // - static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { + static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { // for some type signatures, there exist pre-defined concrete BMH classes try { switch (xtype) { case L_TYPE: - if (true) return bindSingle(type, form, x); // Use known fast path. - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x); + return bindSingle(type, form, x); // Use known fast path. case I_TYPE: - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x)); + return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x)); case J_TYPE: - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x); + return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor().invokeBasic(type, form, (long) x); case F_TYPE: - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x); + return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor().invokeBasic(type, form, (float) x); case D_TYPE: - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x); + return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor().invokeBasic(type, form, (double) x); default : throw newInternalError("unexpected xtype: " + xtype); } } catch (Throwable t) { @@ -82,49 +82,61 @@ import jdk.internal.org.objectweb.asm.Type; } } - static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) { - return new Species_L(type, form, x); + /*non-public*/ + LambdaFormEditor editor() { + return form.editor(); } - MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) { - try { - switch (xtype) { - case L_TYPE: return copyWithExtendL(type, form, x); - case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x)); - case J_TYPE: return copyWithExtendJ(type, form, (long) x); - case F_TYPE: return copyWithExtendF(type, form, (float) x); - case D_TYPE: return copyWithExtendD(type, form, (double) x); - } - } catch (Throwable t) { - throw newInternalError(t); + static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) { + return Species_L.make(type, form, x); + } + + @Override // there is a default binder in the super class, for 'L' types only + /*non-public*/ + BoundMethodHandle bindArgumentL(int pos, Object value) { + return editor().bindArgumentL(this, pos, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentI(int pos, int value) { + return editor().bindArgumentI(this, pos, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentJ(int pos, long value) { + return editor().bindArgumentJ(this, pos, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentF(int pos, float value) { + return editor().bindArgumentF(this, pos, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentD(int pos, double value) { + return editor().bindArgumentD(this, pos, value); + } + + @Override + BoundMethodHandle rebind() { + if (!tooComplex()) { + return this; } - throw newInternalError("unexpected type: " + xtype); + return makeReinvoker(this); } - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - MethodType type = type().dropParameterTypes(pos, pos+1); - LambdaForm form = internalForm().bind(1+pos, speciesData()); - return cloneExtend(type, form, basicType, value); + private boolean tooComplex() { + return (fieldCount() > FIELD_COUNT_THRESHOLD || + form.expressionCount() > FORM_EXPRESSION_THRESHOLD); } + private static final int FIELD_COUNT_THRESHOLD = 12; // largest convenient BMH field count + private static final int FORM_EXPRESSION_THRESHOLD = 24; // largest convenient BMH expression count - @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops)); - try { - return copyWith(srcType, form); - } catch (Throwable t) { - throw newInternalError(t); - } - } - - @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - try { - return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList()))); - } catch (Throwable t) { - throw newInternalError(t); - } + /** + * A reinvoker MH has this form: + * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }} + */ + static BoundMethodHandle makeReinvoker(MethodHandle target) { + LambdaForm form = DelegatingMethodHandle.makeReinvokerForm( + target, MethodTypeForm.LF_REBIND, + Species_L.SPECIES_DATA, Species_L.SPECIES_DATA.getterFunction(0)); + return Species_L.make(target.type(), form, target); } /** @@ -133,14 +145,22 @@ import jdk.internal.org.objectweb.asm.Type; */ /*non-public*/ abstract SpeciesData speciesData(); + /*non-public*/ static SpeciesData speciesData(LambdaForm form) { + Object c = form.names[0].constraint; + if (c instanceof SpeciesData) + return (SpeciesData) c; + // if there is no BMH constraint, then use the null constraint + return SpeciesData.EMPTY; + } + /** * Return the number of fields in this BMH. Equivalent to speciesData().fieldCount(). */ /*non-public*/ abstract int fieldCount(); @Override - final Object internalProperties() { - return "/BMH="+internalValues(); + Object internalProperties() { + return "\n& BMH="+internalValues(); } @Override @@ -178,15 +198,6 @@ import jdk.internal.org.objectweb.asm.Type; /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg); /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg); - // The following is a grossly irregular hack: - @Override MethodHandle reinvokerTarget() { - try { - return (MethodHandle) arg(0); - } catch (Throwable ex) { - throw newInternalError(ex); - } - } - // // concrete BMH classes required to close bootstrap loops // @@ -198,8 +209,6 @@ import jdk.internal.org.objectweb.asm.Type; super(mt, lf); this.argL0 = argL0; } - // The following is a grossly irregular hack: - @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; } @Override /*non-public*/ SpeciesData speciesData() { return SPECIES_DATA; @@ -219,7 +228,7 @@ import jdk.internal.org.objectweb.asm.Type; @Override /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { try { - return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); + return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -227,7 +236,7 @@ import jdk.internal.org.objectweb.asm.Type; @Override /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { try { - return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); + return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -235,7 +244,7 @@ import jdk.internal.org.objectweb.asm.Type; @Override /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { try { - return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); + return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, narg); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -243,7 +252,7 @@ import jdk.internal.org.objectweb.asm.Type; @Override /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { try { - return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); + return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, narg); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -251,7 +260,7 @@ import jdk.internal.org.objectweb.asm.Type; @Override /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { try { - return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); + return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, narg); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -268,18 +277,20 @@ import jdk.internal.org.objectweb.asm.Type; * The fields are immutable; their values are fully specified at object construction. * Each BMH type supplies an array of getter functions which may be used in lambda forms. * A BMH is constructed by cloning a shorter BMH and adding one or more new field values. - * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields. + * The shortest possible BMH has zero fields; its class is SimpleMethodHandle. + * BMH species are not interrelated by subtyping, even though it would appear that + * a shorter BMH could serve as a supertype of a longer one which extends it. */ static class SpeciesData { - final String typeChars; - final BasicType[] typeCodes; - final Class clazz; + private final String typeChars; + private final BasicType[] typeCodes; + private final Class clazz; // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH // Therefore, we need a non-final link in the chain. Use array elements. - final MethodHandle[] constructor; - final MethodHandle[] getters; - final NamedFunction[] nominalGetters; - final SpeciesData[] extensions; + @Stable private final MethodHandle[] constructor; + @Stable private final MethodHandle[] getters; + @Stable private final NamedFunction[] nominalGetters; + @Stable private final SpeciesData[] extensions; /*non-public*/ int fieldCount() { return typeCodes.length; @@ -290,9 +301,14 @@ import jdk.internal.org.objectweb.asm.Type; /*non-public*/ char fieldTypeChar(int i) { return typeChars.charAt(i); } - + Object fieldSignature() { + return typeChars; + } + public Class fieldHolder() { + return clazz; + } public String toString() { - return "SpeciesData["+(isPlaceholder() ? "" : clazz.getSimpleName())+":"+typeChars+"]"; + return "SpeciesData<"+fieldSignature()+">"; } /** @@ -301,7 +317,20 @@ import jdk.internal.org.objectweb.asm.Type; * getter. */ NamedFunction getterFunction(int i) { - return nominalGetters[i]; + NamedFunction nf = nominalGetters[i]; + assert(nf.memberDeclaringClassOrNull() == fieldHolder()); + assert(nf.returnType() == fieldType(i)); + return nf; + } + + NamedFunction[] getterFunctions() { + return nominalGetters; + } + + MethodHandle[] getterHandles() { return getters; } + + MethodHandle constructor() { + return constructor[0]; } static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class); @@ -324,7 +353,7 @@ import jdk.internal.org.objectweb.asm.Type; private void initForBootstrap() { assert(!INIT_DONE); - if (constructor[0] == null) { + if (constructor() == null) { String types = typeChars; Factory.makeCtors(clazz, types, this.constructor); Factory.makeGetters(clazz, types, this.getters); @@ -508,19 +537,19 @@ import jdk.internal.org.objectweb.asm.Type; * return new Species_LLI(mt, lf, argL0, argL1, argI2); * } * final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { - * return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); + * return SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { - * return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); + * return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { - * return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); + * return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { - * return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); + * return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { - * return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); + * return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * } *

@@ -575,16 +604,6 @@ import jdk.internal.org.objectweb.asm.Type; mv.visitMaxs(0, 0); mv.visitEnd(); - // emit implementation of reinvokerTarget() - mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG); - mv.visitTypeInsn(CHECKCAST, MH); - mv.visitInsn(ARETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - // emit implementation of speciesData() mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null); mv.visitCode(); @@ -653,16 +672,14 @@ import jdk.internal.org.objectweb.asm.Type; char btChar = type.basicTypeChar(); mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE); mv.visitCode(); - // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg) + // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg) // obtain constructor mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG); int iconstInsn = ICONST_0 + ord; assert(iconstInsn <= ICONST_5); mv.visitInsn(iconstInsn); mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false); - mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false); // load mt, lf mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java index 949364bcec4..10ac1c0716e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -102,7 +102,7 @@ public class CallSite { */ /*package-private*/ CallSite(MethodType type) { - target = type.invokers().uninitializedCallSite(); + target = makeUninitializedCallSite(type); } /** @@ -211,27 +211,40 @@ public class CallSite { public abstract MethodHandle dynamicInvoker(); /*non-public*/ MethodHandle makeDynamicInvoker() { - MethodHandle getTarget = GET_TARGET.bindReceiver(this); + MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); return MethodHandles.foldArguments(invoker, getTarget); } private static final MethodHandle GET_TARGET; + private static final MethodHandle THROW_UCS; static { try { GET_TARGET = IMPL_LOOKUP. findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); + THROW_UCS = IMPL_LOOKUP. + findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Object.class, Object[].class)); } catch (ReflectiveOperationException e) { throw newInternalError(e); } } /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */ - /*package-private*/ - static Empty uninitializedCallSite() { + private static Object uninitializedCallSite(Object... ignore) { throw new IllegalStateException("uninitialized call site"); } + private MethodHandle makeUninitializedCallSite(MethodType targetType) { + MethodType basicType = targetType.basicType(); + MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS); + if (invoker == null) { + invoker = THROW_UCS.asType(basicType); + invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker); + } + // unchecked view is OK since no values will be received or returned + return invoker.viewAsType(targetType, false); + } + // unsafe stuff: private static final long TARGET_OFFSET; static { @@ -319,7 +332,7 @@ public class CallSite { throw new ClassCastException("bootstrap method failed to produce a CallSite"); } if (!site.getTarget().type().equals(type)) - throw new WrongMethodTypeException("wrong type: "+site.getTarget()); + throw wrongTargetType(site.getTarget(), type); } catch (Throwable ex) { BootstrapMethodError bex; if (ex instanceof BootstrapMethodError) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java new file mode 100644 index 00000000000..63ba8fea5b2 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.invoke; + +import java.util.Arrays; +import static java.lang.invoke.LambdaForm.*; +import static java.lang.invoke.MethodHandleStatics.*; + +/** + * A method handle whose invocation behavior is determined by a target. + * The delegating MH itself can hold extra "intentions" beyond the simple behavior. + * @author jrose + */ +/*non-public*/ +abstract class DelegatingMethodHandle extends MethodHandle { + protected DelegatingMethodHandle(MethodHandle target) { + this(target.type(), target); + } + + protected DelegatingMethodHandle(MethodType type, MethodHandle target) { + super(type, chooseDelegatingForm(target)); + } + + /** Define this to extract the delegated target which supplies the invocation behavior. */ + abstract protected MethodHandle getTarget(); + + @Override + abstract MethodHandle asTypeUncached(MethodType newType); + + @Override + MemberName internalMemberName() { + return getTarget().internalMemberName(); + } + + @Override + boolean isInvokeSpecial() { + return getTarget().isInvokeSpecial(); + } + + @Override + Class internalCallerClass() { + return getTarget().internalCallerClass(); + } + + @Override + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + // FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs + throw newIllegalArgumentException("do not use this"); + } + + @Override + String internalProperties() { + return "\n& Class="+getClass().getSimpleName()+ + "\n& Target="+getTarget().debugString(); + } + + @Override + BoundMethodHandle rebind() { + return getTarget().rebind(); + } + + private static LambdaForm chooseDelegatingForm(MethodHandle target) { + if (target instanceof SimpleMethodHandle) + return target.internalForm(); // no need for an indirection + return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); + } + + /** Create a LF which simply reinvokes a target of the given basic type. */ + static LambdaForm makeReinvokerForm(MethodHandle target, + int whichCache, + Object constraint, + NamedFunction getTargetFn) { + MethodType mtype = target.type().basicType(); + boolean customized = (whichCache < 0 || + mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY); + LambdaForm form; + if (!customized) { + form = mtype.form().cachedLambdaForm(whichCache); + if (form != null) return form; + } + final int THIS_DMH = 0; + final int ARG_BASE = 1; + final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); + int nameCursor = ARG_LIMIT; + final int NEXT_MH = customized ? -1 : nameCursor++; + final int REINVOKE = nameCursor++; + LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); + assert(names.length == nameCursor); + names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint); + Object[] targetArgs; + if (customized) { + targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); + names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself + } else { + names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]); + targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class); + targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH + names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); + } + String debugString; + switch(whichCache) { + case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break; + case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break; + default: debugString = "MH.reinvoke"; break; + } + form = new LambdaForm(debugString, ARG_LIMIT, names); + if (!customized) { + form = mtype.form().setCachedLambdaForm(whichCache, form); + } + return form; + } + + private static final NamedFunction NF_getTarget; + static { + try { + NF_getTarget = new NamedFunction(DelegatingMethodHandle.class + .getDeclaredMethod("getTarget")); + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index 0fbc4619e22..e9d2526cd8d 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -59,6 +59,7 @@ class DirectMethodHandle extends MethodHandle { MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind()); m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null); if (m != null && m.isPublic()) { + assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong member = m; } } @@ -125,61 +126,31 @@ class DirectMethodHandle extends MethodHandle { return new Constructor(mtype, lform, ctor, init, instanceClass); } + @Override + BoundMethodHandle rebind() { + return BoundMethodHandle.makeReinvoker(this); + } + + @Override + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + assert(this.getClass() == DirectMethodHandle.class); // must override in subclasses + return new DirectMethodHandle(mt, lf, member); + } + @Override String internalProperties() { - return "/DMH="+member.toString(); + return "\n& DMH.MN="+internalMemberName(); } //// Implementation methods. @Override - MethodHandle viewAsType(MethodType newType) { - return new DirectMethodHandle(newType, form, member); - } - @Override @ForceInline MemberName internalMemberName() { return member; } - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - // If the member needs dispatching, do so. - if (pos == 0 && basicType == L_TYPE) { - DirectMethodHandle concrete = maybeRebind(value); - if (concrete != null) - return concrete.bindReceiver(value); - } - return super.bindArgument(pos, basicType, value); - } - - @Override - MethodHandle bindReceiver(Object receiver) { - // If the member needs dispatching, do so. - DirectMethodHandle concrete = maybeRebind(receiver); - if (concrete != null) - return concrete.bindReceiver(receiver); - return super.bindReceiver(receiver); - } - private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); - private DirectMethodHandle maybeRebind(Object receiver) { - if (receiver != null) { - switch (member.getReferenceKind()) { - case REF_invokeInterface: - case REF_invokeVirtual: - // Pre-dispatch the member. - Class concreteClass = receiver.getClass(); - MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial); - concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass); - if (concrete != null) - return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete); - break; - } - } - return null; - } - /** * Create a LF which can invoke the given method. * Cache and share this structure among all methods with @@ -260,9 +231,10 @@ class DirectMethodHandle extends MethodHandle { } else { names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]); } + assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]); Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class); assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args! - int result = LambdaForm.LAST_RESULT; + int result = LAST_RESULT; if (doesAlloc) { assert(outArgs[outArgs.length-2] == names[NEW_OBJ]); // got to move this one System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2); @@ -277,6 +249,16 @@ class DirectMethodHandle extends MethodHandle { return lform; } + static Object findDirectMethodHandle(Name name) { + if (name.function == Lazy.NF_internalMemberName || + name.function == Lazy.NF_internalMemberNameEnsureInit || + name.function == Lazy.NF_constructorMethod) { + assert(name.arguments.length == 1); + return name.arguments[0]; + } + return null; + } + private static void maybeCompile(LambdaForm lform, MemberName m) { if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class)) // Help along bootstrapping... @@ -389,8 +371,8 @@ class DirectMethodHandle extends MethodHandle { return true; } @Override - MethodHandle viewAsType(MethodType newType) { - return new Special(newType, form, member); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Special(mt, lf, member); } } @@ -407,8 +389,8 @@ class DirectMethodHandle extends MethodHandle { assert(initMethod.isResolved()); } @Override - MethodHandle viewAsType(MethodType newType) { - return new Constructor(newType, form, member, initMethod, instanceClass); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Constructor(mt, lf, member, initMethod, instanceClass); } } @@ -437,8 +419,8 @@ class DirectMethodHandle extends MethodHandle { return fieldType.cast(obj); } @Override - MethodHandle viewAsType(MethodType newType) { - return new Accessor(newType, form, member, fieldOffset); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Accessor(mt, lf, member, fieldOffset); } } @@ -480,8 +462,8 @@ class DirectMethodHandle extends MethodHandle { return fieldType.cast(obj); } @Override - MethodHandle viewAsType(MethodType newType) { - return new StaticAccessor(newType, form, member, staticBase, staticOffset); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new StaticAccessor(mt, lf, member, staticBase, staticOffset); } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 58e56dd246a..0bfa6e32a98 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -25,21 +25,20 @@ package java.lang.invoke; -import sun.invoke.util.VerifyAccess; -import static java.lang.invoke.LambdaForm.*; - -import sun.invoke.util.Wrapper; - import java.io.*; import java.util.*; +import java.lang.reflect.Modifier; import jdk.internal.org.objectweb.asm.*; -import java.lang.reflect.*; +import static java.lang.invoke.LambdaForm.*; +import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; -import static java.lang.invoke.LambdaForm.BasicType.*; + +import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyType; +import sun.invoke.util.Wrapper; import sun.reflect.misc.ReflectUtil; /** @@ -74,7 +73,11 @@ class InvokerBytecodeGenerator { private final LambdaForm lambdaForm; private final String invokerName; private final MethodType invokerType; - private final int[] localsMap; + + /** Info about local variables in compiled lambda form */ + private final int[] localsMap; // index + private final BasicType[] localTypes; // basic type + private final Class[] localClasses; // type /** ASM bytecode generation. */ private ClassWriter cw; @@ -83,6 +86,7 @@ class InvokerBytecodeGenerator { private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory(); private static final Class HOST_CLASS = LambdaForm.class; + /** Main constructor; other constructors delegate to this one. */ private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize, String className, String invokerName, MethodType invokerType) { if (invokerName.contains(".")) { @@ -98,18 +102,26 @@ class InvokerBytecodeGenerator { this.lambdaForm = lambdaForm; this.invokerName = invokerName; this.invokerType = invokerType; - this.localsMap = new int[localsMapSize]; + this.localsMap = new int[localsMapSize+1]; + // last entry of localsMap is count of allocated local slots + this.localTypes = new BasicType[localsMapSize+1]; + this.localClasses = new Class[localsMapSize+1]; } + /** For generating LambdaForm interpreter entry points. */ private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) { this(null, invokerType.parameterCount(), className, invokerName, invokerType); // Create an array to map name indexes to locals indexes. + localTypes[localTypes.length - 1] = V_TYPE; for (int i = 0; i < localsMap.length; i++) { localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i); + if (i < invokerType.parameterCount()) + localTypes[i] = basicType(invokerType.parameterType(i)); } } + /** For generating customized code for a single LambdaForm. */ private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) { this(form, form.names.length, className, form.debugName, invokerType); @@ -117,7 +129,11 @@ class InvokerBytecodeGenerator { Name[] names = form.names; for (int i = 0, index = 0; i < localsMap.length; i++) { localsMap[i] = index; - index += names[i].type.basicTypeSlots(); + if (i < names.length) { + BasicType type = names[i].type(); + index += type.basicTypeSlots(); + localTypes[i] = type; + } } } @@ -148,7 +164,6 @@ class InvokerBytecodeGenerator { static void maybeDump(final String className, final byte[] classFile) { if (DUMP_CLASS_FILES) { - System.out.println("dump: " + className); java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { @@ -156,6 +171,7 @@ class InvokerBytecodeGenerator { String dumpName = className; //dumpName = dumpName.replace('/', '-'); File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class"); + System.out.println("dump: " + dumpFile); dumpFile.getParentFile().mkdirs(); FileOutputStream file = new FileOutputStream(dumpFile); file.write(classFile); @@ -204,7 +220,7 @@ class InvokerBytecodeGenerator { String constantPlaceholder(Object arg) { String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++; - if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + arg.toString() + ">>"; // debugging aid + if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>"; // debugging aid if (cpPatches.containsKey(cpPlaceholder)) { throw new InternalError("observed CP placeholder twice: " + cpPlaceholder); } @@ -225,6 +241,17 @@ class InvokerBytecodeGenerator { return res; } + private static String debugString(Object arg) { + if (arg instanceof MethodHandle) { + MethodHandle mh = (MethodHandle) arg; + MemberName member = mh.internalMemberName(); + if (member != null) + return member.toString(); + return mh.debugString(); + } + return arg.toString(); + } + /** * Extract the number of constant pool entries from a given class file. * @@ -400,6 +427,64 @@ class InvokerBytecodeGenerator { emitStoreInsn(L_TYPE, index); } + private byte arrayTypeCode(Wrapper elementType) { + switch (elementType) { + case BOOLEAN: return Opcodes.T_BOOLEAN; + case BYTE: return Opcodes.T_BYTE; + case CHAR: return Opcodes.T_CHAR; + case SHORT: return Opcodes.T_SHORT; + case INT: return Opcodes.T_INT; + case LONG: return Opcodes.T_LONG; + case FLOAT: return Opcodes.T_FLOAT; + case DOUBLE: return Opcodes.T_DOUBLE; + case OBJECT: return 0; // in place of Opcodes.T_OBJECT + default: throw new InternalError(); + } + } + + private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError { + assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD); + int xas; + switch (tcode) { + case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break; + case Opcodes.T_BYTE: xas = Opcodes.BASTORE; break; + case Opcodes.T_CHAR: xas = Opcodes.CASTORE; break; + case Opcodes.T_SHORT: xas = Opcodes.SASTORE; break; + case Opcodes.T_INT: xas = Opcodes.IASTORE; break; + case Opcodes.T_LONG: xas = Opcodes.LASTORE; break; + case Opcodes.T_FLOAT: xas = Opcodes.FASTORE; break; + case Opcodes.T_DOUBLE: xas = Opcodes.DASTORE; break; + case 0: xas = Opcodes.AASTORE; break; + default: throw new InternalError(); + } + return xas - Opcodes.AASTORE + aaop; + } + + + private void freeFrameLocal(int oldFrameLocal) { + int i = indexForFrameLocal(oldFrameLocal); + if (i < 0) return; + BasicType type = localTypes[i]; + int newFrameLocal = makeLocalTemp(type); + mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal); + mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal); + assert(localsMap[i] == oldFrameLocal); + localsMap[i] = newFrameLocal; + assert(indexForFrameLocal(oldFrameLocal) < 0); + } + private int indexForFrameLocal(int frameLocal) { + for (int i = 0; i < localsMap.length; i++) { + if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE) + return i; + } + return -1; + } + private int makeLocalTemp(BasicType type) { + int frameLocal = localsMap[localsMap.length - 1]; + localsMap[localsMap.length - 1] = frameLocal + type.basicTypeSlots(); + return frameLocal; + } + /** * Emit a boxing call. * @@ -421,41 +506,79 @@ class InvokerBytecodeGenerator { String owner = "java/lang/" + wrapper.wrapperType().getSimpleName(); String name = wrapper.primitiveSimpleName() + "Value"; String desc = "()" + wrapper.basicTypeChar(); - mv.visitTypeInsn(Opcodes.CHECKCAST, owner); + emitReferenceCast(wrapper.wrapperType(), null); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false); } /** - * Emit an implicit conversion. + * Emit an implicit conversion for an argument which must be of the given pclass. + * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface. * * @param ptype type of value present on stack * @param pclass type of value required on stack + * @param arg compile-time representation of value on stack (Node, constant) or null if none */ - private void emitImplicitConversion(BasicType ptype, Class pclass) { + private void emitImplicitConversion(BasicType ptype, Class pclass, Object arg) { assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller if (pclass == ptype.basicTypeClass() && ptype != L_TYPE) return; // nothing to do switch (ptype) { - case L_TYPE: - if (VerifyType.isNullConversion(Object.class, pclass)) + case L_TYPE: + if (VerifyType.isNullConversion(Object.class, pclass, false)) { + if (PROFILE_LEVEL > 0) + emitReferenceCast(Object.class, arg); + return; + } + emitReferenceCast(pclass, arg); + return; + case I_TYPE: + if (!VerifyType.isNullConversion(int.class, pclass, false)) + emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass)); return; - if (isStaticallyNameable(pclass)) { - mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass)); - } else { - mv.visitLdcInsn(constantPlaceholder(pclass)); - mv.visitTypeInsn(Opcodes.CHECKCAST, CLS); - mv.visitInsn(Opcodes.SWAP); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false); - if (pclass.isArray()) - mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY); - } - return; - case I_TYPE: - if (!VerifyType.isNullConversion(int.class, pclass)) - emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass)); - return; } - throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass); + throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass); + } + + /** Update localClasses type map. Return true if the information is already present. */ + private boolean assertStaticType(Class cls, Name n) { + int local = n.index(); + Class aclass = localClasses[local]; + if (aclass != null && (aclass == cls || cls.isAssignableFrom(aclass))) { + return true; // type info is already present + } else if (aclass == null || aclass.isAssignableFrom(cls)) { + localClasses[local] = cls; // type info can be improved + } + return false; + } + + private void emitReferenceCast(Class cls, Object arg) { + Name writeBack = null; // local to write back result + if (arg instanceof Name) { + Name n = (Name) arg; + if (assertStaticType(cls, n)) + return; // this cast was already performed + if (lambdaForm.useCount(n) > 1) { + // This guy gets used more than once. + writeBack = n; + } + } + if (isStaticallyNameable(cls)) { + String sig = getInternalName(cls); + mv.visitTypeInsn(Opcodes.CHECKCAST, sig); + } else { + mv.visitLdcInsn(constantPlaceholder(cls)); + mv.visitTypeInsn(Opcodes.CHECKCAST, CLS); + mv.visitInsn(Opcodes.SWAP); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false); + if (Object[].class.isAssignableFrom(cls)) + mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY); + else if (PROFILE_LEVEL > 0) + mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ); + } + if (writeBack != null) { + mv.visitInsn(Opcodes.DUP); + emitAstoreInsn(writeBack.index()); + } } /** @@ -477,7 +600,11 @@ class InvokerBytecodeGenerator { } private static String getInternalName(Class c) { - assert(VerifyAccess.isTypeVisible(c, Object.class)); + if (c == Object.class) return OBJ; + else if (c == Object[].class) return OBJARY; + else if (c == Class.class) return CLS; + else if (c == MethodHandle.class) return MH; + assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName(); return c.getName().replace('.', '/'); } @@ -506,39 +633,62 @@ class InvokerBytecodeGenerator { // iterate over the form's names, generating bytecode instructions for each // start iterating at the first name following the arguments + Name onStack = null; for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) { Name name = lambdaForm.names[i]; - MemberName member = name.function.member(); - if (isSelectAlternative(i)) { - emitSelectAlternative(name, lambdaForm.names[i + 1]); - i++; // skip MH.invokeBasic of the selectAlternative result - } else if (isGuardWithCatch(i)) { - emitGuardWithCatch(i); - i = i+2; // Jump to the end of GWC idiom - } else if (isStaticallyInvocable(member)) { + emitStoreResult(onStack); + onStack = name; // unless otherwise modified below + MethodHandleImpl.Intrinsic intr = name.function.intrinsicName(); + switch (intr) { + case SELECT_ALTERNATIVE: + assert isSelectAlternative(i); + onStack = emitSelectAlternative(name, lambdaForm.names[i+1]); + i++; // skip MH.invokeBasic of the selectAlternative result + continue; + case GUARD_WITH_CATCH: + assert isGuardWithCatch(i); + onStack = emitGuardWithCatch(i); + i = i+2; // Jump to the end of GWC idiom + continue; + case NEW_ARRAY: + Class rtype = name.function.methodType().returnType(); + if (isStaticallyNameable(rtype)) { + emitNewArray(name); + continue; + } + break; + case ARRAY_LOAD: + emitArrayLoad(name); + continue; + case ARRAY_STORE: + emitArrayStore(name); + continue; + case IDENTITY: + assert(name.arguments.length == 1); + emitPushArguments(name); + continue; + case ZERO: + assert(name.arguments.length == 0); + emitConst(name.type.basicTypeWrapper().zero()); + continue; + case NONE: + // no intrinsic associated + break; + default: + throw newInternalError("Unknown intrinsic: "+intr); + } + + MemberName member = name.function.member(); + if (isStaticallyInvocable(member)) { emitStaticInvoke(member, name); } else { emitInvoke(name); } - - // Update cached form name's info in case an intrinsic spanning multiple names was encountered. - name = lambdaForm.names[i]; - member = name.function.member(); - - // store the result from evaluating to the target name in a local if required - // (if this is the last value, i.e., the one that is going to be returned, - // avoid store/load/return and just return) - if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) { - // return value - do nothing - } else if (name.type != V_TYPE) { - // non-void: actually assign - emitStoreInsn(name.type, name.index()); - } } // return statement - emitReturn(); + emitReturn(onStack); classFileEpilogue(); bogusMethod(lambdaForm); @@ -548,29 +698,43 @@ class InvokerBytecodeGenerator { return classFile; } + void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); } + void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); } + + void emitArrayOp(Name name, int arrayOpcode) { + assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE; + Class elementType = name.function.methodType().parameterType(0).getComponentType(); + assert elementType != null; + emitPushArguments(name); + if (elementType.isPrimitive()) { + Wrapper w = Wrapper.forPrimitiveType(elementType); + arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode); + } + mv.visitInsn(arrayOpcode); + } + /** * Emit an invoke for the given name. */ void emitInvoke(Name name) { + assert(!isLinkerMethodInvoke(name)); // should use the static path for these if (true) { // push receiver MethodHandle target = name.function.resolvedHandle; assert(target != null) : name.exprString(); mv.visitLdcInsn(constantPlaceholder(target)); - mv.visitTypeInsn(Opcodes.CHECKCAST, MH); + emitReferenceCast(MethodHandle.class, target); } else { // load receiver emitAloadInsn(0); - mv.visitTypeInsn(Opcodes.CHECKCAST, MH); + emitReferenceCast(MethodHandle.class, null); mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG); mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG); // TODO more to come } // push arguments - for (int i = 0; i < name.arguments.length; i++) { - emitPushArgument(name, i); - } + emitPushArguments(name); // invocation MethodType type = name.function.methodType(); @@ -585,6 +749,10 @@ class InvokerBytecodeGenerator { //MethodHandle.class already covered }; + static boolean isStaticallyInvocable(Name name) { + return isStaticallyInvocable(name.function.member()); + } + static boolean isStaticallyInvocable(MemberName member) { if (member == null) return false; if (member.isConstructor()) return false; @@ -611,6 +779,8 @@ class InvokerBytecodeGenerator { } static boolean isStaticallyNameable(Class cls) { + if (cls == Object.class) + return true; while (cls.isArray()) cls = cls.getComponentType(); if (cls.isPrimitive()) @@ -631,12 +801,17 @@ class InvokerBytecodeGenerator { return false; } + void emitStaticInvoke(Name name) { + emitStaticInvoke(name.function.member(), name); + } + /** * Emit an invoke for the given name, using the MemberName directly. */ void emitStaticInvoke(MemberName member, Name name) { assert(member.equals(name.function.member())); - String cname = getInternalName(member.getDeclaringClass()); + Class defc = member.getDeclaringClass(); + String cname = getInternalName(defc); String mname = member.getName(); String mtype; byte refKind = member.getReferenceKind(); @@ -653,9 +828,7 @@ class InvokerBytecodeGenerator { } // push arguments - for (int i = 0; i < name.arguments.length; i++) { - emitPushArgument(name, i); - } + emitPushArguments(name); // invocation if (member.isMethod()) { @@ -666,6 +839,52 @@ class InvokerBytecodeGenerator { mtype = MethodType.toFieldDescriptorString(member.getFieldType()); mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype); } + // Issue a type assertion for the result, so we can avoid casts later. + if (name.type == L_TYPE) { + Class rtype = member.getInvocationType().returnType(); + assert(!rtype.isPrimitive()); + if (rtype != Object.class && !rtype.isInterface()) { + assertStaticType(rtype, name); + } + } + } + + void emitNewArray(Name name) throws InternalError { + Class rtype = name.function.methodType().returnType(); + if (name.arguments.length == 0) { + // The array will be a constant. + Object emptyArray; + try { + emptyArray = name.function.resolvedHandle.invoke(); + } catch (Throwable ex) { + throw newInternalError(ex); + } + assert(java.lang.reflect.Array.getLength(emptyArray) == 0); + assert(emptyArray.getClass() == rtype); // exact typing + mv.visitLdcInsn(constantPlaceholder(emptyArray)); + emitReferenceCast(rtype, emptyArray); + return; + } + Class arrayElementType = rtype.getComponentType(); + assert(arrayElementType != null); + emitIconstInsn(name.arguments.length); + int xas = Opcodes.AASTORE; + if (!arrayElementType.isPrimitive()) { + mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType)); + } else { + byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType)); + xas = arrayInsnOpcode(tc, xas); + mv.visitIntInsn(Opcodes.NEWARRAY, tc); + } + // store arguments + for (int i = 0; i < name.arguments.length; i++) { + mv.visitInsn(Opcodes.DUP); + emitIconstInsn(i); + emitPushArgument(name, i); + mv.visitInsn(xas); + } + // the array is left on the stack + assertStaticType(rtype, name); } int refKindOpcode(byte refKind) { switch (refKind) { @@ -707,6 +926,21 @@ class InvokerBytecodeGenerator { !member.isPublic() && !member.isStatic(); } + /** + * Check if MemberName is a call to MethodHandle.linkToStatic, etc. + */ + private boolean isLinkerMethodInvoke(Name name) { + if (name.function == null) + return false; + if (name.arguments.length < 1) + return false; // must have MH argument + MemberName member = name.function.member(); + return member != null && + member.getDeclaringClass() == MethodHandle.class && + !member.isPublic() && member.isStatic() && + member.getName().startsWith("linkTo"); + } + /** * Check if i-th name is a call to MethodHandleImpl.selectAlternative. */ @@ -755,7 +989,9 @@ class InvokerBytecodeGenerator { * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I} * }
*/ - private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { + private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { + assert isStaticallyInvocable(invokeBasicName); + Name receiver = (Name) invokeBasicName.arguments[0]; Label L_fallback = new Label(); @@ -763,15 +999,15 @@ class InvokerBytecodeGenerator { // load test result emitPushArgument(selectAlternativeName, 0); - mv.visitInsn(Opcodes.ICONST_1); // if_icmpne L_fallback - mv.visitJumpInsn(Opcodes.IF_ICMPNE, L_fallback); + mv.visitJumpInsn(Opcodes.IFEQ, L_fallback); // invoke selectAlternativeName.arguments[1] + Class[] preForkClasses = localClasses.clone(); emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative emitAstoreInsn(receiver.index()); // store the MH in the receiver slot - emitInvoke(invokeBasicName); + emitStaticInvoke(invokeBasicName); // goto L_done mv.visitJumpInsn(Opcodes.GOTO, L_done); @@ -780,12 +1016,17 @@ class InvokerBytecodeGenerator { mv.visitLabel(L_fallback); // invoke selectAlternativeName.arguments[2] + System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative emitAstoreInsn(receiver.index()); // store the MH in the receiver slot - emitInvoke(invokeBasicName); + emitStaticInvoke(invokeBasicName); // L_done: mv.visitLabel(L_done); + // for now do not bother to merge typestate; just reset to the dominator state + System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); + + return invokeBasicName; // return what's on stack } /** @@ -808,7 +1049,7 @@ class InvokerBytecodeGenerator { * return a3.invokeBasic(ex, a6, a7); * }} */ - private void emitGuardWithCatch(int pos) { + private Name emitGuardWithCatch(int pos) { Name args = lambdaForm.names[pos]; Name invoker = lambdaForm.names[pos+1]; Name result = lambdaForm.names[pos+2]; @@ -859,6 +1100,12 @@ class InvokerBytecodeGenerator { mv.visitInsn(Opcodes.ATHROW); mv.visitLabel(L_done); + + return result; + } + + private void emitPushArguments(Name args) { + emitPushArguments(args, 0); } private void emitPushArguments(Name args, int start) { @@ -878,7 +1125,7 @@ class InvokerBytecodeGenerator { if (arg instanceof Name) { Name n = (Name) arg; emitLoadInsn(n.type, n.index()); - emitImplicitConversion(n.type, ptype); + emitImplicitConversion(n.type, ptype, n); } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) { emitConst(arg); } else { @@ -886,15 +1133,25 @@ class InvokerBytecodeGenerator { emitConst(arg); } else { mv.visitLdcInsn(constantPlaceholder(arg)); - emitImplicitConversion(L_TYPE, ptype); + emitImplicitConversion(L_TYPE, ptype, arg); } } } + /** + * Store the name to its local, if necessary. + */ + private void emitStoreResult(Name name) { + if (name != null && name.type != V_TYPE) { + // non-void: actually assign + emitStoreInsn(name.type, name.index()); + } + } + /** * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type. */ - private void emitReturn() { + private void emitReturn(Name onStack) { // return statement Class rclass = invokerType.returnType(); BasicType rtype = lambdaForm.returnType(); @@ -907,12 +1164,11 @@ class InvokerBytecodeGenerator { LambdaForm.Name rn = lambdaForm.names[lambdaForm.result]; // put return value on the stack if it is not already there - if (lambdaForm.result != lambdaForm.names.length - 1 || - lambdaForm.result < lambdaForm.arity) { - emitLoadInsn(rn.type, lambdaForm.result); + if (rn != onStack) { + emitLoadInsn(rtype, lambdaForm.result); } - emitImplicitConversion(rtype, rclass); + emitImplicitConversion(rtype, rclass, rn); // generate actual return statement emitReturnInsn(rtype); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java index d3116d12963..12a118a7576 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -25,8 +25,9 @@ package java.lang.invoke; +import java.lang.reflect.Array; import java.util.Arrays; -import sun.invoke.empty.Empty; + import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @@ -40,52 +41,63 @@ class Invokers { // exact type (sans leading target MH) for the outgoing call private final MethodType targetType; - // FIXME: Get rid of the invokers that are not useful. - - // exact invoker for the outgoing call - private /*lazy*/ MethodHandle exactInvoker; - private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) - - // erased (partially untyped but with primitives) invoker for the outgoing call - // FIXME: get rid of - private /*lazy*/ MethodHandle erasedInvoker; - // FIXME: get rid of - /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric - - // general invoker for the outgoing call - private /*lazy*/ MethodHandle generalInvoker; - - // general invoker for the outgoing call, uses varargs - private /*lazy*/ MethodHandle varargsInvoker; - - // general invoker for the outgoing call; accepts a trailing Object[] - private final /*lazy*/ MethodHandle[] spreadInvokers; - - // invoker for an unbound callsite - private /*lazy*/ MethodHandle uninitializedCallSite; + // Cached adapter information: + private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT]; + // Indexes into invokers: + static final int + INV_EXACT = 0, // MethodHandles.exactInvoker + INV_GENERIC = 1, // MethodHandles.invoker (generic invocation) + INV_BASIC = 2, // MethodHandles.basicInvoker + INV_LIMIT = 3; /** Compute and cache information common to all collecting adapters * that implement members of the erasure-family of the given erased type. */ /*non-public*/ Invokers(MethodType targetType) { this.targetType = targetType; - this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1]; } /*non-public*/ MethodHandle exactInvoker() { - MethodHandle invoker = exactInvoker; + MethodHandle invoker = cachedInvoker(INV_EXACT); if (invoker != null) return invoker; invoker = makeExactOrGeneralInvoker(true); - exactInvoker = invoker; - return invoker; + return setCachedInvoker(INV_EXACT, invoker); } - /*non-public*/ MethodHandle generalInvoker() { - MethodHandle invoker = generalInvoker; + /*non-public*/ MethodHandle genericInvoker() { + MethodHandle invoker = cachedInvoker(INV_GENERIC); if (invoker != null) return invoker; invoker = makeExactOrGeneralInvoker(false); - generalInvoker = invoker; - return invoker; + return setCachedInvoker(INV_GENERIC, invoker); + } + + /*non-public*/ MethodHandle basicInvoker() { + MethodHandle invoker = cachedInvoker(INV_BASIC); + if (invoker != null) return invoker; + MethodType basicType = targetType.basicType(); + if (basicType != targetType) { + // double cache; not used significantly + return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker()); + } + invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV); + if (invoker == null) { + MemberName method = invokeBasicMethod(basicType); + invoker = DirectMethodHandle.make(method); + assert(checkInvoker(invoker)); + invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker); + } + return setCachedInvoker(INV_BASIC, invoker); + } + + private MethodHandle cachedInvoker(int idx) { + return invokers[idx]; + } + + private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) { + // Simulate a CAS, to avoid racy duplication of results. + MethodHandle prev = invokers[idx]; + if (prev != null) return prev; + return invokers[idx] = invoker; } private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { @@ -95,7 +107,7 @@ class Invokers { LambdaForm lform = invokeHandleForm(mtype, false, which); MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); String whichName = (isExact ? "invokeExact" : "invoke"); - invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype)); + invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false); assert(checkInvoker(invoker)); maybeCompileToBytecode(invoker); return invoker; @@ -110,21 +122,6 @@ class Invokers { } } - /*non-public*/ MethodHandle basicInvoker() { - MethodHandle invoker = basicInvoker; - if (invoker != null) return invoker; - MethodType basicType = targetType.basicType(); - if (basicType != targetType) { - // double cache; not used significantly - return basicInvoker = basicType.invokers().basicInvoker(); - } - MemberName method = invokeBasicMethod(basicType); - invoker = DirectMethodHandle.make(method); - assert(checkInvoker(invoker)); - basicInvoker = invoker; - return invoker; - } - // This next one is called from LambdaForm.NamedFunction.. /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { assert(basicType == basicType.basicType()); @@ -145,87 +142,42 @@ class Invokers { return true; } - // FIXME: get rid of - /*non-public*/ MethodHandle erasedInvoker() { - MethodHandle xinvoker = exactInvoker(); - MethodHandle invoker = erasedInvoker; - if (invoker != null) return invoker; - MethodType erasedType = targetType.erase(); - invoker = xinvoker.asType(erasedType.invokerType()); - erasedInvoker = invoker; - return invoker; - } - + /** + * Find or create an invoker which passes unchanged a given number of arguments + * and spreads the rest from a trailing array argument. + * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}. + * All the {@code sarg}s must have a common type {@code C}. (If there are none, {@code Object} is assumed.} + * @param leadingArgCount the number of unchanged (non-spread) arguments + * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)} + */ /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { - MethodHandle vaInvoker = spreadInvokers[leadingArgCount]; - if (vaInvoker != null) return vaInvoker; int spreadArgCount = targetType.parameterCount() - leadingArgCount; - MethodType spreadInvokerType = targetType - .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class); - if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { - // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a) - // where ginvoker.invoke(mh, a*) => mh.invoke(a*). - MethodHandle genInvoker = generalInvoker(); - vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount); - } else { - // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]). - // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a) - // where filter(mh) == mh.asSpreader(Object[], spreadArgCount) - MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType); - MethodHandle makeSpreader; - try { - makeSpreader = IMPL_LOOKUP - .findVirtual(MethodHandle.class, "asSpreader", - MethodType.methodType(MethodHandle.class, Class.class, int.class)); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount); - vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); + MethodType postSpreadType = targetType; + Class argArrayType = impliedRestargType(postSpreadType, leadingArgCount); + if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { + return genericInvoker().asSpreader(argArrayType, spreadArgCount); } - assert(vaInvoker.type().equals(spreadInvokerType.invokerType())); - maybeCompileToBytecode(vaInvoker); - spreadInvokers[leadingArgCount] = vaInvoker; - return vaInvoker; + // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]). + // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a) + // where filter(mh) == mh.asSpreader(Object[], spreadArgCount) + MethodType preSpreadType = postSpreadType + .replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType); + MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType); + MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount); + return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); } - /*non-public*/ MethodHandle varargsInvoker() { - MethodHandle vaInvoker = varargsInvoker; - if (vaInvoker != null) return vaInvoker; - vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType()); - varargsInvoker = vaInvoker; - return vaInvoker; - } - - private static MethodHandle THROW_UCS = null; - - /*non-public*/ MethodHandle uninitializedCallSite() { - MethodHandle invoker = uninitializedCallSite; - if (invoker != null) return invoker; - if (targetType.parameterCount() > 0) { - MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount()); - Invokers invokers0 = type0.invokers(); - invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(), - 0, targetType.parameterList()); - assert(invoker.type().equals(targetType)); - uninitializedCallSite = invoker; - return invoker; + private static Class impliedRestargType(MethodType restargType, int fromPos) { + if (restargType.isGeneric()) return Object[].class; // can be nothing else + int maxPos = restargType.parameterCount(); + if (fromPos >= maxPos) return Object[].class; // reasonable default + Class argType = restargType.parameterType(fromPos); + for (int i = fromPos+1; i < maxPos; i++) { + if (argType != restargType.parameterType(i)) + throw newIllegalArgumentException("need homogeneous rest arguments", restargType); } - invoker = THROW_UCS; - if (invoker == null) { - try { - THROW_UCS = invoker = IMPL_LOOKUP - .findStatic(CallSite.class, "uninitializedCallSite", - MethodType.methodType(Empty.class)); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - } - invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType())); - invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount()); - assert(invoker.type().equals(targetType)); - uninitializedCallSite = invoker; - return invoker; + if (argType == Object.class) return Object[].class; + return Array.newInstance(argType, 0).getClass(); } public String toString() { @@ -308,7 +260,9 @@ class Invokers { : Arrays.asList(mtype, customized, which, nameCursor, names.length); if (MTYPE_ARG >= INARG_LIMIT) { assert(names[MTYPE_ARG] == null); - NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); + BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L(); + names[THIS_MH] = names[THIS_MH].withConstraint(speciesData); + NamedFunction getter = speciesData.getterFunction(0); names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) } @@ -360,9 +314,6 @@ class Invokers { Object checkGenericType(Object mhObj, Object expectedObj) { MethodHandle mh = (MethodHandle) mhObj; MethodType expected = (MethodType) expectedObj; - if (mh.type() == expected) return mh; - MethodHandle atc = mh.asTypeCache; - if (atc != null && atc.type() == expected) return atc; return mh.asType(expected); /* Maybe add more paths here. Possible optimizations: * for (R)MH.invoke(a*), @@ -436,27 +387,40 @@ class Invokers { } // Local constant functions: - private static final NamedFunction NF_checkExactType; - private static final NamedFunction NF_checkGenericType; - private static final NamedFunction NF_asType; - private static final NamedFunction NF_getCallSiteTarget; + private static final NamedFunction + NF_checkExactType, + NF_checkGenericType, + NF_getCallSiteTarget; static { try { - NF_checkExactType = new NamedFunction(Invokers.class - .getDeclaredMethod("checkExactType", Object.class, Object.class)); - NF_checkGenericType = new NamedFunction(Invokers.class - .getDeclaredMethod("checkGenericType", Object.class, Object.class)); - NF_asType = new NamedFunction(MethodHandle.class - .getDeclaredMethod("asType", MethodType.class)); - NF_getCallSiteTarget = new NamedFunction(Invokers.class - .getDeclaredMethod("getCallSiteTarget", Object.class)); - NF_checkExactType.resolve(); - NF_checkGenericType.resolve(); - NF_getCallSiteTarget.resolve(); - // bound + NamedFunction nfs[] = { + NF_checkExactType = new NamedFunction(Invokers.class + .getDeclaredMethod("checkExactType", Object.class, Object.class)), + NF_checkGenericType = new NamedFunction(Invokers.class + .getDeclaredMethod("checkGenericType", Object.class, Object.class)), + NF_getCallSiteTarget = new NamedFunction(Invokers.class + .getDeclaredMethod("getCallSiteTarget", Object.class)) + }; + for (NamedFunction nf : nfs) { + // Each nf must be statically invocable or we get tied up in our bootstraps. + assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf; + nf.resolve(); + } } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } } + private static class Lazy { + private static final MethodHandle MH_asSpreader; + + static { + try { + MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader", + MethodType.methodType(MethodHandle.class, Class.class, int.class)); + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } + } + } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 0676b7b3ab0..b83040647c5 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -27,11 +27,10 @@ package java.lang.invoke; import java.lang.annotation.*; import java.lang.reflect.Method; -import java.util.Map; import java.util.List; import java.util.Arrays; import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; + import sun.invoke.util.Wrapper; import java.lang.reflect.Field; @@ -125,8 +124,7 @@ class LambdaForm { MemberName vmentry; // low-level behavior, or null if not yet prepared private boolean isCompiled; - // Caches for common structural transforms: - LambdaForm[] bindCache; + Object transformCache; // managed by LambdaFormEditor public static final int VOID_RESULT = -1, LAST_RESULT = -2; @@ -214,6 +212,13 @@ class LambdaForm { } return btypes; } + static byte[] basicTypesOrd(BasicType[] btypes) { + byte[] ords = new byte[btypes.length]; + for (int i = 0; i < btypes.length; i++) { + ords[i] = (byte)btypes[i].ordinal(); + } + return ords; + } static boolean isBasicTypeChar(char c) { return "LIJFDV".indexOf(c) >= 0; } @@ -243,7 +248,12 @@ class LambdaForm { this.result = fixResult(result, names); this.names = names.clone(); this.debugName = fixDebugName(debugName); - normalize(); + int maxOutArity = normalize(); + if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { + // Cannot use LF interpreter on very high arity expressions. + assert(maxOutArity <= MethodType.MAX_JVM_ARITY); + compileToBytecode(); + } } LambdaForm(String debugName, @@ -348,9 +358,12 @@ class LambdaForm { return true; } - /** Renumber and/or replace params so that they are interned and canonically numbered. */ - private void normalize() { + /** Renumber and/or replace params so that they are interned and canonically numbered. + * @return maximum argument list length among the names (since we have to pass over them anyway) + */ + private int normalize() { Name[] oldNames = null; + int maxOutArity = 0; int changesStart = 0; for (int i = 0; i < names.length; i++) { Name n = names[i]; @@ -361,6 +374,8 @@ class LambdaForm { } names[i] = n.cloneWithIndex(i); } + if (n.arguments != null && maxOutArity < n.arguments.length) + maxOutArity = n.arguments.length; } if (oldNames != null) { int startFixing = arity; @@ -387,6 +402,7 @@ class LambdaForm { } assert(nameRefsAreLegal()); } + return maxOutArity; } /** @@ -398,7 +414,7 @@ class LambdaForm { * This allows Name references to be freely reused to construct * fresh lambdas, without confusion. */ - private boolean nameRefsAreLegal() { + boolean nameRefsAreLegal() { assert(arity >= 0 && arity <= names.length); assert(result >= -1 && result < names.length); // Do all names possess an index consistent with their local definition order? @@ -439,8 +455,20 @@ class LambdaForm { /** Report the N-th argument type. */ BasicType parameterType(int n) { + return parameter(n).type; + } + + /** Report the N-th argument name. */ + Name parameter(int n) { assert(n < arity); - return names[n].type; + Name param = names[n]; + assert(param.isParam()); + return param; + } + + /** Report the N-th argument type constraint. */ + Object parameterConstraint(int n) { + return parameter(n).constraint; } /** Report the arity. */ @@ -448,6 +476,11 @@ class LambdaForm { return arity; } + /** Report the number of expressions (non-parameter names). */ + int expressionCount() { + return names.length - arity; + } + /** Return the method type corresponding to my basic type signature. */ MethodType methodType() { return signatureType(basicTypeSignature()); @@ -464,7 +497,7 @@ class LambdaForm { return sig.indexOf('_'); } static BasicType signatureReturn(String sig) { - return basicType(sig.charAt(signatureArity(sig)+1)); + return basicType(sig.charAt(signatureArity(sig) + 1)); } static boolean isValidSignature(String sig) { int arity = sig.indexOf('_'); @@ -582,21 +615,12 @@ class LambdaForm { isCompiled = true; return vmentry; } catch (Error | Exception ex) { - throw newInternalError("compileToBytecode", ex); + throw newInternalError(this.toString(), ex); } } - private static final ConcurrentHashMap PREPARED_FORMS; - static { - int capacity = 512; // expect many distinct signatures over time - float loadFactor = 0.75f; // normal default - int writers = 1; - PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers); - } - - private static Map computeInitialPreparedForms() { + private static void computeInitialPreparedForms() { // Find all predefined invokers and associate them with canonical empty lambda forms. - HashMap forms = new HashMap<>(); for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) { if (!m.isStatic() || !m.isPackage()) continue; MethodType mt = m.getMethodType(); @@ -607,13 +631,9 @@ class LambdaForm { assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_')))); LambdaForm form = new LambdaForm(sig); form.vmentry = m; - form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form); - // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only - forms.put(sig, form); + form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, form); } } - //System.out.println("computeInitialPreparedForms => "+forms); - return forms; } // Set this false to disable use of the interpret_L methods defined in this file. @@ -647,13 +667,11 @@ class LambdaForm { } private static LambdaForm getPreparedForm(String sig) { MethodType mtype = signatureType(sig); - //LambdaForm prep = PREPARED_FORMS.get(sig); LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET); if (prep != null) return prep; assert(isValidSignature(sig)); prep = new LambdaForm(sig); prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig); - //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep); return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep); } @@ -709,10 +727,7 @@ class LambdaForm { /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */ private static final int COMPILE_THRESHOLD; static { - if (MethodHandleStatics.COMPILE_THRESHOLD != null) - COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD; - else - COMPILE_THRESHOLD = 30; // default value + COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD); } private int invocationCounter = 0; @@ -728,7 +743,9 @@ class LambdaForm { for (int i = argumentValues.length; i < values.length; i++) { values[i] = interpretName(names[i], values); } - return (result < 0) ? null : values[result]; + Object rv = (result < 0) ? null : values[result]; + assert(resultCheck(argumentValues, rv)); + return rv; } @Hidden @@ -785,28 +802,6 @@ class LambdaForm { return rval; } - //** This transform is applied (statically) to every name.function. */ - /* - private static MethodHandle eraseSubwordTypes(MethodHandle mh) { - MethodType mt = mh.type(); - if (mt.hasPrimitives()) { - mt = mt.changeReturnType(eraseSubwordType(mt.returnType())); - for (int i = 0; i < mt.parameterCount(); i++) { - mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i))); - } - mh = MethodHandles.explicitCastArguments(mh, mt); - } - return mh; - } - private static Class eraseSubwordType(Class type) { - if (!type.isPrimitive()) return type; - if (type == int.class) return type; - Wrapper w = Wrapper.forPrimitiveType(type); - if (w.isSubwordOrInt()) return int.class; - return type; - } - */ - static void traceInterpreter(String event, Object obj, Object... args) { if (TRACE_INTERPRETER) { System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : "")); @@ -819,8 +814,16 @@ class LambdaForm { assert(argumentValues.length == arity) : arity+"!="+Arrays.asList(argumentValues)+".length"; // also check that the leading (receiver) argument is somehow bound to this LF: assert(argumentValues[0] instanceof MethodHandle) : "not MH: " + argumentValues[0]; - assert(((MethodHandle)argumentValues[0]).internalForm() == this); + MethodHandle mh = (MethodHandle) argumentValues[0]; + assert(mh.internalForm() == this); // note: argument #0 could also be an interface wrapper, in the future + argumentTypesMatch(basicTypeSignature(), argumentValues); + return true; + } + private boolean resultCheck(Object[] argumentValues, Object result) { + MethodHandle mh = (MethodHandle) argumentValues[0]; + MethodType mt = mh.type(); + assert(valueMatches(returnType(), mt.returnType(), result)); return true; } @@ -839,7 +842,7 @@ class LambdaForm { if (i == arity) buf.append(")=>{"); Name n = names[i]; if (i >= arity) buf.append("\n "); - buf.append(n); + buf.append(n.paramString()); if (i < arity) { if (i+1 < arity) buf.append(","); continue; @@ -847,6 +850,7 @@ class LambdaForm { buf.append("=").append(n.exprString()); buf.append(";"); } + if (arity == names.length) buf.append(")=>{"); buf.append(result < 0 ? "void" : names[result]).append("}"); if (TRACE_INTERPRETER) { // Extra verbosity: @@ -856,135 +860,19 @@ class LambdaForm { return buf.toString(); } - /** - * Apply immediate binding for a Name in this form indicated by its position relative to the form. - * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not - * accepted as valid. - */ - LambdaForm bindImmediate(int pos, BasicType basicType, Object value) { - // must be an argument, and the types must match - assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value); - - int arity2 = arity - 1; - Name[] names2 = new Name[names.length - 1]; - for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2 - Name n = names[r]; - if (n.isParam()) { - if (n.index == pos) { - // do not copy over the argument that is to be replaced with a literal, - // but adjust the write index - --w; - } else { - names2[w] = new Name(w, n.type); - } - } else { - Object[] arguments2 = new Object[n.arguments.length]; - for (int i = 0; i < n.arguments.length; ++i) { - Object arg = n.arguments[i]; - if (arg instanceof Name) { - int ni = ((Name) arg).index; - if (ni == pos) { - arguments2[i] = value; - } else if (ni < pos) { - // replacement position not yet passed - arguments2[i] = names2[ni]; - } else { - // replacement position passed - arguments2[i] = names2[ni - 1]; - } - } else { - arguments2[i] = arg; - } - } - names2[w] = new Name(n.function, arguments2); - names2[w].initIndex(w); - } - } - - int result2 = result == -1 ? -1 : result - 1; - return new LambdaForm(debugName, arity2, names2, result2); + @Override + public boolean equals(Object obj) { + return obj instanceof LambdaForm && equals((LambdaForm)obj); } - - LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) { - Name name = names[namePos]; - BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type); - return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData); + public boolean equals(LambdaForm that) { + if (this.result != that.result) return false; + return Arrays.equals(this.names, that.names); } - LambdaForm bind(Name name, Name binding, - BoundMethodHandle.SpeciesData oldData, - BoundMethodHandle.SpeciesData newData) { - int pos = name.index; - assert(name.isParam()); - assert(!binding.isParam()); - assert(name.type == binding.type); - assert(0 <= pos && pos < arity && names[pos] == name); - assert(binding.function.memberDeclaringClassOrNull() == newData.clazz); - assert(oldData.getters.length == newData.getters.length-1); - if (bindCache != null) { - LambdaForm form = bindCache[pos]; - if (form != null) { - assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>"; - return form; - } - } else { - bindCache = new LambdaForm[arity]; - } - assert(nameRefsAreLegal()); - int arity2 = arity-1; - Name[] names2 = names.clone(); - names2[pos] = binding; // we might move this in a moment - - // The newly created LF will run with a different BMH. - // Switch over any pre-existing BMH field references to the new BMH class. - int firstOldRef = -1; - for (int i = 0; i < names2.length; i++) { - Name n = names[i]; - if (n.function != null && - n.function.memberDeclaringClassOrNull() == oldData.clazz) { - MethodHandle oldGetter = n.function.resolvedHandle; - MethodHandle newGetter = null; - for (int j = 0; j < oldData.getters.length; j++) { - if (oldGetter == oldData.getters[j]) - newGetter = newData.getters[j]; - } - if (newGetter != null) { - if (firstOldRef < 0) firstOldRef = i; - Name n2 = new Name(newGetter, n.arguments); - names2[i] = n2; - } - } - } - - // Walk over the new list of names once, in forward order. - // Replace references to 'name' with 'binding'. - // Replace data structure references to the old BMH species with the new. - // This might cause a ripple effect, but it will settle in one pass. - assert(firstOldRef < 0 || firstOldRef > pos); - for (int i = pos+1; i < names2.length; i++) { - if (i <= arity2) continue; - names2[i] = names2[i].replaceNames(names, names2, pos, i); - } - - // (a0, a1, name=a2, a3, a4) => (a0, a1, a3, a4, binding) - int insPos = pos; - for (; insPos+1 < names2.length; insPos++) { - Name n = names2[insPos+1]; - if (n.isSiblingBindingBefore(binding)) { - names2[insPos] = n; - } else { - break; - } - } - names2[insPos] = binding; - - // Since we moved some stuff, maybe update the result reference: - int result2 = result; - if (result2 == pos) - result2 = insPos; - else if (result2 > pos && result2 <= insPos) - result2 -= 1; - - return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2); + public int hashCode() { + return result + 31 * Arrays.hashCode(names); + } + LambdaFormEditor editor() { + return LambdaFormEditor.lambdaFormEditor(this); } boolean contains(Name name) { @@ -1000,16 +888,16 @@ class LambdaForm { } LambdaForm addArguments(int pos, BasicType... types) { - assert(pos <= arity); + // names array has MH in slot 0; skip it. + int argpos = pos + 1; + assert(argpos <= arity); int length = names.length; int inTypes = types.length; Name[] names2 = Arrays.copyOf(names, length + inTypes); int arity2 = arity + inTypes; int result2 = result; - if (result2 >= arity) + if (result2 >= argpos) result2 += inTypes; - // names array has MH in slot 0; skip it. - int argpos = pos + 1; // Note: The LF constructor will rename names2[argpos...]. // Make space for new arguments (shift temporaries). System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos); @@ -1102,8 +990,9 @@ class LambdaForm { } NamedFunction(MemberName member, MethodHandle resolvedHandle) { this.member = member; - //resolvedHandle = eraseSubwordTypes(resolvedHandle); this.resolvedHandle = resolvedHandle; + // The following assert is almost always correct, but will fail for corner cases, such as PrivateInvokeTest. + //assert(!isInvokeBasic()); } NamedFunction(MethodType basicInvokerType) { assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType; @@ -1114,6 +1003,13 @@ class LambdaForm { // necessary to pass BigArityTest this.member = Invokers.invokeBasicMethod(basicInvokerType); } + assert(isInvokeBasic()); + } + + private boolean isInvokeBasic() { + return member != null && + member.isMethodHandleInvoke() && + "invokeBasic".equals(member.getName()); } // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc. @@ -1169,7 +1065,7 @@ class LambdaForm { if (LambdaForm.signatureReturn(sig) == V_TYPE) srcType = srcType.changeReturnType(void.class); MethodTypeForm typeForm = srcType.form(); - typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); + typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, DirectMethodHandle.make(m)); } } } @@ -1179,85 +1075,104 @@ class LambdaForm { /** void return type invokers. */ @Hidden static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 0); + assert(arityCheck(0, void.class, mh, a)); mh.invokeBasic(); return null; } @Hidden static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 1); + assert(arityCheck(1, void.class, mh, a)); mh.invokeBasic(a[0]); return null; } @Hidden static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 2); + assert(arityCheck(2, void.class, mh, a)); mh.invokeBasic(a[0], a[1]); return null; } @Hidden static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 3); + assert(arityCheck(3, void.class, mh, a)); mh.invokeBasic(a[0], a[1], a[2]); return null; } @Hidden static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 4); + assert(arityCheck(4, void.class, mh, a)); mh.invokeBasic(a[0], a[1], a[2], a[3]); return null; } @Hidden static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 5); + assert(arityCheck(5, void.class, mh, a)); mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]); return null; } /** Object return type invokers. */ @Hidden static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 0); + assert(arityCheck(0, mh, a)); return mh.invokeBasic(); } @Hidden static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 1); + assert(arityCheck(1, mh, a)); return mh.invokeBasic(a[0]); } @Hidden static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 2); + assert(arityCheck(2, mh, a)); return mh.invokeBasic(a[0], a[1]); } @Hidden static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 3); + assert(arityCheck(3, mh, a)); return mh.invokeBasic(a[0], a[1], a[2]); } @Hidden static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 4); + assert(arityCheck(4, mh, a)); return mh.invokeBasic(a[0], a[1], a[2], a[3]); } @Hidden static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable { - assert(a.length == 5); + assert(arityCheck(5, mh, a)); return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]); } + private static boolean arityCheck(int arity, MethodHandle mh, Object[] a) { + return arityCheck(arity, Object.class, mh, a); + } + private static boolean arityCheck(int arity, Class rtype, MethodHandle mh, Object[] a) { + assert(a.length == arity) + : Arrays.asList(a.length, arity); + assert(mh.type().basicType() == MethodType.genericMethodType(arity).changeReturnType(rtype)) + : Arrays.asList(mh, rtype, arity); + MemberName member = mh.internalMemberName(); + if (member != null && member.getName().equals("invokeBasic") && member.isMethodHandleInvoke()) { + assert(arity > 0); + assert(a[0] instanceof MethodHandle); + MethodHandle mh2 = (MethodHandle) a[0]; + assert(mh2.type().basicType() == MethodType.genericMethodType(arity-1).changeReturnType(rtype)) + : Arrays.asList(member, mh2, rtype, arity); + } + return true; + } static final MethodType INVOKER_METHOD_TYPE = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); private static MethodHandle computeInvoker(MethodTypeForm typeForm) { - MethodHandle mh = typeForm.namedFunctionInvoker; + typeForm = typeForm.basicType().form(); // normalize to basic type + MethodHandle mh = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV); if (mh != null) return mh; MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while mh = DirectMethodHandle.make(invoker); - MethodHandle mh2 = typeForm.namedFunctionInvoker; + MethodHandle mh2 = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV); if (mh2 != null) return mh2; // benign race if (!mh.type().equals(INVOKER_METHOD_TYPE)) throw newInternalError(mh.debugString()); - return typeForm.namedFunctionInvoker = mh; + return typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, mh); } @Hidden @@ -1365,6 +1280,11 @@ class LambdaForm { public boolean isConstantZero() { return this.equals(constantZero(returnType())); } + + public MethodHandleImpl.Intrinsic intrinsicName() { + return resolvedHandle == null ? MethodHandleImpl.Intrinsic.NONE + : resolvedHandle.intrinsicName(); + } } public static String basicTypeSignature(MethodType type) { @@ -1411,6 +1331,7 @@ class LambdaForm { final BasicType type; private short index; final NamedFunction function; + final Object constraint; // additional type information, if not null @Stable final Object[] arguments; private Name(int index, BasicType type, NamedFunction function, Object[] arguments) { @@ -1418,8 +1339,18 @@ class LambdaForm { this.type = type; this.function = function; this.arguments = arguments; + this.constraint = null; assert(this.index == index); } + private Name(Name that, Object constraint) { + this.index = that.index; + this.type = that.type; + this.function = that.function; + this.arguments = that.arguments; + this.constraint = constraint; + assert(constraint == null || isParam()); // only params have constraints + assert(constraint == null || constraint instanceof BoundMethodHandle.SpeciesData || constraint instanceof Class); + } Name(MethodHandle function, Object... arguments) { this(new NamedFunction(function), arguments); } @@ -1431,7 +1362,7 @@ class LambdaForm { this(new NamedFunction(function), arguments); } Name(NamedFunction function, Object... arguments) { - this(-1, function.returnType(), function, arguments = arguments.clone()); + this(-1, function.returnType(), function, arguments = Arrays.copyOf(arguments, arguments.length, Object[].class)); assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString(); for (int i = 0; i < arguments.length; i++) assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString(); @@ -1467,7 +1398,11 @@ class LambdaForm { } Name cloneWithIndex(int i) { Object[] newArguments = (arguments == null) ? null : arguments.clone(); - return new Name(i, type, function, newArguments); + return new Name(i, type, function, newArguments).withConstraint(constraint); + } + Name withConstraint(Object constraint) { + if (constraint == this.constraint) return this; + return new Name(this, constraint); } Name replaceName(Name oldName, Name newName) { // FIXME: use replaceNames uniformly if (oldName == newName) return this; @@ -1487,7 +1422,11 @@ class LambdaForm { if (!replaced) return this; return new Name(function, arguments); } + /** In the arguments of this Name, replace oldNames[i] pairwise by newNames[i]. + * Limit such replacements to {@code start<=i= end) return this; @SuppressWarnings("LocalVariableHidesMemberVariable") Object[] arguments = this.arguments; boolean replaced = false; @@ -1539,9 +1478,17 @@ class LambdaForm { return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar(); } public String debugString() { - String s = toString(); + String s = paramString(); return (function == null) ? s : s + "=" + exprString(); } + public String paramString() { + String s = toString(); + Object c = constraint; + if (c == null) + return s; + if (c instanceof Class) c = ((Class)c).getSimpleName(); + return s + "/" + c; + } public String exprString() { if (function == null) return toString(); StringBuilder buf = new StringBuilder(function.toString()); @@ -1572,34 +1519,6 @@ class LambdaForm { return true; } - /** - * Does this Name precede the given binding node in some canonical order? - * This predicate is used to order data bindings (via insertion sort) - * with some stability. - */ - boolean isSiblingBindingBefore(Name binding) { - assert(!binding.isParam()); - if (isParam()) return true; - if (function.equals(binding.function) && - arguments.length == binding.arguments.length) { - boolean sawInt = false; - for (int i = 0; i < arguments.length; i++) { - Object a1 = arguments[i]; - Object a2 = binding.arguments[i]; - if (!a1.equals(a2)) { - if (a1 instanceof Integer && a2 instanceof Integer) { - if (sawInt) continue; - sawInt = true; - if ((int)a1 < (int)a2) continue; // still might be true - } - return false; - } - } - return sawInt; - } - return false; - } - /** Return the index of the last occurrence of n in the argument array. * Return -1 if the name is not used. */ @@ -1690,6 +1609,7 @@ class LambdaForm { static Name internArgument(Name n) { assert(n.isParam()) : "not param: " + n; assert(n.index < INTERNED_ARGUMENT_LIMIT); + if (n.constraint != null) return n; return argument(n.index, n.type); } static Name[] arguments(int extra, String types) { @@ -1858,37 +1778,6 @@ class LambdaForm { @interface Hidden { } - -/* - // Smoke-test for the invokers used in this file. - static void testMethodHandleLinkers() throws Throwable { - MemberName.Factory lookup = MemberName.getFactory(); - MemberName asList_MN = new MemberName(Arrays.class, "asList", - MethodType.methodType(List.class, Object[].class), - REF_invokeStatic); - //MethodHandleNatives.resolve(asList_MN, null); - asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class); - System.out.println("about to call "+asList_MN); - Object[] abc = { "a", "bc" }; - List lst = (List) MethodHandle.linkToStatic(abc, asList_MN); - System.out.println("lst="+lst); - MemberName toString_MN = new MemberName(Object.class.getMethod("toString")); - String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN); - toString_MN = new MemberName(Object.class.getMethod("toString"), true); - String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN); - System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString())); - MemberName toArray_MN = new MemberName(List.class.getMethod("toArray")); - Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN); - System.out.println("toArray="+Arrays.toString(arr)); - } - static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } } - // Requires these definitions in MethodHandle: - static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable; - static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable; - static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable; - static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable; - */ - private static final HashMap DEBUG_NAME_COUNTERS; static { if (debugEnabled()) @@ -1901,7 +1790,7 @@ class LambdaForm { static { createIdentityForms(); if (USE_PREDEFINED_INTERPRET_METHODS) - PREPARED_FORMS.putAll(computeInitialPreparedForms()); + computeInitialPreparedForms(); NamedFunction.initializeInvokers(); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java new file mode 100644 index 00000000000..872a2a59921 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.invoke; + +import java.util.ArrayList; +import java.util.Arrays; +import static java.lang.invoke.LambdaForm.*; +import static java.lang.invoke.LambdaForm.BasicType.*; + +/** Working storage for an LF that is being transformed. + * Similarly to a StringBuffer, the editing can take place in multiple steps. + */ +final class LambdaFormBuffer { + private int arity, length; + private Name[] names; + private Name[] originalNames; // snapshot of pre-transaction names + private byte flags; + private int firstChange; + private Name resultName; + private String debugName; + private ArrayList dups; + + private static final int F_TRANS = 0x10, F_OWNED = 0x03; + + LambdaFormBuffer(LambdaForm lf) { + this(lf.arity, lf.names, lf.result); + debugName = lf.debugName; + assert(lf.nameRefsAreLegal()); + } + + private LambdaFormBuffer(int arity, Name[] names, int result) { + this.arity = arity; + setNames(names); + if (result == LAST_RESULT) result = length - 1; + if (result >= 0 && names[result].type != V_TYPE) + resultName = names[result]; + } + + private LambdaForm lambdaForm() { + assert(!inTrans()); // need endEdit call to tidy things up + return new LambdaForm(debugName, arity, nameArray(), resultIndex()); + } + + Name name(int i) { + assert(i < length); + return names[i]; + } + + Name[] nameArray() { + return Arrays.copyOf(names, length); + } + + int resultIndex() { + if (resultName == null) return VOID_RESULT; + int index = indexOf(resultName, names); + assert(index >= 0); + return index; + } + + void setNames(Name[] names2) { + names = originalNames = names2; // keep a record of where everything was to start with + length = names2.length; + flags = 0; + } + + private boolean verifyArity() { + for (int i = 0; i < arity && i < firstChange; i++) { + assert(names[i].isParam()) : "#" + i + "=" + names[i]; + } + for (int i = arity; i < length; i++) { + assert(!names[i].isParam()) : "#" + i + "=" + names[i]; + } + for (int i = length; i < names.length; i++) { + assert(names[i] == null) : "#" + i + "=" + names[i]; + } + // check resultName also + if (resultName != null) { + int resultIndex = indexOf(resultName, names); + assert(resultIndex >= 0) : "not found: " + resultName.exprString() + Arrays.asList(names); + assert(names[resultIndex] == resultName); + } + return true; + } + + private boolean verifyFirstChange() { + assert(inTrans()); + for (int i = 0; i < length; i++) { + if (names[i] != originalNames[i]) { + assert(firstChange == i) : Arrays.asList(firstChange, i, originalNames[i].exprString(), Arrays.asList(names)); + return true; + } + } + assert(firstChange == length) : Arrays.asList(firstChange, Arrays.asList(names)); + return true; + } + + private static int indexOf(NamedFunction fn, NamedFunction[] fns) { + for (int i = 0; i < fns.length; i++) { + if (fns[i] == fn) return i; + } + return -1; + } + + private static int indexOf(Name n, Name[] ns) { + for (int i = 0; i < ns.length; i++) { + if (ns[i] == n) return i; + } + return -1; + } + + boolean inTrans() { + return (flags & F_TRANS) != 0; + } + + int ownedCount() { + return flags & F_OWNED; + } + + void growNames(int insertPos, int growLength) { + int oldLength = length; + int newLength = oldLength + growLength; + int oc = ownedCount(); + if (oc == 0 || newLength > names.length) { + names = Arrays.copyOf(names, (names.length + growLength) * 5 / 4); + if (oc == 0) { + flags++; + oc++; + assert(ownedCount() == oc); + } + } + if (originalNames != null && originalNames.length < names.length) { + originalNames = Arrays.copyOf(originalNames, names.length); + if (oc == 1) { + flags++; + oc++; + assert(ownedCount() == oc); + } + } + if (growLength == 0) return; + int insertEnd = insertPos + growLength; + int tailLength = oldLength - insertPos; + System.arraycopy(names, insertPos, names, insertEnd, tailLength); + Arrays.fill(names, insertPos, insertEnd, null); + if (originalNames != null) { + System.arraycopy(originalNames, insertPos, originalNames, insertEnd, tailLength); + Arrays.fill(originalNames, insertPos, insertEnd, null); + } + length = newLength; + if (firstChange >= insertPos) { + firstChange += growLength; + } + } + + int lastIndexOf(Name n) { + int result = -1; + for (int i = 0; i < length; i++) { + if (names[i] == n) result = i; + } + return result; + } + + /** We have just overwritten the name at pos1 with the name at pos2. + * This means that there are two copies of the name, which we will have to fix later. + */ + private void noteDuplicate(int pos1, int pos2) { + Name n = names[pos1]; + assert(n == names[pos2]); + assert(originalNames[pos1] != null); // something was replaced at pos1 + assert(originalNames[pos2] == null || originalNames[pos2] == n); + if (dups == null) { + dups = new ArrayList<>(); + } + dups.add(n); + } + + /** Replace duplicate names by nulls, and remove all nulls. */ + private void clearDuplicatesAndNulls() { + if (dups != null) { + // Remove duplicates. + assert(ownedCount() >= 1); + for (Name dup : dups) { + for (int i = firstChange; i < length; i++) { + if (names[i] == dup && originalNames[i] != dup) { + names[i] = null; + assert(Arrays.asList(names).contains(dup)); + break; // kill only one dup + } + } + } + dups.clear(); + } + // Now that we are done with originalNames, remove "killed" names. + int oldLength = length; + for (int i = firstChange; i < length; i++) { + if (names[i] == null) { + System.arraycopy(names, i + 1, names, i, (--length - i)); + --i; // restart loop at this position + } + } + if (length < oldLength) { + Arrays.fill(names, length, oldLength, null); + } + assert(!Arrays.asList(names).subList(0, length).contains(null)); + } + + /** Create a private, writable copy of names. + * Preserve the original copy, for reference. + */ + void startEdit() { + assert(verifyArity()); + int oc = ownedCount(); + assert(!inTrans()); // no nested transactions + flags |= F_TRANS; + Name[] oldNames = names; + Name[] ownBuffer = (oc == 2 ? originalNames : null); + assert(ownBuffer != oldNames); + if (ownBuffer != null && ownBuffer.length >= length) { + names = copyNamesInto(ownBuffer); + } else { + // make a new buffer to hold the names + final int SLOP = 2; + names = Arrays.copyOf(oldNames, Math.max(length + SLOP, oldNames.length)); + if (oc < 2) ++flags; + assert(ownedCount() == oc + 1); + } + originalNames = oldNames; + assert(originalNames != names); + firstChange = length; + assert(inTrans()); + } + + private void changeName(int i, Name name) { + assert(inTrans()); + assert(i < length); + Name oldName = names[i]; + assert(oldName == originalNames[i]); // no multiple changes + assert(verifyFirstChange()); + if (ownedCount() == 0) + growNames(0, 0); + names[i] = name; + if (firstChange > i) { + firstChange = i; + } + if (resultName != null && resultName == oldName) { + resultName = name; + } + } + + /** Change the result name. Null means a void result. */ + void setResult(Name name) { + assert(name == null || lastIndexOf(name) >= 0); + resultName = name; + } + + /** Finish a transaction. */ + LambdaForm endEdit() { + assert(verifyFirstChange()); + // Assuming names have been changed pairwise from originalNames[i] to names[i], + // update arguments to ensure referential integrity. + for (int i = Math.max(firstChange, arity); i < length; i++) { + Name name = names[i]; + if (name == null) continue; // space for removed duplicate + Name newName = name.replaceNames(originalNames, names, firstChange, i); + if (newName != name) { + names[i] = newName; + if (resultName == name) { + resultName = newName; + } + } + } + assert(inTrans()); + flags &= ~F_TRANS; + clearDuplicatesAndNulls(); + originalNames = null; + // If any parameters have been changed, then reorder them as needed. + // This is a "sheep-and-goats" stable sort, pushing all non-parameters + // to the right of all parameters. + if (firstChange < arity) { + Name[] exprs = new Name[arity - firstChange]; + int argp = firstChange, exprp = 0; + for (int i = firstChange; i < arity; i++) { + Name name = names[i]; + if (name.isParam()) { + names[argp++] = name; + } else { + exprs[exprp++] = name; + } + } + assert(exprp == (arity - argp)); + // copy the exprs just after the last remaining param + System.arraycopy(exprs, 0, names, argp, exprp); + // adjust arity + arity -= exprp; + } + assert(verifyArity()); + return lambdaForm(); + } + + private Name[] copyNamesInto(Name[] buffer) { + System.arraycopy(names, 0, buffer, 0, length); + Arrays.fill(buffer, length, buffer.length, null); + return buffer; + } + + /** Replace any Name whose function is in oldFns with a copy + * whose function is in the corresponding position in newFns. + * Only do this if the arguments are exactly equal to the given. + */ + LambdaFormBuffer replaceFunctions(NamedFunction[] oldFns, NamedFunction[] newFns, + Object... forArguments) { + assert(inTrans()); + if (oldFns.length == 0) return this; + for (int i = arity; i < length; i++) { + Name n = names[i]; + int nfi = indexOf(n.function, oldFns); + if (nfi >= 0 && Arrays.equals(n.arguments, forArguments)) { + changeName(i, new Name(newFns[nfi], n.arguments)); + } + } + return this; + } + + private void replaceName(int pos, Name binding) { + assert(inTrans()); + assert(verifyArity()); + assert(pos < arity); + Name param = names[pos]; + assert(param.isParam()); + assert(param.type == binding.type); + changeName(pos, binding); + } + + /** Replace a parameter by a fresh parameter. */ + LambdaFormBuffer renameParameter(int pos, Name newParam) { + assert(newParam.isParam()); + replaceName(pos, newParam); + return this; + } + + /** Replace a parameter by a fresh expression. */ + LambdaFormBuffer replaceParameterByNewExpression(int pos, Name binding) { + assert(!binding.isParam()); + assert(lastIndexOf(binding) < 0); // else use replaceParameterByCopy + replaceName(pos, binding); + return this; + } + + /** Replace a parameter by another parameter or expression already in the form. */ + LambdaFormBuffer replaceParameterByCopy(int pos, int valuePos) { + assert(pos != valuePos); + replaceName(pos, names[valuePos]); + noteDuplicate(pos, valuePos); // temporarily, will occur twice in the names array + return this; + } + + private void insertName(int pos, Name expr, boolean isParameter) { + assert(inTrans()); + assert(verifyArity()); + assert(isParameter ? pos <= arity : pos >= arity); + growNames(pos, 1); + if (isParameter) arity += 1; + changeName(pos, expr); + } + + /** Insert a fresh expression. */ + LambdaFormBuffer insertExpression(int pos, Name expr) { + assert(!expr.isParam()); + insertName(pos, expr, false); + return this; + } + + /** Insert a fresh parameter. */ + LambdaFormBuffer insertParameter(int pos, Name param) { + assert(param.isParam()); + insertName(pos, param, true); + return this; + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java new file mode 100644 index 00000000000..1c29d73b4cc --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.invoke; + +import java.util.Arrays; +import static java.lang.invoke.LambdaForm.*; +import static java.lang.invoke.LambdaForm.BasicType.*; +import static java.lang.invoke.MethodHandleImpl.Intrinsic; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; + +import sun.invoke.util.Wrapper; + +/** Transforms on LFs. + * A lambda-form editor can derive new LFs from its base LF. + * The editor can cache derived LFs, which simplifies the reuse of their underlying bytecodes. + * To support this caching, a LF has an optional pointer to its editor. + */ +class LambdaFormEditor { + final LambdaForm lambdaForm; + + private LambdaFormEditor(LambdaForm lambdaForm) { + this.lambdaForm = lambdaForm; + } + + // Factory method. + static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) { + // TO DO: Consider placing intern logic here, to cut down on duplication. + // lambdaForm = findPreexistingEquivalent(lambdaForm) + return new LambdaFormEditor(lambdaForm); + } + + /** A description of a cached transform, possibly associated with the result of the transform. + * The logical content is a sequence of byte values, starting with a Kind.ordinal value. + * The sequence is unterminated, ending with an indefinite number of zero bytes. + * Sequences that are simple (short enough and with small enough values) pack into a 64-bit long. + */ + private static final class Transform { + final long packedBytes; + final byte[] fullBytes; + final LambdaForm result; // result of transform, or null, if there is none available + + private enum Kind { + NO_KIND, // necessary because ordinal must be greater than zero + BIND_ARG, ADD_ARG, DUP_ARG, + SPREAD_ARGS, + FILTER_ARG, FILTER_RETURN, FILTER_RETURN_TO_ZERO, + COLLECT_ARGS, COLLECT_ARGS_TO_VOID, COLLECT_ARGS_TO_ARRAY, + FOLD_ARGS, FOLD_ARGS_TO_VOID, + PERMUTE_ARGS + //maybe add more for guard with test, catch exception, pointwise type conversions + } + + private static final boolean STRESS_TEST = false; // turn on to disable most packing + private static final int + PACKED_BYTE_SIZE = (STRESS_TEST ? 2 : 4), + PACKED_BYTE_MASK = (1 << PACKED_BYTE_SIZE) - 1, + PACKED_BYTE_MAX_LENGTH = (STRESS_TEST ? 3 : 64 / PACKED_BYTE_SIZE); + + private static long packedBytes(byte[] bytes) { + if (bytes.length > PACKED_BYTE_MAX_LENGTH) return 0; + long pb = 0; + int bitset = 0; + for (int i = 0; i < bytes.length; i++) { + int b = bytes[i] & 0xFF; + bitset |= b; + pb |= (long)b << (i * PACKED_BYTE_SIZE); + } + if (!inRange(bitset)) + return 0; + return pb; + } + private static long packedBytes(int b0, int b1) { + assert(inRange(b0 | b1)); + return ( (b0 << 0*PACKED_BYTE_SIZE) + | (b1 << 1*PACKED_BYTE_SIZE)); + } + private static long packedBytes(int b0, int b1, int b2) { + assert(inRange(b0 | b1 | b2)); + return ( (b0 << 0*PACKED_BYTE_SIZE) + | (b1 << 1*PACKED_BYTE_SIZE) + | (b2 << 2*PACKED_BYTE_SIZE)); + } + private static long packedBytes(int b0, int b1, int b2, int b3) { + assert(inRange(b0 | b1 | b2 | b3)); + return ( (b0 << 0*PACKED_BYTE_SIZE) + | (b1 << 1*PACKED_BYTE_SIZE) + | (b2 << 2*PACKED_BYTE_SIZE) + | (b3 << 3*PACKED_BYTE_SIZE)); + } + private static boolean inRange(int bitset) { + assert((bitset & 0xFF) == bitset); // incoming values must fit in *unsigned* byte + return ((bitset & ~PACKED_BYTE_MASK) == 0); + } + private static byte[] fullBytes(int... byteValues) { + byte[] bytes = new byte[byteValues.length]; + int i = 0; + for (int bv : byteValues) { + bytes[i++] = bval(bv); + } + assert(packedBytes(bytes) == 0); + return bytes; + } + + private byte byteAt(int i) { + long pb = packedBytes; + if (pb == 0) { + if (i >= fullBytes.length) return 0; + return fullBytes[i]; + } + assert(fullBytes == null); + if (i > PACKED_BYTE_MAX_LENGTH) return 0; + int pos = (i * PACKED_BYTE_SIZE); + return (byte)((pb >>> pos) & PACKED_BYTE_MASK); + } + + Kind kind() { return Kind.values()[byteAt(0)]; } + + private Transform(long packedBytes, byte[] fullBytes, LambdaForm result) { + this.packedBytes = packedBytes; + this.fullBytes = fullBytes; + this.result = result; + } + private Transform(long packedBytes) { + this(packedBytes, null, null); + assert(packedBytes != 0); + } + private Transform(byte[] fullBytes) { + this(0, fullBytes, null); + } + + private static byte bval(int b) { + assert((b & 0xFF) == b); // incoming value must fit in *unsigned* byte + return (byte)b; + } + private static byte bval(Kind k) { + return bval(k.ordinal()); + } + static Transform of(Kind k, int b1) { + byte b0 = bval(k); + if (inRange(b0 | b1)) + return new Transform(packedBytes(b0, b1)); + else + return new Transform(fullBytes(b0, b1)); + } + static Transform of(Kind k, int b1, int b2) { + byte b0 = (byte) k.ordinal(); + if (inRange(b0 | b1 | b2)) + return new Transform(packedBytes(b0, b1, b2)); + else + return new Transform(fullBytes(b0, b1, b2)); + } + static Transform of(Kind k, int b1, int b2, int b3) { + byte b0 = (byte) k.ordinal(); + if (inRange(b0 | b1 | b2 | b3)) + return new Transform(packedBytes(b0, b1, b2, b3)); + else + return new Transform(fullBytes(b0, b1, b2, b3)); + } + private static final byte[] NO_BYTES = {}; + static Transform of(Kind k, int... b123) { + return ofBothArrays(k, b123, NO_BYTES); + } + static Transform of(Kind k, int b1, byte[] b234) { + return ofBothArrays(k, new int[]{ b1 }, b234); + } + static Transform of(Kind k, int b1, int b2, byte[] b345) { + return ofBothArrays(k, new int[]{ b1, b2 }, b345); + } + private static Transform ofBothArrays(Kind k, int[] b123, byte[] b456) { + byte[] fullBytes = new byte[1 + b123.length + b456.length]; + int i = 0; + fullBytes[i++] = bval(k); + for (int bv : b123) { + fullBytes[i++] = bval(bv); + } + for (byte bv : b456) { + fullBytes[i++] = bv; + } + long packedBytes = packedBytes(fullBytes); + if (packedBytes != 0) + return new Transform(packedBytes); + else + return new Transform(fullBytes); + } + + Transform withResult(LambdaForm result) { + return new Transform(this.packedBytes, this.fullBytes, result); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Transform && equals((Transform)obj); + } + public boolean equals(Transform that) { + return this.packedBytes == that.packedBytes && Arrays.equals(this.fullBytes, that.fullBytes); + } + @Override + public int hashCode() { + if (packedBytes != 0) { + assert(fullBytes == null); + return Long.hashCode(packedBytes); + } + return Arrays.hashCode(fullBytes); + } + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + long bits = packedBytes; + if (bits != 0) { + buf.append("("); + while (bits != 0) { + buf.append(bits & PACKED_BYTE_MASK); + bits >>>= PACKED_BYTE_SIZE; + if (bits != 0) buf.append(","); + } + buf.append(")"); + } + if (fullBytes != null) { + buf.append("unpacked"); + buf.append(Arrays.toString(fullBytes)); + } + if (result != null) { + buf.append(" result="); + buf.append(result); + } + return buf.toString(); + } + } + + /** Find a previously cached transform equivalent to the given one, and return its result. */ + private LambdaForm getInCache(Transform key) { + assert(key.result == null); + // The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap. + Object c = lambdaForm.transformCache; + Transform k = null; + if (c instanceof ConcurrentHashMap) { + @SuppressWarnings("unchecked") + ConcurrentHashMap m = (ConcurrentHashMap) c; + k = m.get(key); + } else if (c == null) { + return null; + } else if (c instanceof Transform) { + // one-element cache avoids overhead of an array + Transform t = (Transform)c; + if (t.equals(key)) k = t; + } else { + Transform[] ta = (Transform[])c; + for (int i = 0; i < ta.length; i++) { + Transform t = ta[i]; + if (t == null) break; + if (t.equals(key)) { k = t; break; } + } + } + assert(k == null || key.equals(k)); + return k == null ? null : k.result; + } + + /** Arbitrary but reasonable limits on Transform[] size for cache. */ + private static final int MIN_CACHE_ARRAY_SIZE = 4, MAX_CACHE_ARRAY_SIZE = 16; + + /** Cache a transform with its result, and return that result. + * But if an equivalent transform has already been cached, return its result instead. + */ + private LambdaForm putInCache(Transform key, LambdaForm form) { + key = key.withResult(form); + for (int pass = 0; ; pass++) { + Object c = lambdaForm.transformCache; + if (c instanceof ConcurrentHashMap) { + @SuppressWarnings("unchecked") + ConcurrentHashMap m = (ConcurrentHashMap) c; + Transform k = m.putIfAbsent(key, key); + return k != null ? k.result : form; + } + assert(pass == 0); + synchronized (lambdaForm) { + c = lambdaForm.transformCache; + if (c instanceof ConcurrentHashMap) + continue; + if (c == null) { + lambdaForm.transformCache = key; + return form; + } + Transform[] ta; + if (c instanceof Transform) { + Transform k = (Transform)c; + if (k.equals(key)) { + return k.result; + } + // expand one-element cache to small array + ta = new Transform[MIN_CACHE_ARRAY_SIZE]; + ta[0] = k; + lambdaForm.transformCache = c = ta; + } else { + // it is already expanded + ta = (Transform[])c; + } + int len = ta.length; + int i; + for (i = 0; i < len; i++) { + Transform k = ta[i]; + if (k == null) { + break; + } + if (k.equals(key)) { + return k.result; + } + } + if (i < len) { + // just fall through to cache update + } else if (len < MAX_CACHE_ARRAY_SIZE) { + len = Math.min(len * 2, MAX_CACHE_ARRAY_SIZE); + ta = Arrays.copyOf(ta, len); + lambdaForm.transformCache = ta; + } else { + ConcurrentHashMap m = new ConcurrentHashMap<>(MAX_CACHE_ARRAY_SIZE * 2); + for (Transform k : ta) { + m.put(k, k); + } + lambdaForm.transformCache = m; + // The second iteration will update for this query, concurrently. + continue; + } + ta[i] = key; + return form; + } + } + } + + private LambdaFormBuffer buffer() { + return new LambdaFormBuffer(lambdaForm); + } + + /// Editing methods for method handles. These need to have fast paths. + + private BoundMethodHandle.SpeciesData oldSpeciesData() { + return BoundMethodHandle.speciesData(lambdaForm); + } + private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) { + return oldSpeciesData().extendWith(type); + } + + BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) { + assert(mh.speciesData() == oldSpeciesData()); + BasicType bt = L_TYPE; + MethodType type2 = bindArgumentType(mh, pos, bt); + LambdaForm form2 = bindArgumentForm(1+pos); + return mh.copyWithExtendL(type2, form2, value); + } + BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) { + assert(mh.speciesData() == oldSpeciesData()); + BasicType bt = I_TYPE; + MethodType type2 = bindArgumentType(mh, pos, bt); + LambdaForm form2 = bindArgumentForm(1+pos); + return mh.copyWithExtendI(type2, form2, value); + } + + BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) { + assert(mh.speciesData() == oldSpeciesData()); + BasicType bt = J_TYPE; + MethodType type2 = bindArgumentType(mh, pos, bt); + LambdaForm form2 = bindArgumentForm(1+pos); + return mh.copyWithExtendJ(type2, form2, value); + } + + BoundMethodHandle bindArgumentF(BoundMethodHandle mh, int pos, float value) { + assert(mh.speciesData() == oldSpeciesData()); + BasicType bt = F_TYPE; + MethodType type2 = bindArgumentType(mh, pos, bt); + LambdaForm form2 = bindArgumentForm(1+pos); + return mh.copyWithExtendF(type2, form2, value); + } + + BoundMethodHandle bindArgumentD(BoundMethodHandle mh, int pos, double value) { + assert(mh.speciesData() == oldSpeciesData()); + BasicType bt = D_TYPE; + MethodType type2 = bindArgumentType(mh, pos, bt); + LambdaForm form2 = bindArgumentForm(1+pos); + return mh.copyWithExtendD(type2, form2, value); + } + + private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) { + assert(mh.form == lambdaForm); + assert(mh.form.names[1+pos].type == bt); + assert(BasicType.basicType(mh.type().parameterType(pos)) == bt); + return mh.type().dropParameterTypes(pos, pos+1); + } + + /// Editing methods for lambda forms. + // Each editing method can (potentially) cache the edited LF so that it can be reused later. + + LambdaForm bindArgumentForm(int pos) { + Transform key = Transform.of(Transform.Kind.BIND_ARG, pos); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos))); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); + BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos)); + Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values + Name newBaseAddress; + NamedFunction getter = newData.getterFunction(oldData.fieldCount()); + + if (pos != 0) { + // The newly created LF will run with a different BMH. + // Switch over any pre-existing BMH field references to the new BMH class. + buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); + newBaseAddress = oldBaseAddress.withConstraint(newData); + buf.renameParameter(0, newBaseAddress); + buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress)); + } else { + // cannot bind the MH arg itself, unless oldData is empty + assert(oldData == BoundMethodHandle.SpeciesData.EMPTY); + newBaseAddress = new Name(L_TYPE).withConstraint(newData); + buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress)); + buf.insertParameter(0, newBaseAddress); + } + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm addArgumentForm(int pos, BasicType type) { + Transform key = Transform.of(Transform.Kind.ADD_ARG, pos, type.ordinal()); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity+1); + assert(form.parameterType(pos) == type); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + buf.insertParameter(pos, new Name(type)); + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm dupArgumentForm(int srcPos, int dstPos) { + Transform key = Transform.of(Transform.Kind.DUP_ARG, srcPos, dstPos); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity-1); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + assert(lambdaForm.parameter(srcPos).constraint == null); + assert(lambdaForm.parameter(dstPos).constraint == null); + buf.replaceParameterByCopy(dstPos, srcPos); + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm spreadArgumentsForm(int pos, Class arrayType, int arrayLength) { + Class elementType = arrayType.getComponentType(); + Class erasedArrayType = arrayType; + if (!elementType.isPrimitive()) + erasedArrayType = Object[].class; + BasicType bt = basicType(elementType); + int elementTypeKey = bt.ordinal(); + if (bt.basicTypeClass() != elementType) { + if (elementType.isPrimitive()) { + elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal(); + } + } + Transform key = Transform.of(Transform.Kind.SPREAD_ARGS, pos, elementTypeKey, arrayLength); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity - arrayLength + 1); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + assert(pos <= MethodType.MAX_JVM_ARITY); + assert(pos + arrayLength <= lambdaForm.arity); + assert(pos > 0); // cannot spread the MH arg itself + + Name spreadParam = new Name(L_TYPE); + Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength); + + // insert the new expressions + int exprPos = lambdaForm.arity(); + buf.insertExpression(exprPos++, checkSpread); + // adjust the arguments + MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType); + for (int i = 0; i < arrayLength; i++) { + Name loadArgument = new Name(aload, spreadParam, i); + buf.insertExpression(exprPos + i, loadArgument); + buf.replaceParameterByCopy(pos + i, exprPos + i); + } + buf.insertParameter(pos, spreadParam); + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm collectArgumentsForm(int pos, MethodType collectorType) { + int collectorArity = collectorType.parameterCount(); + boolean dropResult = (collectorType.returnType() == void.class); + if (collectorArity == 1 && !dropResult) { + return filterArgumentForm(pos, basicType(collectorType.parameterType(0))); + } + BasicType[] newTypes = BasicType.basicTypes(collectorType.parameterList()); + Transform.Kind kind = (dropResult + ? Transform.Kind.COLLECT_ARGS_TO_VOID + : Transform.Kind.COLLECT_ARGS); + if (dropResult && collectorArity == 0) pos = 1; // pure side effect + Transform key = Transform.of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes)); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity); + return form; + } + form = makeArgumentCombinationForm(pos, collectorType, false, dropResult); + return putInCache(key, form); + } + + LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) { + MethodType collectorType = arrayCollector.type(); + int collectorArity = collectorType.parameterCount(); + assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY); + Class arrayType = collectorType.returnType(); + Class elementType = arrayType.getComponentType(); + BasicType argType = basicType(elementType); + int argTypeKey = argType.ordinal(); + if (argType.basicTypeClass() != elementType) { + // return null if it requires more metadata (like String[].class) + if (!elementType.isPrimitive()) + return null; + argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal(); + } + assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType))); + Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY; + Transform key = Transform.of(kind, pos, collectorArity, argTypeKey); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity - 1 + collectorArity); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + assert(pos + 1 <= lambdaForm.arity); + assert(pos > 0); // cannot filter the MH arg itself + + Name[] newParams = new Name[collectorArity]; + for (int i = 0; i < collectorArity; i++) { + newParams[i] = new Name(pos + i, argType); + } + Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams); + + // insert the new expression + int exprPos = lambdaForm.arity(); + buf.insertExpression(exprPos, callCombiner); + + // insert new arguments + int argPos = pos + 1; // skip result parameter + for (Name newParam : newParams) { + buf.insertParameter(argPos++, newParam); + } + assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length); + buf.replaceParameterByCopy(pos, exprPos+newParams.length); + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm filterArgumentForm(int pos, BasicType newType) { + Transform key = Transform.of(Transform.Kind.FILTER_ARG, pos, newType.ordinal()); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity); + assert(form.parameterType(pos) == newType); + return form; + } + + BasicType oldType = lambdaForm.parameterType(pos); + MethodType filterType = MethodType.methodType(oldType.basicTypeClass(), + newType.basicTypeClass()); + form = makeArgumentCombinationForm(pos, filterType, false, false); + return putInCache(key, form); + } + + private LambdaForm makeArgumentCombinationForm(int pos, + MethodType combinerType, + boolean keepArguments, boolean dropResult) { + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + int combinerArity = combinerType.parameterCount(); + int resultArity = (dropResult ? 0 : 1); + + assert(pos <= MethodType.MAX_JVM_ARITY); + assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity); + assert(pos > 0); // cannot filter the MH arg itself + assert(combinerType == combinerType.basicType()); + assert(combinerType.returnType() != void.class || dropResult); + + BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); + BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE); + + // The newly created LF will run with a different BMH. + // Switch over any pre-existing BMH field references to the new BMH class. + Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values + buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); + Name newBaseAddress = oldBaseAddress.withConstraint(newData); + buf.renameParameter(0, newBaseAddress); + + Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress); + Object[] combinerArgs = new Object[1 + combinerArity]; + combinerArgs[0] = getCombiner; + Name[] newParams; + if (keepArguments) { + newParams = new Name[0]; + System.arraycopy(lambdaForm.names, pos + resultArity, + combinerArgs, 1, combinerArity); + } else { + newParams = new Name[combinerArity]; + BasicType[] newTypes = basicTypes(combinerType.parameterList()); + for (int i = 0; i < newTypes.length; i++) { + newParams[i] = new Name(pos + i, newTypes[i]); + } + System.arraycopy(newParams, 0, + combinerArgs, 1, combinerArity); + } + Name callCombiner = new Name(combinerType, combinerArgs); + + // insert the two new expressions + int exprPos = lambdaForm.arity(); + buf.insertExpression(exprPos+0, getCombiner); + buf.insertExpression(exprPos+1, callCombiner); + + // insert new arguments, if needed + int argPos = pos + resultArity; // skip result parameter + for (Name newParam : newParams) { + buf.insertParameter(argPos++, newParam); + } + assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length); + if (!dropResult) { + buf.replaceParameterByCopy(pos, exprPos+1+newParams.length); + } + + return buf.endEdit(); + } + + LambdaForm filterReturnForm(BasicType newType, boolean constantZero) { + Transform.Kind kind = (constantZero ? Transform.Kind.FILTER_RETURN_TO_ZERO : Transform.Kind.FILTER_RETURN); + Transform key = Transform.of(kind, newType.ordinal()); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity); + assert(form.returnType() == newType); + return form; + } + LambdaFormBuffer buf = buffer(); + buf.startEdit(); + + int insPos = lambdaForm.names.length; + Name callFilter; + if (constantZero) { + // Synthesize a constant zero value for the given type. + if (newType == V_TYPE) + callFilter = null; + else + callFilter = new Name(constantZero(newType)); + } else { + BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); + BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE); + + // The newly created LF will run with a different BMH. + // Switch over any pre-existing BMH field references to the new BMH class. + Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values + buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); + Name newBaseAddress = oldBaseAddress.withConstraint(newData); + buf.renameParameter(0, newBaseAddress); + + Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress); + buf.insertExpression(insPos++, getFilter); + BasicType oldType = lambdaForm.returnType(); + if (oldType == V_TYPE) { + MethodType filterType = MethodType.methodType(newType.basicTypeClass()); + callFilter = new Name(filterType, getFilter); + } else { + MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass()); + callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]); + } + } + + if (callFilter != null) + buf.insertExpression(insPos++, callFilter); + buf.setResult(callFilter); + + form = buf.endEdit(); + return putInCache(key, form); + } + + LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) { + int combinerArity = combinerType.parameterCount(); + Transform.Kind kind = (dropResult ? Transform.Kind.FOLD_ARGS_TO_VOID : Transform.Kind.FOLD_ARGS); + Transform key = Transform.of(kind, foldPos, combinerArity); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == lambdaForm.arity - (kind == Transform.Kind.FOLD_ARGS ? 1 : 0)); + return form; + } + form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult); + return putInCache(key, form); + } + + LambdaForm permuteArgumentsForm(int skip, int[] reorder) { + assert(skip == 1); // skip only the leading MH argument, names[0] + int length = lambdaForm.names.length; + int outArgs = reorder.length; + int inTypes = 0; + boolean nullPerm = true; + for (int i = 0; i < reorder.length; i++) { + int inArg = reorder[i]; + if (inArg != i) nullPerm = false; + inTypes = Math.max(inTypes, inArg+1); + } + assert(skip + reorder.length == lambdaForm.arity); + if (nullPerm) return lambdaForm; // do not bother to cache + Transform key = Transform.of(Transform.Kind.PERMUTE_ARGS, reorder); + LambdaForm form = getInCache(key); + if (form != null) { + assert(form.arity == skip+inTypes) : form; + return form; + } + + BasicType[] types = new BasicType[inTypes]; + for (int i = 0; i < outArgs; i++) { + int inArg = reorder[i]; + types[inArg] = lambdaForm.names[skip + i].type; + } + assert (skip + outArgs == lambdaForm.arity); + assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip)); + int pos = 0; + while (pos < outArgs && reorder[pos] == pos) { + pos += 1; + } + Name[] names2 = new Name[length - outArgs + inTypes]; + System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos); + int bodyLength = length - lambdaForm.arity; + System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength); + int arity2 = names2.length - bodyLength; + int result2 = lambdaForm.result; + if (result2 >= 0) { + if (result2 < skip + outArgs) { + result2 = reorder[result2 - skip]; + } else { + result2 = result2 - outArgs + inTypes; + } + } + for (int j = pos; j < outArgs; j++) { + Name n = lambdaForm.names[skip + j]; + int i = reorder[j]; + Name n2 = names2[skip + i]; + if (n2 == null) { + names2[skip + i] = n2 = new Name(types[i]); + } else { + assert (n2.type == types[i]); + } + for (int k = arity2; k < names2.length; k++) { + names2[k] = names2[k].replaceName(n, n2); + } + } + for (int i = skip + pos; i < arity2; i++) { + if (names2[i] == null) { + names2[i] = argument(i, types[i - skip]); + } + } + for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) { + int i = j - lambdaForm.arity + arity2; + Name n = lambdaForm.names[j]; + Name n2 = names2[i]; + if (n != n2) { + for (int k = i + 1; k < names2.length; k++) { + names2[k] = names2[k].replaceName(n, n2); + } + } + } + + form = new LambdaForm(lambdaForm.debugName, arity2, names2, result2); + return putInCache(key, form); + } + + static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) { + for (int i = 0; i < reorder.length; i++) { + assert (names[skip + i].isParam()); + assert (names[skip + i].type == types[reorder[i]]); + } + return true; + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index 75b26be4e0c..d4634c84a8e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -327,10 +327,6 @@ import java.util.Objects; assert(getReferenceKind() == oldKind); assert(MethodHandleNatives.refKindIsValid(refKind)); flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT); -// if (isConstructor() && refKind != REF_newInvokeSpecial) -// flags += (IS_METHOD - IS_CONSTRUCTOR); -// else if (refKind == REF_newInvokeSpecial && isMethod()) -// flags += (IS_CONSTRUCTOR - IS_METHOD); return this; } @@ -344,9 +340,11 @@ import java.util.Objects; return !testFlags(mask, 0); } - /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */ + /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). + * Also returns true for the non-public MH.invokeBasic. + */ public boolean isMethodHandleInvoke() { - final int bits = MH_INVOKE_MODS; + final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC; final int negs = Modifier.STATIC; if (testFlags(bits | negs, bits) && clazz == MethodHandle.class) { @@ -355,7 +353,14 @@ import java.util.Objects; return false; } public static boolean isMethodHandleInvokeName(String name) { - return name.equals("invoke") || name.equals("invokeExact"); + switch (name) { + case "invoke": + case "invokeExact": + case "invokeBasic": // internal sig-poly method + return true; + default: + return false; + } } private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC; @@ -720,16 +725,8 @@ import java.util.Objects; init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind)); initResolved(false); } - /** Create a field or type name from the given components: Declaring class, name, type. - * The declaring class may be supplied as null if this is to be a bare name and type. - * The modifier flags default to zero. - * The resulting name will in an unresolved state. - */ - public MemberName(Class defClass, String name, Class type, Void unused) { - this(defClass, name, type, REF_NONE); - initResolved(false); - } - /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers. + /** Create a method or constructor name from the given components: + * Declaring class, name, type, reference kind. * It will be a constructor if and only if the name is {@code "<init>"}. * The declaring class may be supplied as null if this is to be a bare name and type. * The last argument is optional, a boolean which requests REF_invokeSpecial. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 5ed091e408f..e72a07a2aff 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -27,12 +27,8 @@ package java.lang.invoke; import java.util.*; -import java.lang.invoke.LambdaForm.BasicType; -import sun.invoke.util.*; -import sun.misc.Unsafe; import static java.lang.invoke.MethodHandleStatics.*; -import static java.lang.invoke.LambdaForm.BasicType.*; /** * A method handle is a typed, directly executable reference to an underlying method, @@ -625,15 +621,8 @@ public abstract class MethodHandle { * @see MethodHandles#spreadInvoker */ public Object invokeWithArguments(Object... arguments) throws Throwable { - int argc = arguments == null ? 0 : arguments.length; - @SuppressWarnings("LocalVariableHidesMemberVariable") - MethodType type = type(); - if (type.parameterCount() != argc || isVarargsCollector()) { - // simulate invoke - return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments); - } - MethodHandle invoker = type.invokers().varargsInvoker(); - return invoker.invokeExact(this, arguments); + MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length); + return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments); } /** @@ -763,18 +752,26 @@ public abstract class MethodHandle { return this; } // Return 'this.asTypeCache' if the conversion is already memoized. + MethodHandle atc = asTypeCached(newType); + if (atc != null) { + return atc; + } + return asTypeUncached(newType); + } + + private MethodHandle asTypeCached(MethodType newType) { MethodHandle atc = asTypeCache; if (atc != null && newType == atc.type) { return atc; } - return asTypeUncached(newType); + return null; } /** Override this to change asType behavior. */ /*non-public*/ MethodHandle asTypeUncached(MethodType newType) { if (!type.isConvertibleTo(newType)) throw new WrongMethodTypeException("cannot convert "+this+" to "+newType); - return asTypeCache = convertArguments(newType); + return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, true); } /** @@ -867,34 +864,48 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray * @see #asCollector */ public MethodHandle asSpreader(Class arrayType, int arrayLength) { - asSpreaderChecks(arrayType, arrayLength); - int spreadArgPos = type.parameterCount() - arrayLength; - return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength); + MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength); + int arity = type().parameterCount(); + int spreadArgPos = arity - arrayLength; + if (USE_LAMBDA_FORM_EDITOR) { + MethodHandle afterSpread = this.asType(postSpreadType); + BoundMethodHandle mh = afterSpread.rebind(); + LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength); + MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType); + return mh.copyWith(preSpreadType, lform); + } else { + return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength); + } } - private void asSpreaderChecks(Class arrayType, int arrayLength) { + /** + * See if {@code asSpreader} can be validly called with the given arguments. + * Return the type of the method handle call after spreading but before conversions. + */ + private MethodType asSpreaderChecks(Class arrayType, int arrayLength) { spreadArrayChecks(arrayType, arrayLength); int nargs = type().parameterCount(); if (nargs < arrayLength || arrayLength < 0) throw newIllegalArgumentException("bad spread array length"); - if (arrayType != Object[].class && arrayLength != 0) { - boolean sawProblem = false; - Class arrayElement = arrayType.getComponentType(); - for (int i = nargs - arrayLength; i < nargs; i++) { - if (!MethodType.canConvert(arrayElement, type().parameterType(i))) { - sawProblem = true; + Class arrayElement = arrayType.getComponentType(); + MethodType mtype = type(); + boolean match = true, fail = false; + for (int i = nargs - arrayLength; i < nargs; i++) { + Class ptype = mtype.parameterType(i); + if (ptype != arrayElement) { + match = false; + if (!MethodType.canConvert(arrayElement, ptype)) { + fail = true; break; } } - if (sawProblem) { - ArrayList> ptypes = new ArrayList<>(type().parameterList()); - for (int i = nargs - arrayLength; i < nargs; i++) { - ptypes.set(i, arrayElement); - } - // elicit an error: - this.asType(MethodType.methodType(type().returnType(), ptypes)); - } } + if (match) return mtype; + MethodType needType = mtype.asSpreaderType(arrayType, arrayLength); + if (!fail) return needType; + // elicit an error: + this.asType(needType); + throw newInternalError("should not return", null); } private void spreadArrayChecks(Class arrayType, int arrayLength) { @@ -984,16 +995,31 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123)); */ public MethodHandle asCollector(Class arrayType, int arrayLength) { asCollectorChecks(arrayType, arrayLength); - int collectArgPos = type().parameterCount()-1; - MethodHandle target = this; - if (arrayType != type().parameterType(collectArgPos)) - target = convertArguments(type().changeParameterType(collectArgPos, arrayType)); - MethodHandle collector = ValueConversions.varargsArray(arrayType, arrayLength); - return MethodHandles.collectArguments(target, collectArgPos, collector); + int collectArgPos = type().parameterCount() - 1; + if (USE_LAMBDA_FORM_EDITOR) { + BoundMethodHandle mh = rebind(); + MethodType resultType = type().asCollectorType(arrayType, arrayLength); + MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength); + LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray); + if (lform != null) { + return mh.copyWith(resultType, lform); + } + lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType()); + return mh.copyWithExtendL(resultType, lform, newArray); + } else { + MethodHandle target = this; + if (arrayType != type().parameterType(collectArgPos)) + target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true); + MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength); + return MethodHandles.collectArguments(target, collectArgPos, collector); + } } - // private API: return true if last param exactly matches arrayType - private boolean asCollectorChecks(Class arrayType, int arrayLength) { + /** + * See if {@code asCollector} can be validly called with the given arguments. + * Return false if the last parameter is not an exact match to arrayType. + */ + /*non-public*/ boolean asCollectorChecks(Class arrayType, int arrayLength) { spreadArrayChecks(arrayType, arrayLength); int nargs = type().parameterCount(); if (nargs != 0) { @@ -1155,7 +1181,7 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); * @see #asFixedArity */ public MethodHandle asVarargsCollector(Class arrayType) { - Class arrayElement = arrayType.getComponentType(); + arrayType.getClass(); // explicit NPE boolean lastMatch = asCollectorChecks(arrayType, 0); if (isVarargsCollector() && lastMatch) return this; @@ -1257,14 +1283,8 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); * @see MethodHandles#insertArguments */ public MethodHandle bindTo(Object x) { - Class ptype; - @SuppressWarnings("LocalVariableHidesMemberVariable") - MethodType type = type(); - if (type.parameterCount() == 0 || - (ptype = type.parameterType(0)).isPrimitive()) - throw newIllegalArgumentException("no leading reference parameter", x); - x = ptype.cast(x); // throw CCE if needed - return bindReceiver(x); + x = type.leadingReferenceParameter().cast(x); // throw CCE if needed + return bindArgumentL(0, x); } /** @@ -1284,14 +1304,17 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); */ @Override public String toString() { - if (DEBUG_METHOD_HANDLE_NAMES) return debugString(); + if (DEBUG_METHOD_HANDLE_NAMES) return "MethodHandle"+debugString(); return standardString(); } String standardString() { return "MethodHandle"+type; } + /** Return a string with a several lines describing the method handle structure. + * This string would be suitable for display in an IDE debugger. + */ String debugString() { - return standardString()+"/LF="+internalForm()+internalProperties(); + return type+" : "+internalForm()+internalProperties(); } //// Implementation methods. @@ -1300,22 +1323,42 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); // Other transforms to do: convert, explicitCast, permute, drop, filter, fold, GWT, catch + BoundMethodHandle bindArgumentL(int pos, Object value) { + return rebind().bindArgumentL(pos, value); + } + /*non-public*/ MethodHandle setVarargs(MemberName member) throws IllegalAccessException { if (!member.isVarargs()) return this; - int argc = type().parameterCount(); - if (argc != 0) { - Class arrayType = type().parameterType(argc-1); - if (arrayType.isArray()) { - return MethodHandleImpl.makeVarargsCollector(this, arrayType); - } + Class arrayType = type().lastParameterType(); + if (arrayType.isArray()) { + return MethodHandleImpl.makeVarargsCollector(this, arrayType); } throw member.makeAccessException("cannot make variable arity", null); } + /*non-public*/ - MethodHandle viewAsType(MethodType newType) { + MethodHandle viewAsType(MethodType newType, boolean strict) { // No actual conversions, just a new view of the same method. - return MethodHandleImpl.makePairwiseConvert(this, newType, 0); + // Note that this operation must not produce a DirectMethodHandle, + // because retyped DMHs, like any transformed MHs, + // cannot be cracked into MethodHandleInfo. + assert viewAsTypeChecks(newType, strict); + BoundMethodHandle mh = rebind(); + assert(!((MethodHandle)mh instanceof DirectMethodHandle)); + return mh.copyWith(newType, mh.form); + } + + /*non-public*/ + boolean viewAsTypeChecks(MethodType newType, boolean strict) { + if (strict) { + assert(type().isViewableAs(newType, true)) + : Arrays.asList(this, newType); + } else { + assert(type().basicType().isViewableAs(newType.basicType(), true)) + : Arrays.asList(this, newType); + } + return true; } // Decoding @@ -1336,9 +1379,15 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); } /*non-public*/ - MethodHandle withInternalMemberName(MemberName member) { + MethodHandleImpl.Intrinsic intrinsicName() { + // no special intrinsic meaning to most MHs + return MethodHandleImpl.Intrinsic.NONE; + } + + /*non-public*/ + MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) { if (member != null) { - return MethodHandleImpl.makeWrappedMember(this, member); + return MethodHandleImpl.makeWrappedMember(this, member, isInvokeSpecial); } else if (internalMemberName() == null) { // The required internaMemberName is null, and this MH (like most) doesn't have one. return this; @@ -1362,7 +1411,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); /*non-public*/ Object internalProperties() { - // Override to something like "/FOO=bar" + // Override to something to follow this.form, like "\n& FOO=bar" return ""; } @@ -1370,95 +1419,14 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); //// Sub-classes can override these default implementations. //// All these methods assume arguments are already validated. - /*non-public*/ MethodHandle convertArguments(MethodType newType) { - // Override this if it can be improved. - return MethodHandleImpl.makePairwiseConvert(this, newType, 1); - } - /*non-public*/ - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - // Override this if it can be improved. - return rebind().bindArgument(pos, basicType, value); - } + abstract MethodHandle copyWith(MethodType mt, LambdaForm lf); - /*non-public*/ - MethodHandle bindReceiver(Object receiver) { - // Override this if it can be improved. - return bindArgument(0, L_TYPE, receiver); - } - - /*non-public*/ - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - // Override this if it can be improved. - return rebind().dropArguments(srcType, pos, drops); - } - - /*non-public*/ - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - // Override this if it can be improved. - return rebind().permuteArguments(newType, reorder); - } - - /*non-public*/ - MethodHandle rebind() { - // Bind 'this' into a new invoker, of the known class BMH. - MethodType type2 = type(); - LambdaForm form2 = reinvokerForm(this); - // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) } - return BoundMethodHandle.bindSingle(type2, form2, this); - } - - /*non-public*/ - MethodHandle reinvokerTarget() { - throw new InternalError("not a reinvoker MH: "+this.getClass().getName()+": "+this); - } - - /** Create a LF which simply reinvokes a target of the given basic type. - * The target MH must override {@link #reinvokerTarget} to provide the target. + /** Require this method handle to be a BMH, or else replace it with a "wrapper" BMH. + * Many transforms are implemented only for BMHs. + * @return a behaviorally equivalent BMH */ - static LambdaForm reinvokerForm(MethodHandle target) { - MethodType mtype = target.type().basicType(); - LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE); - if (reinvoker != null) return reinvoker; - if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY) - return makeReinvokerForm(target.type(), target); // cannot cache this - reinvoker = makeReinvokerForm(mtype, null); - return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker); - } - private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) { - boolean customized = (customTargetOrNull != null); - MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype); - final int THIS_BMH = 0; - final int ARG_BASE = 1; - final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); - int nameCursor = ARG_LIMIT; - final int NEXT_MH = customized ? -1 : nameCursor++; - final int REINVOKE = nameCursor++; - LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); - Object[] targetArgs; - MethodHandle targetMH; - if (customized) { - targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); - targetMH = customTargetOrNull; - } else { - names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]); - targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class); - targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH - targetMH = MethodHandles.basicInvoker(mtype); - } - names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs); - return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names); - } - - private static final LambdaForm.NamedFunction NF_reinvokerTarget; - static { - try { - NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class - .getDeclaredMethod("reinvokerTarget")); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - } + abstract BoundMethodHandle rebind(); /** * Replace the old lambda form of this method handle with a new one. @@ -1470,6 +1438,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); /*non-public*/ void updateForm(LambdaForm newForm) { if (form == newForm) return; + assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic()); // ISSUE: Should we have a memory fence here? UNSAFE.putObject(this, FORM_OFFSET, newForm); this.form.prepare(); // as in MethodHandle. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 3e4ee65e161..7b018f036cf 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -27,8 +27,10 @@ package java.lang.invoke; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; +import java.util.Collections; + import sun.invoke.empty.Empty; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; @@ -44,6 +46,20 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; * @author jrose */ /*non-public*/ abstract class MethodHandleImpl { + // Do not adjust this except for special platforms: + private static final int MAX_ARITY; + static { + final Object[] values = { 255 }; + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + values[0] = Integer.getInteger(MethodHandleImpl.class.getName()+".MAX_ARITY", 255); + return null; + } + }); + MAX_ARITY = (Integer) values[0]; + } + /// Factory methods to create method handles: static void initStatics() { @@ -52,27 +68,55 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } static MethodHandle makeArrayElementAccessor(Class arrayClass, boolean isSetter) { + if (arrayClass == Object[].class) + return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); if (!arrayClass.isArray()) throw newIllegalArgumentException("not an array: "+arrayClass); - MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter); - MethodType srcType = accessor.type().erase(); - MethodType lambdaType = srcType.invokerType(); - Name[] names = arguments(1, lambdaType); - Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount()); - names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args); - LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names); - MethodHandle mh = SimpleMethodHandle.make(srcType, form); - if (ArrayAccessor.needCast(arrayClass)) { - mh = mh.bindTo(arrayClass); + MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass); + int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX); + MethodHandle mh = cache[cacheIndex]; + if (mh != null) return mh; + mh = ArrayAccessor.getAccessor(arrayClass, isSetter); + MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); + if (mh.type() != correctType) { + assert(mh.type().parameterType(0) == Object[].class); + assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); + assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); + // safe to view non-strictly, because element type follows from array type + mh = mh.viewAsType(correctType, false); + } + mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD)); + // Atomically update accessor cache. + synchronized(cache) { + if (cache[cacheIndex] == null) { + cache[cacheIndex] = mh; + } else { + // Throw away newly constructed accessor and use cached version. + mh = cache[cacheIndex]; + } } - mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter)); return mh; } static final class ArrayAccessor { /// Support for array element access - static final HashMap, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it - static final HashMap, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it + static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; + static final ClassValue TYPED_ACCESSORS + = new ClassValue() { + @Override + protected MethodHandle[] computeValue(Class type) { + return new MethodHandle[INDEX_LIMIT]; + } + }; + static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER; + static { + MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); + cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD); + cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE); + + assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName())); + assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName())); + } static int getElementI(int[] a, int i) { return a[i]; } static long getElementJ(long[] a, int i) { return a[i]; } @@ -94,45 +138,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static void setElementC(char[] a, int i, char x) { a[i] = x; } static void setElementL(Object[] a, int i, Object x) { a[i] = x; } - static Object getElementL(Class arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; } - static void setElementL(Class arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; } - - // Weakly typed wrappers of Object[] accessors: - static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); } - static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); } - static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class) arrayClass, (Object[])a, i); } - static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class) arrayClass, (Object[])a, i, x); } - - static boolean needCast(Class arrayClass) { - Class elemClass = arrayClass.getComponentType(); - return !elemClass.isPrimitive() && elemClass != Object.class; - } static String name(Class arrayClass, boolean isSetter) { Class elemClass = arrayClass.getComponentType(); - if (elemClass == null) throw new IllegalArgumentException(); + if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); } - static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide static MethodType type(Class arrayClass, boolean isSetter) { Class elemClass = arrayClass.getComponentType(); Class arrayArgClass = arrayClass; if (!elemClass.isPrimitive()) { arrayArgClass = Object[].class; - if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS) - arrayArgClass = Object.class; + elemClass = Object.class; } - if (!needCast(arrayClass)) { - return !isSetter ? + return !isSetter ? MethodType.methodType(elemClass, arrayArgClass, int.class) : MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); - } else { - Class classArgClass = Class.class; - if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS) - classArgClass = Object.class; - return !isSetter ? - MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) : - MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class); - } } static MethodType correctType(Class arrayClass, boolean isSetter) { Class elemClass = arrayClass.getComponentType(); @@ -159,40 +179,110 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; * integral widening or narrowing, and floating point widening or narrowing. * @param srcType required call type * @param target original method handle - * @param level which strength of conversion is allowed + * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed + * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double) * @return an adapter to the original handle with the desired new type, * or the original target if the types are already identical * or null if the adaptation cannot be made */ - static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) { - assert(level >= 0 && level <= 2); + static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, + boolean strict, boolean monobox) { MethodType dstType = target.type(); assert(dstType.parameterCount() == target.type().parameterCount()); if (srcType == dstType) return target; + if (USE_LAMBDA_FORM_EDITOR) { + return makePairwiseConvertByEditor(target, srcType, strict, monobox); + } else { + return makePairwiseConvertIndirect(target, srcType, strict, monobox); + } + } - // Calculate extra arguments (temporaries) required in the names array. - // FIXME: Use an ArrayList. Some arguments require more than one conversion step. - final int INARG_COUNT = srcType.parameterCount(); - int conversions = 0; - boolean[] needConv = new boolean[1+INARG_COUNT]; - for (int i = 0; i <= INARG_COUNT; i++) { - Class src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i); - Class dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i); - if (!VerifyType.isNullConversion(src, dst) || - level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) { - needConv[i] = true; - conversions++; + private static int countNonNull(Object[] array) { + int count = 0; + for (Object x : array) { + if (x != null) ++count; + } + return count; + } + + static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType, + boolean strict, boolean monobox) { + Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); + int convCount = countNonNull(convSpecs); + if (convCount == 0) + return target.viewAsType(srcType, strict); + MethodType basicSrcType = srcType.basicType(); + MethodType midType = target.type().basicType(); + BoundMethodHandle mh = target.rebind(); + // FIXME: Reduce number of bindings when there is more than one Class conversion. + // FIXME: Reduce number of bindings when there are repeated conversions. + for (int i = 0; i < convSpecs.length-1; i++) { + Object convSpec = convSpecs[i]; + if (convSpec == null) continue; + MethodHandle fn; + if (convSpec instanceof Class) { + fn = Lazy.MH_castReference.bindTo(convSpec); + } else { + fn = (MethodHandle) convSpec; + } + Class newType = basicSrcType.parameterType(i); + if (--convCount == 0) + midType = srcType; + else + midType = midType.changeParameterType(i, newType); + LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType)); + mh = mh.copyWithExtendL(midType, form2, fn); + mh = mh.rebind(); + } + Object convSpec = convSpecs[convSpecs.length-1]; + if (convSpec != null) { + MethodHandle fn; + if (convSpec instanceof Class) { + if (convSpec == void.class) + fn = null; + else + fn = Lazy.MH_castReference.bindTo(convSpec); + } else { + fn = (MethodHandle) convSpec; + } + Class newType = basicSrcType.returnType(); + assert(--convCount == 0); + midType = srcType; + if (fn != null) { + mh = mh.rebind(); // rebind if too complex + LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false); + mh = mh.copyWithExtendL(midType, form2, fn); + } else { + LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true); + mh = mh.copyWith(midType, form2); } } - boolean retConv = needConv[INARG_COUNT]; + assert(convCount == 0); + assert(mh.type().equals(srcType)); + return mh; + } + + static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType, + boolean strict, boolean monobox) { + // Calculate extra arguments (temporaries) required in the names array. + Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); + final int INARG_COUNT = srcType.parameterCount(); + int convCount = countNonNull(convSpecs); + boolean retConv = (convSpecs[INARG_COUNT] != null); + boolean retVoid = srcType.returnType() == void.class; + if (retConv && retVoid) { + convCount -= 1; + retConv = false; + } final int IN_MH = 0; final int INARG_BASE = 1; final int INARG_LIMIT = INARG_BASE + INARG_COUNT; - final int NAME_LIMIT = INARG_LIMIT + conversions + 1; + final int NAME_LIMIT = INARG_LIMIT + convCount + 1; final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1); final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1; + final int RESULT = (retVoid ? -1 : NAME_LIMIT - 1); // Now build a LambdaForm. MethodType lambdaType = srcType.basicType().invokerType(); @@ -204,59 +294,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; int nameCursor = INARG_LIMIT; for (int i = 0; i < INARG_COUNT; i++) { - Class src = srcType.parameterType(i); - Class dst = dstType.parameterType(i); - - if (!needConv[i]) { + Object convSpec = convSpecs[i]; + if (convSpec == null) { // do nothing: difference is trivial outArgs[OUTARG_BASE + i] = names[INARG_BASE + i]; continue; } - // Tricky case analysis follows. - MethodHandle fn = null; - if (src.isPrimitive()) { - if (dst.isPrimitive()) { - fn = ValueConversions.convertPrimitive(src, dst); - } else { - Wrapper w = Wrapper.forPrimitiveType(src); - MethodHandle boxMethod = ValueConversions.box(w); - if (dst == w.wrapperType()) - fn = boxMethod; - else - fn = boxMethod.asType(MethodType.methodType(dst, src)); - } + Name conv; + if (convSpec instanceof Class) { + Class convClass = (Class) convSpec; + conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]); } else { - if (dst.isPrimitive()) { - // Caller has boxed a primitive. Unbox it for the target. - Wrapper w = Wrapper.forPrimitiveType(dst); - if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) { - fn = ValueConversions.unbox(dst); - } else if (src == Object.class || !Wrapper.isWrapperType(src)) { - // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int - // must include additional conversions - // src must be examined at runtime, to detect Byte, Character, etc. - MethodHandle unboxMethod = (level == 1 - ? ValueConversions.unbox(dst) - : ValueConversions.unboxCast(dst)); - fn = unboxMethod; - } else { - // Example: Byte->int - // Do this by reformulating the problem to Byte->byte. - Class srcPrim = Wrapper.forWrapperType(src).primitiveType(); - MethodHandle unbox = ValueConversions.unbox(srcPrim); - // Compose the two conversions. FIXME: should make two Names for this job - fn = unbox.asType(MethodType.methodType(dst, src)); - } - } else { - // Simple reference conversion. - // Note: Do not check for a class hierarchy relation - // between src and dst. In all cases a 'null' argument - // will pass the cast conversion. - fn = ValueConversions.cast(dst, Lazy.MH_castReference); - } + MethodHandle fn = (MethodHandle) convSpec; + conv = new Name(fn, names[INARG_BASE + i]); } - Name conv = new Name(fn, names[INARG_BASE + i]); assert(names[nameCursor] == null); names[nameCursor++] = conv; assert(outArgs[OUTARG_BASE + i] == null); @@ -267,29 +319,29 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; assert(nameCursor == OUT_CALL); names[OUT_CALL] = new Name(target, outArgs); - if (RETURN_CONV < 0) { + Object convSpec = convSpecs[INARG_COUNT]; + if (!retConv) { assert(OUT_CALL == names.length-1); } else { - Class needReturn = srcType.returnType(); - Class haveReturn = dstType.returnType(); - MethodHandle fn; - Object[] arg = { names[OUT_CALL] }; - if (haveReturn == void.class) { - // synthesize a zero value for the given void - Object zero = Wrapper.forBasicType(needReturn).zero(); - fn = MethodHandles.constant(needReturn, zero); - arg = new Object[0]; // don't pass names[OUT_CALL] to conversion + Name conv; + if (convSpec == void.class) { + conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType()))); + } else if (convSpec instanceof Class) { + Class convClass = (Class) convSpec; + conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]); } else { - MethodHandle identity = MethodHandles.identity(needReturn); - MethodType needConversion = identity.type().changeParameterType(0, haveReturn); - fn = makePairwiseConvert(identity, needConversion, level); + MethodHandle fn = (MethodHandle) convSpec; + if (fn.type().parameterCount() == 0) + conv = new Name(fn); // don't pass retval to void conversion + else + conv = new Name(fn, names[OUT_CALL]); } assert(names[RETURN_CONV] == null); - names[RETURN_CONV] = new Name(fn, arg); + names[RETURN_CONV] = conv; assert(RETURN_CONV == names.length-1); } - LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names); + LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT); return SimpleMethodHandle.make(srcType, form); } @@ -312,12 +364,79 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); } - static MethodHandle makeReferenceIdentity(Class refType) { - MethodType lambdaType = MethodType.genericMethodType(1).invokerType(); - Name[] names = arguments(1, lambdaType); - names[names.length - 1] = new Name(ValueConversions.identity(), names[1]); - LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names); - return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form); + static Object[] computeValueConversions(MethodType srcType, MethodType dstType, + boolean strict, boolean monobox) { + final int INARG_COUNT = srcType.parameterCount(); + Object[] convSpecs = new Object[INARG_COUNT+1]; + for (int i = 0; i <= INARG_COUNT; i++) { + boolean isRet = (i == INARG_COUNT); + Class src = isRet ? dstType.returnType() : srcType.parameterType(i); + Class dst = isRet ? srcType.returnType() : dstType.parameterType(i); + if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) { + convSpecs[i] = valueConversion(src, dst, strict, monobox); + } + } + return convSpecs; + } + static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, + boolean strict) { + return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false); + } + + /** + * Find a conversion function from the given source to the given destination. + * This conversion function will be used as a LF NamedFunction. + * Return a Class object if a simple cast is needed. + * Return void.class if void is involved. + */ + static Object valueConversion(Class src, Class dst, boolean strict, boolean monobox) { + assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)); // caller responsibility + if (dst == void.class) + return dst; + MethodHandle fn; + if (src.isPrimitive()) { + if (src == void.class) { + return void.class; // caller must recognize this specially + } else if (dst.isPrimitive()) { + // Examples: int->byte, byte->int, boolean->int (!strict) + fn = ValueConversions.convertPrimitive(src, dst); + } else { + // Examples: int->Integer, boolean->Object, float->Number + Wrapper wsrc = Wrapper.forPrimitiveType(src); + fn = ValueConversions.boxExact(wsrc); + assert(fn.type().parameterType(0) == wsrc.primitiveType()); + assert(fn.type().returnType() == wsrc.wrapperType()); + if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) { + // Corner case, such as int->Long, which will probably fail. + MethodType mt = MethodType.methodType(dst, src); + if (strict) + fn = fn.asType(mt); + else + fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false); + } + } + } else if (dst.isPrimitive()) { + Wrapper wdst = Wrapper.forPrimitiveType(dst); + if (monobox || src == wdst.wrapperType()) { + // Use a strongly-typed unboxer, if possible. + fn = ValueConversions.unboxExact(wdst, strict); + } else { + // Examples: Object->int, Number->int, Comparable->int, Byte->int + // must include additional conversions + // src must be examined at runtime, to detect Byte, Character, etc. + fn = (strict + ? ValueConversions.unboxWiden(wdst) + : ValueConversions.unboxCast(wdst)); + } + } else { + // Simple reference conversion. + // Note: Do not check for a class hierarchy relation + // between src and dst. In all cases a 'null' argument + // will pass the cast conversion. + return dst; + } + assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn); + return fn; } static MethodHandle makeVarargsCollector(MethodHandle target, Class arrayType) { @@ -326,33 +445,45 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; if (type.parameterType(last) != arrayType) target = target.asType(type.changeParameterType(last, arrayType)); target = target.asFixedArity(); // make sure this attribute is turned off - return new AsVarargsCollector(target, target.type(), arrayType); + return new AsVarargsCollector(target, arrayType); } - static class AsVarargsCollector extends MethodHandle { + private static final class AsVarargsCollector extends DelegatingMethodHandle { private final MethodHandle target; private final Class arrayType; - private /*@Stable*/ MethodHandle asCollectorCache; + private @Stable MethodHandle asCollectorCache; - AsVarargsCollector(MethodHandle target, MethodType type, Class arrayType) { - super(type, reinvokerForm(target)); + AsVarargsCollector(MethodHandle target, Class arrayType) { + this(target.type(), target, arrayType); + } + AsVarargsCollector(MethodType type, MethodHandle target, Class arrayType) { + super(type, target); this.target = target; this.arrayType = arrayType; this.asCollectorCache = target.asCollector(arrayType, 0); } - @Override MethodHandle reinvokerTarget() { return target; } - @Override public boolean isVarargsCollector() { return true; } + @Override + protected MethodHandle getTarget() { + return target; + } + @Override public MethodHandle asFixedArity() { return target; } + @Override + MethodHandle setVarargs(MemberName member) { + if (member.isVarargs()) return this; + return asFixedArity(); + } + @Override public MethodHandle asTypeUncached(MethodType newType) { MethodType type = this.type(); @@ -381,54 +512,15 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } @Override - MethodHandle setVarargs(MemberName member) { - if (member.isVarargs()) return this; - return asFixedArity(); - } - - @Override - MethodHandle viewAsType(MethodType newType) { - if (newType.lastParameterType() != type().lastParameterType()) - throw new InternalError(); - MethodHandle newTarget = asFixedArity().viewAsType(newType); - // put back the varargs bit: - return new AsVarargsCollector(newTarget, newType, arrayType); - } - - @Override - MemberName internalMemberName() { - return asFixedArity().internalMemberName(); - } - @Override - Class internalCallerClass() { - return asFixedArity().internalCallerClass(); - } - - /*non-public*/ - @Override - boolean isInvokeSpecial() { - return asFixedArity().isInvokeSpecial(); - } - - - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - return asFixedArity().bindArgument(pos, basicType, value); - } - - @Override - MethodHandle bindReceiver(Object receiver) { - return asFixedArity().bindReceiver(receiver); - } - - @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - return asFixedArity().dropArguments(srcType, pos, drops); - } - - @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - return asFixedArity().permuteArguments(newType, reorder); + boolean viewAsTypeChecks(MethodType newType, boolean strict) { + super.viewAsTypeChecks(newType, true); + if (strict) return true; + // extra assertion for non-strict checks: + assert (type().lastParameterType().getComponentType() + .isAssignableFrom( + newType.lastParameterType().getComponentType())) + : Arrays.asList(this, newType); + return true; } } @@ -499,32 +591,46 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; * Pre-initialized NamedFunctions for bootstrapping purposes. * Factored in an inner class to delay initialization until first usage. */ - private static class Lazy { + static class Lazy { private static final Class MHI = MethodHandleImpl.class; static final NamedFunction NF_checkSpreadArgument; static final NamedFunction NF_guardWithCatch; - static final NamedFunction NF_selectAlternative; static final NamedFunction NF_throwException; static final MethodHandle MH_castReference; + static final MethodHandle MH_selectAlternative; + static final MethodHandle MH_copyAsPrimitiveArray; + static final MethodHandle MH_fillNewTypedArray; + static final MethodHandle MH_fillNewArray; + static final MethodHandle MH_arrayIdentity; static { try { NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, MethodHandle.class, Object[].class)); - NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class, - MethodHandle.class)); NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); NF_checkSpreadArgument.resolve(); NF_guardWithCatch.resolve(); - NF_selectAlternative.resolve(); NF_throwException.resolve(); - MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class); - MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt); + MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", + MethodType.methodType(Object.class, Class.class, Object.class)); + MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray", + MethodType.methodType(Object.class, Wrapper.class, Object[].class)); + MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity", + MethodType.methodType(Object[].class, Object[].class)); + MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray", + MethodType.methodType(Object[].class, Integer.class, Object[].class)); + MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray", + MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); + + MH_selectAlternative = makeIntrinsic( + IMPL_LOOKUP.findStatic(MHI, "selectAlternative", + MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), + Intrinsic.SELECT_ALTERNATIVE); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } @@ -595,29 +701,66 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MethodHandle makeGuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { - MethodType basicType = target.type().basicType(); - MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType); - int arity = basicType.parameterCount(); - int extraNames = 3; - MethodType lambdaType = basicType.invokerType(); - Name[] names = arguments(extraNames, lambdaType); + MethodType type = target.type(); + assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type)); + MethodType basicType = type.basicType(); + LambdaForm form = makeGuardWithTestForm(basicType); + BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); + BoundMethodHandle mh; + try { + mh = (BoundMethodHandle) + data.constructor().invokeBasic(type, form, + (Object) test, (Object) target, (Object) fallback); + } catch (Throwable ex) { + throw uncaughtException(ex); + } + assert(mh.type() == type); + return mh; + } - Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class); - Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class); + static + LambdaForm makeGuardWithTestForm(MethodType basicType) { + LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT); + if (lform != null) return lform; + final int THIS_MH = 0; // the BMH_LLL + final int ARG_BASE = 1; // start of incoming arguments + final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); + int nameCursor = ARG_LIMIT; + final int GET_TEST = nameCursor++; + final int GET_TARGET = nameCursor++; + final int GET_FALLBACK = nameCursor++; + final int CALL_TEST = nameCursor++; + final int SELECT_ALT = nameCursor++; + final int CALL_TARGET = nameCursor++; + assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative + + MethodType lambdaType = basicType.invokerType(); + Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); + + BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); + names[THIS_MH] = names[THIS_MH].withConstraint(data); + names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]); + names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]); + names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]); + + Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class); // call test - names[arity + 1] = new Name(test, testArgs); + MethodType testType = basicType.changeReturnType(boolean.class).basicType(); + invokeArgs[0] = names[GET_TEST]; + names[CALL_TEST] = new Name(testType, invokeArgs); // call selectAlternative - Object[] selectArgs = { names[arity + 1], target, fallback }; - names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs); - targetArgs[0] = names[arity + 2]; + names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST], + names[GET_TARGET], names[GET_FALLBACK]); // call target or fallback - names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); + invokeArgs[0] = names[SELECT_ALT]; + names[CALL_TARGET] = new Name(basicType, invokeArgs); - LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); - return SimpleMethodHandle.make(target.type(), form); + lform = new LambdaForm("guard", lambdaType.parameterCount(), names); + + return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); } /** @@ -665,6 +808,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); + names[THIS_MH] = names[THIS_MH].withConstraint(data); names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); @@ -679,7 +823,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; Object[] args = new Object[invokeBasic.type().parameterCount()]; args[0] = names[GET_COLLECT_ARGS]; System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); - names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args); + names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args); // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; @@ -688,7 +832,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; - names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs); + names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); @@ -705,22 +849,27 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; // Prepare auxiliary method handles used during LambdaForm interpretation. // Box arguments and wrap them into Object[]: ValueConversions.array(). MethodType varargsType = type.changeReturnType(Object[].class); - MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount()) - .asType(varargsType); + MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType); // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). MethodHandle unboxResult; - if (type.returnType().isPrimitive()) { - unboxResult = ValueConversions.unbox(type.returnType()); + Class rtype = type.returnType(); + if (rtype.isPrimitive()) { + if (rtype == void.class) { + unboxResult = ValueConversions.ignore(); + } else { + Wrapper w = Wrapper.forPrimitiveType(type.returnType()); + unboxResult = ValueConversions.unboxExact(w); + } } else { - unboxResult = ValueConversions.identity(); + unboxResult = MethodHandles.identity(Object.class); } BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); BoundMethodHandle mh; try { mh = (BoundMethodHandle) - data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, - (Object) collectArgs, (Object) unboxResult); + data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, + (Object) collectArgs, (Object) unboxResult); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -758,9 +907,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; assert(Throwable.class.isAssignableFrom(type.parameterType(0))); int arity = type.parameterCount(); if (arity > 1) { - return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); + MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); + mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); + return mh; } - return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2); + return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true); } static Empty throwException(T t) throws T { throw t; } @@ -782,7 +933,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); if (!method.getInvocationType().equals(mh.type())) throw new InternalError(method.toString()); - mh = mh.withInternalMemberName(method); + mh = mh.withInternalMemberName(method, false); mh = mh.asVarargsCollector(Object[].class); assert(method.isVarargs()); FAKE_METHOD_HANDLE_INVOKE[idx] = mh; @@ -819,7 +970,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MethodHandle vamh = prepareForInvoker(mh); // Cache the result of makeInjectedInvoker once per argument class. MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); - return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass); + return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass); } private static MethodHandle makeInjectedInvoker(Class hostClass) { @@ -874,12 +1025,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } // Undo the adapter effect of prepareForInvoker: - private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, - MemberName member, + private static MethodHandle restoreToType(MethodHandle vamh, + MethodHandle original, Class hostClass) { + MethodType type = original.type(); MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); + MemberName member = original.internalMemberName(); mh = mh.asType(type); - mh = new WrappedMember(mh, type, member, hostClass); + mh = new WrappedMember(mh, type, member, original.isInvokeSpecial(), hostClass); return mh; } @@ -945,28 +1098,22 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ - static class WrappedMember extends MethodHandle { + private static final class WrappedMember extends DelegatingMethodHandle { private final MethodHandle target; private final MemberName member; private final Class callerClass; + private final boolean isInvokeSpecial; - private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class callerClass) { - super(type, reinvokerForm(target)); + private WrappedMember(MethodHandle target, MethodType type, + MemberName member, boolean isInvokeSpecial, + Class callerClass) { + super(type, target); this.target = target; this.member = member; this.callerClass = callerClass; + this.isInvokeSpecial = isInvokeSpecial; } - @Override - MethodHandle reinvokerTarget() { - return target; - } - @Override - public MethodHandle asTypeUncached(MethodType newType) { - // This MH is an alias for target, except for the MemberName - // Drop the MemberName if there is any conversion. - return asTypeCache = target.asType(newType); - } @Override MemberName internalMemberName() { return member; @@ -977,18 +1124,367 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } @Override boolean isInvokeSpecial() { - return target.isInvokeSpecial(); + return isInvokeSpecial; } @Override - MethodHandle viewAsType(MethodType newType) { - return new WrappedMember(target, newType, member, callerClass); + protected MethodHandle getTarget() { + return target; + } + @Override + public MethodHandle asTypeUncached(MethodType newType) { + // This MH is an alias for target, except for the MemberName + // Drop the MemberName if there is any conversion. + return asTypeCache = target.asType(newType); } } - static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { - if (member.equals(target.internalMemberName())) + static MethodHandle makeWrappedMember(MethodHandle target, MemberName member, boolean isInvokeSpecial) { + if (member.equals(target.internalMemberName()) && isInvokeSpecial == target.isInvokeSpecial()) return target; - return new WrappedMember(target, target.type(), member, null); + return new WrappedMember(target, target.type(), member, isInvokeSpecial, null); } + /** Intrinsic IDs */ + /*non-public*/ + enum Intrinsic { + SELECT_ALTERNATIVE, + GUARD_WITH_CATCH, + NEW_ARRAY, + ARRAY_LOAD, + ARRAY_STORE, + IDENTITY, + ZERO, + NONE // no intrinsic associated + } + + /** Mark arbitrary method handle as intrinsic. + * InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */ + private static final class IntrinsicMethodHandle extends DelegatingMethodHandle { + private final MethodHandle target; + private final Intrinsic intrinsicName; + + IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) { + super(target.type(), target); + this.target = target; + this.intrinsicName = intrinsicName; + } + + @Override + protected MethodHandle getTarget() { + return target; + } + + @Override + Intrinsic intrinsicName() { + return intrinsicName; + } + + @Override + public MethodHandle asTypeUncached(MethodType newType) { + // This MH is an alias for target, except for the intrinsic name + // Drop the name if there is any conversion. + return asTypeCache = target.asType(newType); + } + + @Override + String internalProperties() { + return super.internalProperties() + + "\n& Intrinsic="+intrinsicName; + } + + @Override + public MethodHandle asCollector(Class arrayType, int arrayLength) { + if (intrinsicName == Intrinsic.IDENTITY) { + MethodType resultType = type().asCollectorType(arrayType, arrayLength); + MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength); + return newArray.asType(resultType); + } + return super.asCollector(arrayType, arrayLength); + } + } + + static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) { + if (intrinsicName == target.intrinsicName()) + return target; + return new IntrinsicMethodHandle(target, intrinsicName); + } + + static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) { + return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName); + } + + /// Collection of multiple arguments. + + private static MethodHandle findCollector(String name, int nargs, Class rtype, Class... ptypes) { + MethodType type = MethodType.genericMethodType(nargs) + .changeReturnType(rtype) + .insertParameterTypes(0, ptypes); + try { + return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, name, type); + } catch (ReflectiveOperationException ex) { + return null; + } + } + + private static final Object[] NO_ARGS_ARRAY = {}; + private static Object[] makeArray(Object... args) { return args; } + private static Object[] array() { return NO_ARGS_ARRAY; } + private static Object[] array(Object a0) + { return makeArray(a0); } + private static Object[] array(Object a0, Object a1) + { return makeArray(a0, a1); } + private static Object[] array(Object a0, Object a1, Object a2) + { return makeArray(a0, a1, a2); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3) + { return makeArray(a0, a1, a2, a3); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4) + { return makeArray(a0, a1, a2, a3, a4); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { return makeArray(a0, a1, a2, a3, a4, a5); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { return makeArray(a0, a1, a2, a3, a4, a5, a6); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + private static MethodHandle[] makeArrays() { + ArrayList mhs = new ArrayList<>(); + for (;;) { + MethodHandle mh = findCollector("array", mhs.size(), Object[].class); + if (mh == null) break; + mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); + mhs.add(mh); + } + assert(mhs.size() == 11); // current number of methods + return mhs.toArray(new MethodHandle[MAX_ARITY+1]); + } + private static final MethodHandle[] ARRAYS = makeArrays(); + + // filling versions of the above: + // using Integer len instead of int len and no varargs to avoid bootstrapping problems + private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { + Object[] a = new Object[len]; + fillWithArguments(a, 0, args); + return a; + } + private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { + Object[] a = Arrays.copyOf(example, len); + assert(a.getClass() != Object[].class); + fillWithArguments(a, 0, args); + return a; + } + private static void fillWithArguments(Object[] a, int pos, Object... args) { + System.arraycopy(args, 0, a, pos, args.length); + } + // using Integer pos instead of int pos to avoid bootstrapping problems + private static Object[] fillArray(Integer pos, Object[] a, Object a0) + { fillWithArguments(a, pos, a0); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) + { fillWithArguments(a, pos, a0, a1); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) + { fillWithArguments(a, pos, a0, a1, a2); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) + { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } + private static MethodHandle[] makeFillArrays() { + ArrayList mhs = new ArrayList<>(); + mhs.add(null); // there is no empty fill; at least a0 is required + for (;;) { + MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); + if (mh == null) break; + mhs.add(mh); + } + assert(mhs.size() == 11); // current number of methods + return mhs.toArray(new MethodHandle[0]); + } + private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); + + private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { + Object a = w.makeArray(boxes.length); + w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); + return a; + } + + /** Return a method handle that takes the indicated number of Object + * arguments and returns an Object array of them, as if for varargs. + */ + static MethodHandle varargsArray(int nargs) { + MethodHandle mh = ARRAYS[nargs]; + if (mh != null) return mh; + mh = findCollector("array", nargs, Object[].class); + if (mh != null) mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); + if (mh != null) return ARRAYS[nargs] = mh; + mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs); + assert(assertCorrectArity(mh, nargs)); + mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); + return ARRAYS[nargs] = mh; + } + + private static boolean assertCorrectArity(MethodHandle mh, int arity) { + assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; + return true; + } + + // Array identity function (used as Lazy.MH_arrayIdentity). + static T[] identity(T[] x) { + return x; + } + + private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { + // Build up the result mh as a sequence of fills like this: + // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) + // The various fill(_,10*I,___*[J]) are reusable. + int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately + int rightLen = nargs - leftLen; + MethodHandle leftCollector = newArray.bindTo(nargs); + leftCollector = leftCollector.asCollector(Object[].class, leftLen); + MethodHandle mh = finisher; + if (rightLen > 0) { + MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); + if (mh == Lazy.MH_arrayIdentity) + mh = rightFiller; + else + mh = MethodHandles.collectArguments(mh, 0, rightFiller); + } + if (mh == Lazy.MH_arrayIdentity) + mh = leftCollector; + else + mh = MethodHandles.collectArguments(mh, 0, leftCollector); + return mh; + } + + private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); + private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; + /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) + * fills a[L]..a[N-1] with corresponding arguments, + * and then returns a. The value L is a global constant (LEFT_ARGS). + */ + private static MethodHandle fillToRight(int nargs) { + MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; + if (filler != null) return filler; + filler = buildFiller(nargs); + assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); + return FILL_ARRAY_TO_RIGHT[nargs] = filler; + } + private static MethodHandle buildFiller(int nargs) { + if (nargs <= LEFT_ARGS) + return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged + // we need room for both mh and a in mh.invoke(a, arg*[nargs]) + final int CHUNK = LEFT_ARGS; + int rightLen = nargs % CHUNK; + int midLen = nargs - rightLen; + if (rightLen == 0) { + midLen = nargs - (rightLen = CHUNK); + if (FILL_ARRAY_TO_RIGHT[midLen] == null) { + // build some precursors from left to right + for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) + if (j > LEFT_ARGS) fillToRight(j); + } + } + if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); + assert(rightLen > 0); + MethodHandle midFill = fillToRight(midLen); // recursive fill + MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] + assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); + assert(rightFill.type().parameterCount() == 1 + rightLen); + + // Combine the two fills: + // right(mid(a, x10..x19), x20..x23) + // The final product will look like this: + // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) + if (midLen == LEFT_ARGS) + return rightFill; + else + return MethodHandles.collectArguments(rightFill, 0, midFill); + } + + // Type-polymorphic version of varargs maker. + private static final ClassValue TYPED_COLLECTORS + = new ClassValue() { + @Override + protected MethodHandle[] computeValue(Class type) { + return new MethodHandle[256]; + } + }; + + static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM + + /** Return a method handle that takes the indicated number of + * typed arguments and returns an array of them. + * The type argument is the array type. + */ + static MethodHandle varargsArray(Class arrayType, int nargs) { + Class elemType = arrayType.getComponentType(); + if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); + // FIXME: Need more special casing and caching here. + if (nargs >= MAX_JVM_ARITY/2 - 1) { + int slots = nargs; + final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH + if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive()) + slots *= Wrapper.forPrimitiveType(elemType).stackSlots(); + if (slots > MAX_ARRAY_SLOTS) + throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); + } + if (elemType == Object.class) + return varargsArray(nargs); + // other cases: primitive arrays, subtypes of Object[] + MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); + MethodHandle mh = nargs < cache.length ? cache[nargs] : null; + if (mh != null) return mh; + if (nargs == 0) { + Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0); + mh = MethodHandles.constant(arrayType, example); + } else if (elemType.isPrimitive()) { + MethodHandle builder = Lazy.MH_fillNewArray; + MethodHandle producer = buildArrayProducer(arrayType); + mh = buildVarargsArray(builder, producer, nargs); + } else { + Class objArrayType = arrayType.asSubclass(Object[].class); + Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); + MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example); + MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed + mh = buildVarargsArray(builder, producer, nargs); + } + mh = mh.asType(MethodType.methodType(arrayType, Collections.>nCopies(nargs, elemType))); + mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); + assert(assertCorrectArity(mh, nargs)); + if (nargs < cache.length) + cache[nargs] = mh; + return mh; + } + + private static MethodHandle buildArrayProducer(Class arrayType) { + Class elemType = arrayType.getComponentType(); + assert(elemType.isPrimitive()); + return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType)); + } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index 8fec887447b..1167eeb4a2b 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; +import static java.lang.invoke.MethodHandleStatics.*; /** * This class consists exclusively of static methods that help adapt @@ -148,7 +149,7 @@ public class MethodHandleProxies { public static T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) - throw new IllegalArgumentException("not a public interface: "+intfc.getName()); + throw newIllegalArgumentException("not a public interface", intfc.getName()); final MethodHandle mh; if (System.getSecurityManager() != null) { final Class caller = Reflection.getCallerClass(); @@ -165,7 +166,7 @@ public class MethodHandleProxies { } final Method[] methods = getSingleNameMethods(intfc); if (methods == null) - throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); + throw newIllegalArgumentException("not a single-method interface", intfc.getName()); final MethodHandle[] vaTargets = new MethodHandle[methods.length]; for (int i = 0; i < methods.length; i++) { Method sm = methods[i]; @@ -189,7 +190,7 @@ public class MethodHandleProxies { return getArg(method.getName()); if (isObjectMethod(method)) return callObjectMethod(proxy, method, args); - throw new InternalError("bad proxy method: "+method); + throw newInternalError("bad proxy method: "+method); } }; @@ -240,7 +241,7 @@ public class MethodHandleProxies { return (WrapperInstance) x; } catch (ClassCastException ex) { } - throw new IllegalArgumentException("not a wrapper instance"); + throw newIllegalArgumentException("not a wrapper instance"); } /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java index 50a14b35d52..c3d9ac12c09 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -45,16 +45,21 @@ import sun.misc.Unsafe; static final boolean DUMP_CLASS_FILES; static final boolean TRACE_INTERPRETER; static final boolean TRACE_METHOD_LINKAGE; - static final Integer COMPILE_THRESHOLD; + static final boolean USE_LAMBDA_FORM_EDITOR; + static final int COMPILE_THRESHOLD; + static final int PROFILE_LEVEL; + static { - final Object[] values = { false, false, false, false, null }; + final Object[] values = { false, false, false, false, false, null, null }; AccessController.doPrivileged(new PrivilegedAction() { public Void run() { values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES"); values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER"); values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"); - values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD"); + values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR"); + values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30); + values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); return null; } }); @@ -62,7 +67,9 @@ import sun.misc.Unsafe; DUMP_CLASS_FILES = (Boolean) values[1]; TRACE_INTERPRETER = (Boolean) values[2]; TRACE_METHOD_LINKAGE = (Boolean) values[3]; - COMPILE_THRESHOLD = (Integer) values[4]; + USE_LAMBDA_FORM_EDITOR = (Boolean) values[4]; + COMPILE_THRESHOLD = (Integer) values[5]; + PROFILE_LEVEL = (Integer) values[6]; } /** Tell if any of the debugging switches are turned on. @@ -127,7 +134,10 @@ import sun.misc.Unsafe; /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) { return new IllegalArgumentException(message(message, obj, obj2)); } + /** Propagate unchecked exceptions and errors, but wrap anything checked and throw that instead. */ /*non-public*/ static Error uncaughtException(Throwable ex) { + if (ex instanceof Error) throw (Error) ex; + if (ex instanceof RuntimeException) throw (RuntimeException) ex; throw newInternalError("uncaught exception", ex); } static Error NYI() { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index ee282752032..ea692345d66 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -26,8 +26,8 @@ package java.lang.invoke; import java.lang.reflect.*; +import java.util.BitSet; import java.util.List; -import java.util.ArrayList; import java.util.Arrays; import sun.invoke.util.ValueConversions; @@ -40,6 +40,7 @@ import sun.security.util.SecurityConstants; import java.lang.invoke.LambdaForm.BasicType; import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.MethodHandleStatics.*; +import static java.lang.invoke.MethodHandleImpl.Intrinsic; import static java.lang.invoke.MethodHandleNatives.Constants.*; import java.util.concurrent.ConcurrentHashMap; @@ -862,6 +863,8 @@ assertEquals("", (String) MH_newString.invokeExact()); return invoker(type); if ("invokeExact".equals(name)) return exactInvoker(type); + if ("invokeBasic".equals(name)) + return basicInvoker(type); assert(!MemberName.isMethodHandleInvokeName(name)); return null; } @@ -1141,7 +1144,7 @@ return mh1; Class refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); - return mh.bindReceiver(receiver).setVarargs(method); + return mh.bindArgumentL(0, receiver).setVarargs(method); } /** @@ -1576,7 +1579,7 @@ return mh1; return false; return true; } - private MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class caller) throws IllegalAccessException { + private MethodHandle restrictReceiver(MemberName method, DirectMethodHandle mh, Class caller) throws IllegalAccessException { assert(!method.isStatic()); // receiver type of mh is too wide; narrow to caller if (!method.getDeclaringClass().isAssignableFrom(caller)) { @@ -1585,7 +1588,9 @@ return mh1; MethodType rawType = mh.type(); if (rawType.parameterType(0) == caller) return mh; MethodType narrowType = rawType.changeParameterType(0, caller); - return mh.viewAsType(narrowType); + assert(!mh.isVarargsCollector()); // viewAsType will lose varargs-ness + assert(mh.viewAsTypeChecks(narrowType, true)); + return mh.copyWith(narrowType, mh.form); } /** Check access and get the requested method. */ @@ -1647,15 +1652,17 @@ return mh1; checkMethod(refKind, refc, method); } - MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); - mh = maybeBindCaller(method, mh, callerClass); - mh = mh.setVarargs(method); + DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method); + MethodHandle mh = dmh; // Optionally narrow the receiver argument to refc using restrictReceiver. if (doRestrict && (refKind == REF_invokeSpecial || (MethodHandleNatives.refKindHasReceiver(refKind) && - restrictProtectedReceiver(method)))) - mh = restrictReceiver(method, mh, lookupClass()); + restrictProtectedReceiver(method)))) { + mh = restrictReceiver(method, dmh, lookupClass()); + } + mh = maybeBindCaller(method, mh, callerClass); + mh = mh.setVarargs(method); return mh; } private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, @@ -1687,12 +1694,12 @@ return mh1; // Optionally check with the security manager; this isn't needed for unreflect* calls. if (checkSecurity) checkSecurityManager(refc, field); - MethodHandle mh = DirectMethodHandle.make(refc, field); + DirectMethodHandle dmh = DirectMethodHandle.make(refc, field); boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(field)); if (doRestrict) - mh = restrictReceiver(field, mh, lookupClass()); - return mh; + return restrictReceiver(field, dmh, lookupClass()); + return dmh; } /** Check access and get the requested constructor. */ private MethodHandle getDirectConstructor(Class refc, MemberName ctor) throws IllegalAccessException { @@ -1879,7 +1886,8 @@ return invoker; static public MethodHandle spreadInvoker(MethodType type, int leadingArgCount) { if (leadingArgCount < 0 || leadingArgCount > type.parameterCount()) - throw new IllegalArgumentException("bad argument count "+leadingArgCount); + throw newIllegalArgumentException("bad argument count", leadingArgCount); + type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount); return type.invokers().spreadInvoker(leadingArgCount); } @@ -1959,12 +1967,12 @@ return invoker; */ static public MethodHandle invoker(MethodType type) { - return type.invokers().generalInvoker(); + return type.invokers().genericInvoker(); } static /*non-public*/ MethodHandle basicInvoker(MethodType type) { - return type.form().basicInvoker(); + return type.invokers().basicInvoker(); } /// method handle modification (creation from other method handles) @@ -2015,10 +2023,13 @@ return invoker; */ public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) { - if (!target.type().isCastableTo(newType)) { - throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType); + MethodType oldType = target.type(); + // use the asTypeCache when possible: + if (oldType == newType) return target; + if (oldType.explicitCastEquivalentToAsType(newType)) { + return target.asType(newType); } - return MethodHandleImpl.makePairwiseConvert(target, newType, 2); + return MethodHandleImpl.makePairwiseConvert(target, newType, false); } /** @@ -2082,12 +2093,165 @@ assert((int)twice.invokeExact(21) == 42); */ public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { - reorder = reorder.clone(); - checkReorder(reorder, newType, target.type()); - return target.permuteArguments(newType, reorder); + reorder = reorder.clone(); // get a private copy + MethodType oldType = target.type(); + permuteArgumentChecks(reorder, newType, oldType); + if (USE_LAMBDA_FORM_EDITOR) { + // first detect dropped arguments and handle them separately + int[] originalReorder = reorder; + BoundMethodHandle result = target.rebind(); + LambdaForm form = result.form; + int newArity = newType.parameterCount(); + // Normalize the reordering into a real permutation, + // by removing duplicates and adding dropped elements. + // This somewhat improves lambda form caching, as well + // as simplifying the transform by breaking it up into steps. + for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) { + if (ddIdx > 0) { + // We found a duplicated entry at reorder[ddIdx]. + // Example: (x,y,z)->asList(x,y,z) + // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1) + // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0) + // The starred element corresponds to the argument + // deleted by the dupArgumentForm transform. + int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos]; + boolean killFirst = false; + for (int val; (val = reorder[--dstPos]) != dupVal; ) { + // Set killFirst if the dup is larger than an intervening position. + // This will remove at least one inversion from the permutation. + if (dupVal > val) killFirst = true; + } + if (!killFirst) { + srcPos = dstPos; + dstPos = ddIdx; + } + form = form.editor().dupArgumentForm(1 + srcPos, 1 + dstPos); + assert (reorder[srcPos] == reorder[dstPos]); + oldType = oldType.dropParameterTypes(dstPos, dstPos + 1); + // contract the reordering by removing the element at dstPos + int tailPos = dstPos + 1; + System.arraycopy(reorder, tailPos, reorder, dstPos, reorder.length - tailPos); + reorder = Arrays.copyOf(reorder, reorder.length - 1); + } else { + int dropVal = ~ddIdx, insPos = 0; + while (insPos < reorder.length && reorder[insPos] < dropVal) { + // Find first element of reorder larger than dropVal. + // This is where we will insert the dropVal. + insPos += 1; + } + Class ptype = newType.parameterType(dropVal); + form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype)); + oldType = oldType.insertParameterTypes(insPos, ptype); + // expand the reordering by inserting an element at insPos + int tailPos = insPos + 1; + reorder = Arrays.copyOf(reorder, reorder.length + 1); + System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos); + reorder[insPos] = dropVal; + } + assert (permuteArgumentChecks(reorder, newType, oldType)); + } + assert (reorder.length == newArity); // a perfect permutation + // Note: This may cache too many distinct LFs. Consider backing off to varargs code. + form = form.editor().permuteArgumentsForm(1, reorder); + if (newType == result.type() && form == result.internalForm()) + return result; + return result.copyWith(newType, form); + } else { + // first detect dropped arguments and handle them separately + MethodHandle originalTarget = target; + int newArity = newType.parameterCount(); + for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) { + // dropIdx is missing from reorder; add it in at the end + int oldArity = reorder.length; + target = dropArguments(target, oldArity, newType.parameterType(dropIdx)); + reorder = Arrays.copyOf(reorder, oldArity+1); + reorder[oldArity] = dropIdx; + } + assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type())); + // Note: This may cache too many distinct LFs. Consider backing off to varargs code. + BoundMethodHandle result = target.rebind(); + LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList())); + return result.copyWith(newType, form); + } } - private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) { + /** Return the first value in [0..newArity-1] that is not present in reorder. */ + private static int findFirstDrop(int[] reorder, int newArity) { + final int BIT_LIMIT = 63; // max number of bits in bit mask + if (newArity < BIT_LIMIT) { + long mask = 0; + for (int arg : reorder) { + assert(arg < newArity); + mask |= (1 << arg); + } + if (mask == (1 << newArity) - 1) { + assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); + return -1; + } + // find first zero + long zeroBit = Long.lowestOneBit(~mask); + int zeroPos = Long.numberOfTrailingZeros(zeroBit); + assert(zeroPos < newArity); + return zeroPos; + } + BitSet mask = new BitSet(newArity); + for (int arg : reorder) { + assert(arg < newArity); + mask.set(arg); + } + int zeroPos = mask.nextClearBit(0); + if (zeroPos == newArity) + return -1; + return zeroPos; + } + + /** + * Return an indication of any duplicate or omission in reorder. + * If the reorder contains a duplicate entry, return the index of the second occurrence. + * Otherwise, return ~(n), for the first n in [0..newArity-1] that is not present in reorder. + * Otherwise, return zero. + * If an element not in [0..newArity-1] is encountered, return reorder.length. + */ + private static int findFirstDupOrDrop(int[] reorder, int newArity) { + final int BIT_LIMIT = 63; // max number of bits in bit mask + if (newArity < BIT_LIMIT) { + long mask = 0; + for (int i = 0; i < reorder.length; i++) { + int arg = reorder[i]; + if (arg >= newArity) return reorder.length; + int bit = 1 << arg; + if ((mask & bit) != 0) + return i; // >0 indicates a dup + mask |= bit; + } + if (mask == (1 << newArity) - 1) { + assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); + return 0; + } + // find first zero + long zeroBit = Long.lowestOneBit(~mask); + int zeroPos = Long.numberOfTrailingZeros(zeroBit); + assert(zeroPos < newArity); + return ~zeroPos; + } else { + // same algorithm, different bit set + BitSet mask = new BitSet(newArity); + for (int i = 0; i < reorder.length; i++) { + int arg = reorder[i]; + if (arg >= newArity) return reorder.length; + if (mask.get(arg)) + return i; // >0 indicates a dup + mask.set(arg); + } + int zeroPos = mask.nextClearBit(0); + if (zeroPos == newArity) { + return 0; + } + return ~zeroPos; + } + } + + private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) { if (newType.returnType() != oldType.returnType()) throw newIllegalArgumentException("return types do not match", oldType, newType); @@ -2105,7 +2269,7 @@ assert((int)twice.invokeExact(21) == 42); throw newIllegalArgumentException("parameter types do not match after reorder", oldType, newType); } - if (!bad) return; + if (!bad) return true; } throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder)); } @@ -2131,9 +2295,14 @@ assert((int)twice.invokeExact(21) == 42); if (type == void.class) throw newIllegalArgumentException("void type"); Wrapper w = Wrapper.forPrimitiveType(type); - return insertArguments(identity(type), 0, w.convert(value, type)); + value = w.convert(value, type); + if (w.zero().equals(value)) + return zero(w, type); + return insertArguments(identity(type), 0, value); } else { - return identity(type).bindTo(type.cast(value)); + if (value == null) + return zero(Wrapper.OBJECT, type); + return identity(type).bindTo(value); } } @@ -2146,14 +2315,48 @@ assert((int)twice.invokeExact(21) == 42); */ public static MethodHandle identity(Class type) { - if (type == void.class) - throw newIllegalArgumentException("void type"); - else if (type == Object.class) - return ValueConversions.identity(); - else if (type.isPrimitive()) - return ValueConversions.identity(Wrapper.forPrimitiveType(type)); - else - return MethodHandleImpl.makeReferenceIdentity(type); + Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT); + int pos = btw.ordinal(); + MethodHandle ident = IDENTITY_MHS[pos]; + if (ident == null) { + ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType())); + } + if (ident.type().returnType() == type) + return ident; + // something like identity(Foo.class); do not bother to intern these + assert(btw == Wrapper.OBJECT); + return makeIdentity(type); + } + private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length]; + private static MethodHandle makeIdentity(Class ptype) { + MethodType mtype = MethodType.methodType(ptype, ptype); + LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype)); + return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY); + } + + private static MethodHandle zero(Wrapper btw, Class rtype) { + int pos = btw.ordinal(); + MethodHandle zero = ZERO_MHS[pos]; + if (zero == null) { + zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType())); + } + if (zero.type().returnType() == rtype) + return zero; + assert(btw == Wrapper.OBJECT); + return makeZero(rtype); + } + private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length]; + private static MethodHandle makeZero(Class rtype) { + MethodType mtype = MethodType.methodType(rtype); + LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype)); + return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO); + } + + synchronized private static MethodHandle setCachedMethodHandle(MethodHandle[] cache, int pos, MethodHandle value) { + // Simulate a CAS, to avoid racy duplication of results. + MethodHandle prev = cache[pos]; + if (prev != null) return prev; + return cache[pos] = value; } /** @@ -2189,6 +2392,37 @@ assert((int)twice.invokeExact(21) == 42); public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values) { int insCount = values.length; + Class[] ptypes = insertArgumentsChecks(target, insCount, pos); + if (insCount == 0) return target; + BoundMethodHandle result = target.rebind(); + for (int i = 0; i < insCount; i++) { + Object value = values[i]; + Class ptype = ptypes[pos+i]; + if (ptype.isPrimitive()) { + result = insertArgumentPrimitive(result, pos, ptype, value); + } else { + value = ptype.cast(value); // throw CCE if needed + result = result.bindArgumentL(pos, value); + } + } + return result; + } + + private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos, + Class ptype, Object value) { + Wrapper w = Wrapper.forPrimitiveType(ptype); + // perform unboxing and/or primitive conversion + value = w.convert(value, ptype); + switch (w) { + case INT: return result.bindArgumentI(pos, (int)value); + case LONG: return result.bindArgumentJ(pos, (long)value); + case FLOAT: return result.bindArgumentF(pos, (float)value); + case DOUBLE: return result.bindArgumentD(pos, (double)value); + default: return result.bindArgumentI(pos, ValueConversions.widenSubword(value)); + } + } + + private static Class[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException { MethodType oldType = target.type(); int outargs = oldType.parameterCount(); int inargs = outargs - insCount; @@ -2196,31 +2430,7 @@ assert((int)twice.invokeExact(21) == 42); throw newIllegalArgumentException("too many values to insert"); if (pos < 0 || pos > inargs) throw newIllegalArgumentException("no argument type to append"); - MethodHandle result = target; - for (int i = 0; i < insCount; i++) { - Object value = values[i]; - Class ptype = oldType.parameterType(pos+i); - if (ptype.isPrimitive()) { - BasicType btype = I_TYPE; - Wrapper w = Wrapper.forPrimitiveType(ptype); - switch (w) { - case LONG: btype = J_TYPE; break; - case FLOAT: btype = F_TYPE; break; - case DOUBLE: btype = D_TYPE; break; - } - // perform unboxing and/or primitive conversion - value = w.convert(value, ptype); - result = result.bindArgument(pos, btype, value); - continue; - } - value = ptype.cast(value); // throw CCE if needed - if (pos == 0) { - result = result.bindReceiver(value); - } else { - result = result.bindArgument(pos, L_TYPE, value); - } - } - return result; + return oldType.ptypes(); } /** @@ -2268,18 +2478,33 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); public static MethodHandle dropArguments(MethodHandle target, int pos, List> valueTypes) { MethodType oldType = target.type(); // get NPE + int dropped = dropArgumentChecks(oldType, pos, valueTypes); + if (dropped == 0) return target; + BoundMethodHandle result = target.rebind(); + LambdaForm lform = result.form; + if (USE_LAMBDA_FORM_EDITOR) { + int insertFormArg = 1 + pos; + for (Class ptype : valueTypes) { + lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype)); + } + } else { + lform = lform.addArguments(pos, valueTypes); + } + MethodType newType = oldType.insertParameterTypes(pos, valueTypes); + result = result.copyWith(newType, lform); + return result; + } + + private static int dropArgumentChecks(MethodType oldType, int pos, List> valueTypes) { int dropped = valueTypes.size(); MethodType.checkSlotCount(dropped); - if (dropped == 0) return target; int outargs = oldType.parameterCount(); int inargs = outargs + dropped; - if (pos < 0 || pos >= inargs) - throw newIllegalArgumentException("no argument type to remove"); - ArrayList> ptypes = new ArrayList<>(oldType.parameterList()); - ptypes.addAll(pos, valueTypes); - if (ptypes.size() != inargs) throw newIllegalArgumentException("valueTypes"); - MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); - return target.dropArguments(newType, pos, dropped); + if (pos < 0 || pos > outargs) + throw newIllegalArgumentException("no argument type to remove" + + Arrays.asList(oldType, pos, valueTypes, inargs, outargs) + ); + return dropped; } /** @@ -2401,32 +2626,47 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY */ public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) { - MethodType targetType = target.type(); + filterArgumentsCheckArity(target, pos, filters); MethodHandle adapter = target; - MethodType adapterType = null; - assert((adapterType = targetType) != null); - int maxPos = targetType.parameterCount(); - if (pos + filters.length > maxPos) - throw newIllegalArgumentException("too many filters"); int curPos = pos-1; // pre-incremented for (MethodHandle filter : filters) { curPos += 1; if (filter == null) continue; // ignore null elements of filters adapter = filterArgument(adapter, curPos, filter); - assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null); } - assert(adapterType.equals(adapter.type())); return adapter; } /*non-public*/ static MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { + filterArgumentChecks(target, pos, filter); + if (USE_LAMBDA_FORM_EDITOR) { + MethodType targetType = target.type(); + MethodType filterType = filter.type(); + BoundMethodHandle result = target.rebind(); + Class newParamType = filterType.parameterType(0); + LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType)); + MethodType newType = targetType.changeParameterType(pos, newParamType); + result = result.copyWithExtendL(newType, lform, filter); + return result; + } else { + return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); + } + } + + private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) { + MethodType targetType = target.type(); + int maxPos = targetType.parameterCount(); + if (pos + filters.length > maxPos) + throw newIllegalArgumentException("too many filters"); + } + + private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException { MethodType targetType = target.type(); MethodType filterType = filter.type(); if (filterType.parameterCount() != 1 || filterType.returnType() != targetType.parameterType(pos)) throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); - return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); } /** @@ -2537,12 +2777,36 @@ assertEquals("[top, [[up, down, strange], charm], bottom]", */ public static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) { + MethodType newType = collectArgumentsChecks(target, pos, filter); + if (USE_LAMBDA_FORM_EDITOR) { + MethodType collectorType = filter.type(); + BoundMethodHandle result = target.rebind(); + LambdaForm lform; + if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) { + lform = result.editor().collectArgumentArrayForm(1 + pos, filter); + if (lform != null) { + return result.copyWith(newType, lform); + } + } + lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType()); + return result.copyWithExtendL(newType, lform, filter); + } else { + return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); + } + } + + private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException { MethodType targetType = target.type(); MethodType filterType = filter.type(); - if (filterType.returnType() != void.class && - filterType.returnType() != targetType.parameterType(pos)) + Class rtype = filterType.returnType(); + List> filterArgs = filterType.parameterList(); + if (rtype == void.class) { + return targetType.insertParameterTypes(pos, filterArgs); + } + if (rtype != targetType.parameterType(pos)) { throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); - return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); + } + return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs); } /** @@ -2606,15 +2870,26 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { MethodType targetType = target.type(); MethodType filterType = filter.type(); + filterReturnValueChecks(targetType, filterType); + if (USE_LAMBDA_FORM_EDITOR) { + BoundMethodHandle result = target.rebind(); + BasicType rtype = BasicType.basicType(filterType.returnType()); + LambdaForm lform = result.editor().filterReturnForm(rtype, false); + MethodType newType = targetType.changeReturnType(filterType.returnType()); + result = result.copyWithExtendL(newType, lform, filter); + return result; + } else { + return MethodHandleImpl.makeCollectArguments(filter, target, 0, false); + } + } + + private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException { Class rtype = targetType.returnType(); int filterValues = filterType.parameterCount(); if (filterValues == 0 ? (rtype != void.class) : (rtype != filterType.parameterType(0))) - throw newIllegalArgumentException("target and filter types do not match", target, filter); - // result = fold( lambda(retval, arg...) { filter(retval) }, - // lambda( arg...) { target(arg...) } ) - return MethodHandleImpl.makeCollectArguments(filter, target, 0, false); + throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); } /** @@ -2695,24 +2970,40 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); */ public static MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { - int pos = 0; + int foldPos = 0; MethodType targetType = target.type(); MethodType combinerType = combiner.type(); - int foldPos = pos; - int foldArgs = combinerType.parameterCount(); - int foldVals = combinerType.returnType() == void.class ? 0 : 1; + Class rtype = foldArgumentChecks(foldPos, targetType, combinerType); + if (USE_LAMBDA_FORM_EDITOR) { + BoundMethodHandle result = target.rebind(); + boolean dropResult = (rtype == void.class); + // Note: This may cache too many distinct LFs. Consider backing off to varargs code. + LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType()); + MethodType newType = targetType; + if (!dropResult) + newType = newType.dropParameterTypes(foldPos, foldPos + 1); + result = result.copyWithExtendL(newType, lform, combiner); + return result; + } else { + return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true); + } + } + + private static Class foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) { + int foldArgs = combinerType.parameterCount(); + Class rtype = combinerType.returnType(); + int foldVals = rtype == void.class ? 0 : 1; int afterInsertPos = foldPos + foldVals; boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs); if (ok && !(combinerType.parameterList() .equals(targetType.parameterList().subList(afterInsertPos, afterInsertPos + foldArgs)))) ok = false; - if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0))) + if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0)) ok = false; if (!ok) throw misMatchedTypes("target and combiner types", targetType, combinerType); - MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos); - return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true); + return rtype; } /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java index 2b20ae71935..2762227f5c2 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java @@ -467,6 +467,75 @@ class MethodType implements java.io.Serializable { return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert); } + /** Replace the last arrayLength parameter types with the component type of arrayType. + * @param arrayType any array type + * @param arrayLength the number of parameter types to change + * @return the resulting type + */ + /*non-public*/ MethodType asSpreaderType(Class arrayType, int arrayLength) { + assert(parameterCount() >= arrayLength); + int spreadPos = ptypes.length - arrayLength; + if (arrayLength == 0) return this; // nothing to change + if (arrayType == Object[].class) { + if (isGeneric()) return this; // nothing to change + if (spreadPos == 0) { + // no leading arguments to preserve; go generic + MethodType res = genericMethodType(arrayLength); + if (rtype != Object.class) { + res = res.changeReturnType(rtype); + } + return res; + } + } + Class elemType = arrayType.getComponentType(); + assert(elemType != null); + for (int i = spreadPos; i < ptypes.length; i++) { + if (ptypes[i] != elemType) { + Class[] fixedPtypes = ptypes.clone(); + Arrays.fill(fixedPtypes, i, ptypes.length, elemType); + return methodType(rtype, fixedPtypes); + } + } + return this; // arguments check out; no change + } + + /** Return the leading parameter type, which must exist and be a reference. + * @return the leading parameter type, after error checks + */ + /*non-public*/ Class leadingReferenceParameter() { + Class ptype; + if (ptypes.length == 0 || + (ptype = ptypes[0]).isPrimitive()) + throw newIllegalArgumentException("no leading reference parameter"); + return ptype; + } + + /** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType. + * @param arrayType any array type + * @param arrayLength the number of parameter types to insert + * @return the resulting type + */ + /*non-public*/ MethodType asCollectorType(Class arrayType, int arrayLength) { + assert(parameterCount() >= 1); + assert(lastParameterType().isAssignableFrom(arrayType)); + MethodType res; + if (arrayType == Object[].class) { + res = genericMethodType(arrayLength); + if (rtype != Object.class) { + res = res.changeReturnType(rtype); + } + } else { + Class elemType = arrayType.getComponentType(); + assert(elemType != null); + res = methodType(rtype, Collections.nCopies(arrayLength, elemType)); + } + if (ptypes.length == 1) { + return res; + } else { + return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1)); + } + } + /** * Finds or creates a method type with some parameter types omitted. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. @@ -574,6 +643,10 @@ class MethodType implements java.io.Serializable { return genericMethodType(parameterCount()); } + /*non-public*/ boolean isGeneric() { + return this == erase() && !hasPrimitives(); + } + /** * Converts all primitive types to their corresponding wrapper types. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. @@ -726,44 +799,137 @@ class MethodType implements java.io.Serializable { return sj.toString(); } - + /** True if the old return type can always be viewed (w/o casting) under new return type, + * and the new parameters can be viewed (w/o casting) under the old parameter types. + */ /*non-public*/ - boolean isViewableAs(MethodType newType) { - if (!VerifyType.isNullConversion(returnType(), newType.returnType())) + boolean isViewableAs(MethodType newType, boolean keepInterfaces) { + if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces)) return false; + return parametersAreViewableAs(newType, keepInterfaces); + } + /** True if the new parameters can be viewed (w/o casting) under the old parameter types. */ + /*non-public*/ + boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) { + if (form == newType.form && form.erasedType == this) + return true; // my reference parameters are all Object + if (ptypes == newType.ptypes) + return true; int argc = parameterCount(); if (argc != newType.parameterCount()) return false; for (int i = 0; i < argc; i++) { - if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i))) + if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces)) return false; } return true; } /*non-public*/ - boolean isCastableTo(MethodType newType) { - int argc = parameterCount(); - if (argc != newType.parameterCount()) - return false; - return true; - } - /*non-public*/ boolean isConvertibleTo(MethodType newType) { + MethodTypeForm oldForm = this.form(); + MethodTypeForm newForm = newType.form(); + if (oldForm == newForm) + // same parameter count, same primitive/object mix + return true; if (!canConvert(returnType(), newType.returnType())) return false; - int argc = parameterCount(); - if (argc != newType.parameterCount()) + Class[] srcTypes = newType.ptypes; + Class[] dstTypes = ptypes; + if (srcTypes == dstTypes) + return true; + int argc; + if ((argc = srcTypes.length) != dstTypes.length) return false; - for (int i = 0; i < argc; i++) { - if (!canConvert(newType.parameterType(i), parameterType(i))) + if (argc <= 1) { + if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0])) return false; + return true; + } + if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) || + (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) { + // Somewhat complicated test to avoid a loop of 2 or more trips. + // If either type has only Object parameters, we know we can convert. + assert(canConvertParameters(srcTypes, dstTypes)); + return true; + } + return canConvertParameters(srcTypes, dstTypes); + } + + /** Returns true if MHs.explicitCastArguments produces the same result as MH.asType. + * If the type conversion is impossible for either, the result should be false. + */ + /*non-public*/ + boolean explicitCastEquivalentToAsType(MethodType newType) { + if (this == newType) return true; + if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) { + return false; + } + Class[] srcTypes = newType.ptypes; + Class[] dstTypes = ptypes; + if (dstTypes == srcTypes) { + return true; + } + if (dstTypes.length != srcTypes.length) { + return false; + } + for (int i = 0; i < dstTypes.length; i++) { + if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) { + return false; + } } return true; } + + /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE, + * and with the same effect. + * MHs.eCA has the following "upgrades" to MH.asType: + * 1. interfaces are unchecked (that is, treated as if aliased to Object) + * Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics + * 2. the full matrix of primitive-to-primitive conversions is supported + * Narrowing like {@code long->byte} and basic-typing like {@code boolean->int} + * are not supported by asType, but anything supported by asType is equivalent + * with MHs.eCE. + * 3a. unboxing conversions can be followed by the full matrix of primitive conversions + * 3b. unboxing of null is permitted (creates a zero primitive value) + * Most unboxing conversions, like {@code Object->int}, has potentially + * different behaviors for asType vs. MHs.eCE, because the dynamic value + * might be a wrapper of a type that requires narrowing, like {@code (Object)1L->byte}. + * The equivalence is only certain if the static src type is a wrapper, + * and the conversion will be a widening one. + * Other than interfaces, reference-to-reference conversions are the same. + * Boxing primitives to references is the same for both operators. + */ + private static boolean explicitCastEquivalentToAsType(Class src, Class dst) { + if (src == dst || dst == Object.class || dst == void.class) return true; + if (src.isPrimitive()) { + // Could be a prim/prim conversion, where casting is a strict superset. + // Or a boxing conversion, which is always to an exact wrapper class. + return canConvert(src, dst); + } else if (dst.isPrimitive()) { + Wrapper dw = Wrapper.forPrimitiveType(dst); + // Watch out: If src is Number or Object, we could get dynamic narrowing conversion. + // The conversion is known to be widening only if the wrapper type is statically visible. + return (Wrapper.isWrapperType(src) && + dw.isConvertibleFrom(Wrapper.forWrapperType(src))); + } else { + // R->R always works, but we have to avoid a check-cast to an interface. + return !dst.isInterface() || dst.isAssignableFrom(src); + } + } + + private boolean canConvertParameters(Class[] srcTypes, Class[] dstTypes) { + for (int i = 0; i < srcTypes.length; i++) { + if (!canConvert(srcTypes[i], dstTypes[i])) { + return false; + } + } + return true; + } + /*non-public*/ static boolean canConvert(Class src, Class dst) { // short-circuit a few cases: - if (src == dst || dst == Object.class) return true; + if (src == dst || src == Object.class || dst == Object.class) return true; // the remainder of this logic is documented in MethodHandle.asType if (src.isPrimitive()) { // can force void to an explicit null, a la reflect.Method.invoke @@ -905,7 +1071,7 @@ class MethodType implements java.io.Serializable { if (!descriptor.startsWith("(") || // also generates NPE if needed descriptor.indexOf(')') < 0 || descriptor.indexOf('.') >= 0) - throw new IllegalArgumentException("not a method descriptor: "+descriptor); + throw newIllegalArgumentException("not a method descriptor: "+descriptor); List> types = BytecodeDescriptor.parseMethod(descriptor, loader); Class rtype = types.remove(types.size() - 1); checkSlotCount(types.size()); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java index d34a2998cab..43e85589410 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java @@ -47,15 +47,17 @@ final class MethodTypeForm { final int[] argToSlotTable, slotToArgTable; final long argCounts; // packed slot & value counts final long primCounts; // packed prim & double counts - final int vmslots; // total number of parameter slots final MethodType erasedType; // the canonical erasure final MethodType basicType; // the canonical erasure, with primitives simplified // Cached adapter information: - @Stable String typeString; // argument type signature characters - @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke - @Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic - @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction + @Stable final MethodHandle[] methodHandles; + // Indexes into methodHandles: + static final int + MH_BASIC_INV = 0, // cached instance of MH.invokeBasic + MH_NF_INV = 1, // cached helper for LF.NamedFunction + MH_UNINIT_CS = 2, // uninitialized call site + MH_LIMIT = 3; // Cached lambda form information, for basic types only: final @Stable LambdaForm[] lambdaForms; @@ -68,26 +70,55 @@ final class MethodTypeForm { LF_INVINTERFACE = 4, LF_INVSTATIC_INIT = 5, // DMH invokeStatic with barrier LF_INTERPRET = 6, // LF interpreter - LF_COUNTER = 7, // CMH wrapper - LF_REINVOKE = 8, // other wrapper - LF_EX_LINKER = 9, // invokeExact_MT - LF_EX_INVOKER = 10, // invokeExact MH - LF_GEN_LINKER = 11, - LF_GEN_INVOKER = 12, + LF_REBIND = 7, // BoundMethodHandle + LF_DELEGATE = 8, // DelegatingMethodHandle + LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle) + LF_EX_INVOKER = 10, // MHs.invokeExact + LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle) + LF_GEN_INVOKER = 12, // generic MHs.invoke LF_CS_LINKER = 13, // linkToCallSite_CS LF_MH_LINKER = 14, // linkToCallSite_MH - LF_GWC = 15, - LF_LIMIT = 16; + LF_GWC = 15, // guardWithCatch (catchException) + LF_GWT = 16, // guardWithTest + LF_LIMIT = 17; + /** Return the type corresponding uniquely (1-1) to this MT-form. + * It might have any primitive returns or arguments, but will have no references except Object. + */ public MethodType erasedType() { return erasedType; } + /** Return the basic type derived from the erased type of this MT-form. + * A basic type is erased (all references Object) and also has all primitive + * types (except int, long, float, double, void) normalized to int. + * Such basic types correspond to low-level JVM calling sequences. + */ public MethodType basicType() { return basicType; } + private boolean assertIsBasicType() { + // primitives must be flattened also + assert(erasedType == basicType) + : "erasedType: " + erasedType + " != basicType: " + basicType; + return true; + } + + public MethodHandle cachedMethodHandle(int which) { + assert(assertIsBasicType()); + return methodHandles[which]; + } + + synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) { + // Simulate a CAS, to avoid racy duplication of results. + MethodHandle prev = methodHandles[which]; + if (prev != null) return prev; + return methodHandles[which] = mh; + } + public LambdaForm cachedLambdaForm(int which) { + assert(assertIsBasicType()); return lambdaForms[which]; } @@ -98,28 +129,6 @@ final class MethodTypeForm { return lambdaForms[which] = form; } - public MethodHandle basicInvoker() { - assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also - MethodHandle invoker = basicInvoker; - if (invoker != null) return invoker; - invoker = DirectMethodHandle.make(invokeBasicMethod(basicType)); - basicInvoker = invoker; - return invoker; - } - - // This next one is called from LambdaForm.NamedFunction.. - /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { - assert(basicType == basicType.basicType()); - try { - // Do approximately the same as this public API call: - // Lookup.findVirtual(MethodHandle.class, name, type); - // But bypass access and corner case checks, since we know exactly what we need. - return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); - } catch (ReflectiveOperationException ex) { - throw newInternalError("JVM cannot find invoker for "+basicType, ex); - } - } - /** * Build an MTF for a given type, which must have all references erased to Object. * This MTF will stand for that type and all un-erased variations. @@ -172,6 +181,16 @@ final class MethodTypeForm { this.basicType = erasedType; } else { this.basicType = MethodType.makeImpl(bt, bpts, true); + // fill in rest of data from the basic type: + MethodTypeForm that = this.basicType.form(); + assert(this != that); + this.primCounts = that.primCounts; + this.argCounts = that.argCounts; + this.argToSlotTable = that.argToSlotTable; + this.slotToArgTable = that.slotToArgTable; + this.methodHandles = null; + this.lambdaForms = null; + return; } if (lac != 0) { int slot = ptypeCount + lac; @@ -187,10 +206,14 @@ final class MethodTypeForm { argToSlotTab[1+i] = slot; } assert(slot == 0); // filled the table - } - this.primCounts = pack(lrc, prc, lac, pac); - this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); - if (slotToArgTab == null) { + } else if (pac != 0) { + // have primitives but no long primitives; share slot counts with generic + assert(ptypeCount == pslotCount); + MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form(); + assert(this != that); + slotToArgTab = that.slotToArgTable; + argToSlotTab = that.argToSlotTable; + } else { int slot = ptypeCount; // first arg is deepest in stack slotToArgTab = new int[slot+1]; argToSlotTab = new int[1+ptypeCount]; @@ -201,19 +224,17 @@ final class MethodTypeForm { argToSlotTab[1+i] = slot; } } + this.primCounts = pack(lrc, prc, lac, pac); + this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); this.argToSlotTable = argToSlotTab; this.slotToArgTable = slotToArgTab; if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); - // send a few bits down to the JVM: - this.vmslots = parameterSlotCount(); - - if (basicType == erasedType) { - lambdaForms = new LambdaForm[LF_LIMIT]; - } else { - lambdaForms = null; // could be basicType.form().lambdaForms; - } + // Initialize caches, but only for basic types + assert(basicType == erasedType); + this.lambdaForms = new LambdaForm[LF_LIMIT]; + this.methodHandles = new MethodHandle[MH_LIMIT]; } private static long pack(int a, int b, int c, int d) { @@ -300,7 +321,7 @@ final class MethodTypeForm { */ public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { Class[] ptypes = mt.ptypes(); - Class[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs); + Class[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs); Class rtype = mt.returnType(); Class rtc = MethodTypeForm.canonicalize(rtype, howRet); if (ptc == null && rtc == null) { @@ -368,7 +389,7 @@ final class MethodTypeForm { /** Canonicalize each param type in the given array. * Return null if all types are already canonicalized. */ - static Class[] canonicalizes(Class[] ts, int how) { + static Class[] canonicalizeAll(Class[] ts, int how) { Class[] cs = null; for (int imax = ts.length, i = 0; i < imax; i++) { Class c = canonicalize(ts[i], how); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java index 752505ee68e..c9e37a81ff4 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java @@ -25,38 +25,77 @@ package java.lang.invoke; -import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.BasicType.*; +import static java.lang.invoke.MethodHandleStatics.*; /** * A method handle whose behavior is determined only by its LambdaForm. * @author jrose */ -final class SimpleMethodHandle extends MethodHandle { +final class SimpleMethodHandle extends BoundMethodHandle { private SimpleMethodHandle(MethodType type, LambdaForm form) { super(type, form); } - /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) { + /*non-public*/ static BoundMethodHandle make(MethodType type, LambdaForm form) { return new SimpleMethodHandle(type, form); } - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - MethodType type2 = type().dropParameterTypes(pos, pos+1); - LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY); - return BoundMethodHandle.bindSingle(type2, form2, basicType, value); + /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY; + + /*non-public*/ public SpeciesData speciesData() { + return SPECIES_DATA; } @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - LambdaForm newForm = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops)); - return new SimpleMethodHandle(srcType, newForm); + /*non-public*/ BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) { + return make(mt, lf); } @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList())); - return new SimpleMethodHandle(newType, form2); + String internalProperties() { + return "\n& Class="+getClass().getSimpleName(); + } + + @Override + /*non-public*/ public int fieldCount() { + return 0; + } + + @Override + /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { + return BoundMethodHandle.bindSingle(mt, lf, narg); // Use known fast path. + } + @Override + /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { + try { + return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, narg); + } catch (Throwable ex) { + throw uncaughtException(ex); + } + } + @Override + /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { + try { + return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, narg); + } catch (Throwable ex) { + throw uncaughtException(ex); + } + } + @Override + /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { + try { + return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, narg); + } catch (Throwable ex) { + throw uncaughtException(ex); + } + } + @Override + /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { + try { + return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, narg); + } catch (Throwable ex) { + throw uncaughtException(ex); + } } } diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java index 4b112bf16b3..b86e1a4eae0 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -94,8 +94,19 @@ public final class Constructor extends Executable { // For sharing of ConstructorAccessors. This branching structure // is currently only two levels deep (i.e., one root Constructor // and potentially many Constructor objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Constructor root; + /** + * Used by Excecutable for annotation sharing. + */ + @Override + Executable getRoot() { + return root; + } + /** * Package-private constructor used by ReflectAccess to enable * instantiation of these objects in Java code from the java.lang @@ -132,6 +143,9 @@ public final class Constructor extends Executable { // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Constructor"); + Constructor res = new Constructor<>(clazz, parameterTypes, exceptionTypes, modifiers, slot, diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java index 99eb1eb8b90..15c6574d078 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java @@ -52,6 +52,11 @@ public abstract class Executable extends AccessibleObject */ abstract byte[] getAnnotationBytes(); + /** + * Accessor method to allow code sharing + */ + abstract Executable getRoot(); + /** * Does the Executable have generic information. */ @@ -540,11 +545,16 @@ public abstract class Executable extends AccessibleObject private synchronized Map, Annotation> declaredAnnotations() { if (declaredAnnotations == null) { - declaredAnnotations = AnnotationParser.parseAnnotations( - getAnnotationBytes(), - sun.misc.SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - getDeclaringClass()); + Executable root = getRoot(); + if (root != null) { + declaredAnnotations = root.declaredAnnotations(); + } else { + declaredAnnotations = AnnotationParser.parseAnnotations( + getAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + getDeclaringClass()); + } } return declaredAnnotations; } diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java index 6e243bc82b6..bb23b22dc94 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java @@ -81,6 +81,9 @@ class Field extends AccessibleObject implements Member { // For sharing of FieldAccessors. This branching structure is // currently only two levels deep (i.e., one root Field and // potentially many Field objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Field root; // Generics infrastructure @@ -141,6 +144,9 @@ class Field extends AccessibleObject implements Member { // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Field"); + Field res = new Field(clazz, name, type, modifiers, slot, signature, annotations); res.root = this; // Might as well eagerly propagate this if already present @@ -1137,10 +1143,15 @@ class Field extends AccessibleObject implements Member { private synchronized Map, Annotation> declaredAnnotations() { if (declaredAnnotations == null) { - declaredAnnotations = AnnotationParser.parseAnnotations( - annotations, sun.misc.SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - getDeclaringClass()); + Field root = this.root; + if (root != null) { + declaredAnnotations = root.declaredAnnotations(); + } else { + declaredAnnotations = AnnotationParser.parseAnnotations( + annotations, + sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(getDeclaringClass()), + getDeclaringClass()); + } } return declaredAnnotations; } diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java index 6c58138ee52..ddf0f3888ab 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java @@ -79,6 +79,9 @@ public final class Method extends Executable { // For sharing of MethodAccessors. This branching structure is // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Method root; // Generics infrastructure @@ -144,6 +147,9 @@ public final class Method extends Executable { // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Method"); + Method res = new Method(clazz, name, parameterTypes, returnType, exceptionTypes, modifiers, slot, signature, annotations, parameterAnnotations, annotationDefault); @@ -153,6 +159,14 @@ public final class Method extends Executable { return res; } + /** + * Used by Excecutable for annotation sharing. + */ + @Override + Executable getRoot() { + return root; + } + @Override boolean hasGenericInformation() { return (getGenericSignature() != null); diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index 6f4691404c3..7bb5fc54a9e 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -354,10 +354,11 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * @exception NullPointerException if {@code name} is {@code null}. */ protected Class findClass(final String name) - throws ClassNotFoundException + throws ClassNotFoundException { + final Class result; try { - return AccessController.doPrivileged( + result = AccessController.doPrivileged( new PrivilegedExceptionAction>() { public Class run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); @@ -369,13 +370,17 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { throw new ClassNotFoundException(name, e); } } else { - throw new ClassNotFoundException(name); + return null; } } }, acc); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } + if (result == null) { + throw new ClassNotFoundException(name); + } + return result; } /* diff --git a/jdk/src/java.base/share/classes/java/time/Duration.java b/jdk/src/java.base/share/classes/java/time/Duration.java index 30d146dbf64..d5a49956e90 100644 --- a/jdk/src/java.base/share/classes/java/time/Duration.java +++ b/jdk/src/java.base/share/classes/java/time/Duration.java @@ -424,7 +424,7 @@ public final class Duration return 0; } try { - long val = Long.parseLong(text, 10, start, end); + long val = Long.parseLong(text, start, end, 10); return Math.multiplyExact(val, multiplier); } catch (NumberFormatException | ArithmeticException ex) { throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); @@ -437,7 +437,7 @@ public final class Duration return 0; } try { - int fraction = Integer.parseInt(text, 10, start, end); + int fraction = Integer.parseInt(text, start, end, 10); // for number strings smaller than 9 digits, interpret as if there // were trailing zeros diff --git a/jdk/src/java.base/share/classes/java/time/Period.java b/jdk/src/java.base/share/classes/java/time/Period.java index 88adb958fa0..c7c04435262 100644 --- a/jdk/src/java.base/share/classes/java/time/Period.java +++ b/jdk/src/java.base/share/classes/java/time/Period.java @@ -358,7 +358,7 @@ public final class Period if (start < 0 || end < 0) { return 0; } - int val = Integer.parseInt(text, 10, start, end); + int val = Integer.parseInt(text, start, end, 10); try { return Math.multiplyExact(val, negate); } catch (ArithmeticException ex) { diff --git a/jdk/src/java.base/share/classes/java/util/Arrays.java b/jdk/src/java.base/share/classes/java/util/Arrays.java index b7b75794ce4..628ce831ab6 100644 --- a/jdk/src/java.base/share/classes/java/util/Arrays.java +++ b/jdk/src/java.base/share/classes/java/util/Arrays.java @@ -3865,7 +3865,7 @@ public class Arrays { @Override public boolean contains(Object o) { - return indexOf(o) != -1; + return indexOf(o) >= 0; } @Override diff --git a/jdk/src/java.base/share/classes/java/util/LinkedList.java b/jdk/src/java.base/share/classes/java/util/LinkedList.java index 18a8b21ba80..343ded84d07 100644 --- a/jdk/src/java.base/share/classes/java/util/LinkedList.java +++ b/jdk/src/java.base/share/classes/java/util/LinkedList.java @@ -314,7 +314,7 @@ public class LinkedList * @return {@code true} if this list contains the specified element */ public boolean contains(Object o) { - return indexOf(o) != -1; + return indexOf(o) >= 0; } /** diff --git a/jdk/src/java.base/share/classes/java/util/PriorityQueue.java b/jdk/src/java.base/share/classes/java/util/PriorityQueue.java index b0fb9816be0..cc1af05aa36 100644 --- a/jdk/src/java.base/share/classes/java/util/PriorityQueue.java +++ b/jdk/src/java.base/share/classes/java/util/PriorityQueue.java @@ -406,7 +406,7 @@ public class PriorityQueue extends AbstractQueue * @return {@code true} if this queue contains the specified element */ public boolean contains(Object o) { - return indexOf(o) != -1; + return indexOf(o) >= 0; } /** diff --git a/jdk/src/java.base/share/classes/java/util/UUID.java b/jdk/src/java.base/share/classes/java/util/UUID.java index 11e024678e0..39e507df40c 100644 --- a/jdk/src/java.base/share/classes/java/util/UUID.java +++ b/jdk/src/java.base/share/classes/java/util/UUID.java @@ -194,7 +194,8 @@ public final class UUID implements java.io.Serializable, Comparable { * */ public static UUID fromString(String name) { - if (name.length() > 36) { + int len = name.length(); + if (len > 36) { throw new IllegalArgumentException("UUID string too large"); } @@ -214,15 +215,14 @@ public final class UUID implements java.io.Serializable, Comparable { throw new IllegalArgumentException("Invalid UUID string: " + name); } - long mostSigBits = Long.parseLong(name, 16, 0, dash1) & 0xffffffffL; + long mostSigBits = Long.parseLong(name, 0, dash1, 16) & 0xffffffffL; mostSigBits <<= 16; - mostSigBits |= Long.parseLong(name, 16, dash1 + 1, dash2) & 0xffffL; + mostSigBits |= Long.parseLong(name, dash1 + 1, dash2, 16) & 0xffffL; mostSigBits <<= 16; - mostSigBits |= Long.parseLong(name, 16, dash2 + 1, dash3) & 0xffffL; - - long leastSigBits = Long.parseLong(name, 16, dash3 + 1, dash4) & 0xffffL; + mostSigBits |= Long.parseLong(name, dash2 + 1, dash3, 16) & 0xffffL; + long leastSigBits = Long.parseLong(name, dash3 + 1, dash4, 16) & 0xffffL; leastSigBits <<= 48; - leastSigBits |= Long.parseLong(name, 16, dash4 + 1) & 0xffffffffffffL; + leastSigBits |= Long.parseLong(name, dash4 + 1, len, 16) & 0xffffffffffffL; return new UUID(mostSigBits, leastSigBits); } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 9f5e14914d0..c3ebf04d343 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -49,6 +49,7 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RunnableFuture; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.security.AccessControlContext; import java.security.ProtectionDomain; import java.security.Permissions; @@ -80,9 +81,9 @@ import java.security.Permissions; * *

For applications that require separate or custom pools, a {@code * ForkJoinPool} may be constructed with a given target parallelism - * level; by default, equal to the number of available processors. The - * pool attempts to maintain enough active (or available) threads by - * dynamically adding, suspending, or resuming internal worker + * level; by default, equal to the number of available processors. + * The pool attempts to maintain enough active (or available) threads + * by dynamically adding, suspending, or resuming internal worker * threads, even if some tasks are stalled waiting to join others. * However, no such adjustments are guaranteed in the face of blocked * I/O or other unmanaged synchronization. The nested {@link @@ -142,6 +143,9 @@ import java.security.Permissions; * - the class name of a {@link ForkJoinWorkerThreadFactory} *

  • {@code java.util.concurrent.ForkJoinPool.common.exceptionHandler} * - the class name of a {@link UncaughtExceptionHandler} + *
  • {@code java.util.concurrent.ForkJoinPool.common.maximumSpares} + * - the maximum number of allowed extra threads to maintain target + * parallelism (default 256). * * If a {@link SecurityManager} is present and no factory is * specified, then the default pool uses a factory supplying @@ -178,7 +182,14 @@ public class ForkJoinPool extends AbstractExecutorService { * that may be stolen by other workers. Preference rules give * first priority to processing tasks from their own queues (LIFO * or FIFO, depending on mode), then to randomized FIFO steals of - * tasks in other queues. + * tasks in other queues. This framework began as vehicle for + * supporting tree-structured parallelism using work-stealing. + * Over time, its scalability advantages led to extensions and + * changes to better support more diverse usage contexts. Because + * most internal methods and nested classes are interrelated, + * their main rationale and descriptions are presented here; + * individual methods and nested classes contain only brief + * comments about details. * * WorkQueues * ========== @@ -198,201 +209,318 @@ public class ForkJoinPool extends AbstractExecutorService { * (http://research.sun.com/scalable/pubs/index.html) and * "Idempotent work stealing" by Michael, Saraswat, and Vechev, * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186). - * See also "Correct and Efficient Work-Stealing for Weak Memory - * Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013 - * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an - * analysis of memory ordering (atomic, volatile etc) issues. The - * main differences ultimately stem from GC requirements that we - * null out taken slots as soon as we can, to maintain as small a - * footprint as possible even in programs generating huge numbers - * of tasks. To accomplish this, we shift the CAS arbitrating pop - * vs poll (steal) from being on the indices ("base" and "top") to - * the slots themselves. So, both a successful pop and poll - * mainly entail a CAS of a slot from non-null to null. Because - * we rely on CASes of references, we do not need tag bits on base - * or top. They are simple ints as used in any circular + * The main differences ultimately stem from GC requirements that + * we null out taken slots as soon as we can, to maintain as small + * a footprint as possible even in programs generating huge + * numbers of tasks. To accomplish this, we shift the CAS + * arbitrating pop vs poll (steal) from being on the indices + * ("base" and "top") to the slots themselves. + * + * Adding tasks then takes the form of a classic array push(task): + * q.array[q.top] = task; ++q.top; + * + * (The actual code needs to null-check and size-check the array, + * properly fence the accesses, and possibly signal waiting + * workers to start scanning -- see below.) Both a successful pop + * and poll mainly entail a CAS of a slot from non-null to null. + * + * The pop operation (always performed by owner) is: + * if ((base != top) and + * (the task at top slot is not null) and + * (CAS slot to null)) + * decrement top and return task; + * + * And the poll operation (usually by a stealer) is + * if ((base != top) and + * (the task at base slot is not null) and + * (base has not changed) and + * (CAS slot to null)) + * increment base and return task; + * + * Because we rely on CASes of references, we do not need tag bits + * on base or top. They are simple ints as used in any circular * array-based queue (see for example ArrayDeque). Updates to the - * indices must still be ordered in a way that guarantees that top - * == base means the queue is empty, but otherwise may err on the - * side of possibly making the queue appear nonempty when a push, - * pop, or poll have not fully committed. Note that this means - * that the poll operation, considered individually, is not - * wait-free. One thief cannot successfully continue until another - * in-progress one (or, if previously empty, a push) completes. - * However, in the aggregate, we ensure at least probabilistic + * indices guarantee that top == base means the queue is empty, + * but otherwise may err on the side of possibly making the queue + * appear nonempty when a push, pop, or poll have not fully + * committed. (Method isEmpty() checks the case of a partially + * completed removal of the last element.) Because of this, the + * poll operation, considered individually, is not wait-free. One + * thief cannot successfully continue until another in-progress + * one (or, if previously empty, a push) completes. However, in + * the aggregate, we ensure at least probabilistic * non-blockingness. If an attempted steal fails, a thief always * chooses a different random victim target to try next. So, in * order for one thief to progress, it suffices for any * in-progress poll or new push on any empty queue to * complete. (This is why we normally use method pollAt and its * variants that try once at the apparent base index, else - * consider alternative actions, rather than method poll.) + * consider alternative actions, rather than method poll, which + * retries.) * - * This approach also enables support of a user mode in which local - * task processing is in FIFO, not LIFO order, simply by using - * poll rather than pop. This can be useful in message-passing - * frameworks in which tasks are never joined. However neither - * mode considers affinities, loads, cache localities, etc, so - * rarely provide the best possible performance on a given - * machine, but portably provide good throughput by averaging over - * these factors. (Further, even if we did try to use such - * information, we do not usually have a basis for exploiting it. - * For example, some sets of tasks profit from cache affinities, - * but others are harmed by cache pollution effects.) + * This approach also enables support of a user mode in which + * local task processing is in FIFO, not LIFO order, simply by + * using poll rather than pop. This can be useful in + * message-passing frameworks in which tasks are never joined. + * However neither mode considers affinities, loads, cache + * localities, etc, so rarely provide the best possible + * performance on a given machine, but portably provide good + * throughput by averaging over these factors. Further, even if + * we did try to use such information, we do not usually have a + * basis for exploiting it. For example, some sets of tasks + * profit from cache affinities, but others are harmed by cache + * pollution effects. Additionally, even though it requires + * scanning, long-term throughput is often best using random + * selection rather than directed selection policies, so cheap + * randomization of sufficient quality is used whenever + * applicable. Various Marsaglia XorShifts (some with different + * shift constants) are inlined at use points. * * WorkQueues are also used in a similar way for tasks submitted * to the pool. We cannot mix these tasks in the same queues used - * for work-stealing (this would contaminate lifo/fifo - * processing). Instead, we randomly associate submission queues + * by workers. Instead, we randomly associate submission queues * with submitting threads, using a form of hashing. The * ThreadLocalRandom probe value serves as a hash code for * choosing existing queues, and may be randomly repositioned upon * contention with other submitters. In essence, submitters act * like workers except that they are restricted to executing local * tasks that they submitted (or in the case of CountedCompleters, - * others with the same root task). However, because most - * shared/external queue operations are more expensive than - * internal, and because, at steady state, external submitters - * will compete for CPU with workers, ForkJoinTask.join and - * related methods disable them from repeatedly helping to process - * tasks if all workers are active. Insertion of tasks in shared + * others with the same root task). Insertion of tasks in shared * mode requires a lock (mainly to protect in the case of - * resizing) but we use only a simple spinlock (using bits in - * field qlock), because submitters encountering a busy queue move - * on to try or create other queues -- they block only when - * creating and registering new queues. + * resizing) but we use only a simple spinlock (using field + * qlock), because submitters encountering a busy queue move on to + * try or create other queues -- they block only when creating and + * registering new queues. Additionally, "qlock" saturates to an + * unlockable value (-1) at shutdown. Unlocking still can be and + * is performed by cheaper ordered writes of "qlock" in successful + * cases, but uses CAS in unsuccessful cases. * * Management * ========== * * The main throughput advantages of work-stealing stem from * decentralized control -- workers mostly take tasks from - * themselves or each other. We cannot negate this in the - * implementation of other management responsibilities. The main - * tactic for avoiding bottlenecks is packing nearly all - * essentially atomic control state into two volatile variables - * that are by far most often read (not written) as status and - * consistency checks. + * themselves or each other, at rates that can exceed a billion + * per second. The pool itself creates, activates (enables + * scanning for and running tasks), deactivates, blocks, and + * terminates threads, all with minimal central information. + * There are only a few properties that we can globally track or + * maintain, so we pack them into a small number of variables, + * often maintaining atomicity without blocking or locking. + * Nearly all essentially atomic control state is held in two + * volatile variables that are by far most often read (not + * written) as status and consistency checks. (Also, field + * "config" holds unchanging configuration state.) * - * Field "ctl" contains 64 bits holding all the information needed - * to atomically decide to add, inactivate, enqueue (on an event + * Field "ctl" contains 64 bits holding information needed to + * atomically decide to add, inactivate, enqueue (on an event * queue), dequeue, and/or re-activate workers. To enable this * packing, we restrict maximum parallelism to (1<<15)-1 (which is * far in excess of normal operating range) to allow ids, counts, * and their negations (used for thresholding) to fit into 16bit - * fields. + * subfields. * - * Field "plock" is a form of sequence lock with a saturating - * shutdown bit (similarly for per-queue "qlocks"), mainly - * protecting updates to the workQueues array, as well as to - * enable shutdown. When used as a lock, it is normally only very - * briefly held, so is nearly always available after at most a - * brief spin, but we use a monitor-based backup strategy to - * block when needed. + * Field "runState" holds lockable state bits (STARTED, STOP, etc) + * also protecting updates to the workQueues array. When used as + * a lock, it is normally held only for a few instructions (the + * only exceptions are one-time array initialization and uncommon + * resizing), so is nearly always available after at most a brief + * spin. But to be extra-cautious, after spinning, method + * awaitRunStateLock (called only if an initial CAS fails), uses a + * wait/notify mechanics on a builtin monitor to block when + * (rarely) needed. This would be a terrible idea for a highly + * contended lock, but most pools run without the lock ever + * contending after the spin limit, so this works fine as a more + * conservative alternative. Because we don't otherwise have an + * internal Object to use as a monitor, the "stealCounter" (an + * AtomicLong) is used when available (it too must be lazily + * initialized; see externalSubmit). + * + * Usages of "runState" vs "ctl" interact in only one case: + * deciding to add a worker thread (see tryAddWorker), in which + * case the ctl CAS is performed while the lock is held. * * Recording WorkQueues. WorkQueues are recorded in the - * "workQueues" array that is created upon first use and expanded - * if necessary. Updates to the array while recording new workers - * and unrecording terminated ones are protected from each other - * by a lock but the array is otherwise concurrently readable, and - * accessed directly. To simplify index-based operations, the - * array size is always a power of two, and all readers must - * tolerate null slots. Worker queues are at odd indices. Shared - * (submission) queues are at even indices, up to a maximum of 64 - * slots, to limit growth even if array needs to expand to add - * more workers. Grouping them together in this way simplifies and - * speeds up task scanning. + * "workQueues" array. The array is created upon first use (see + * externalSubmit) and expanded if necessary. Updates to the + * array while recording new workers and unrecording terminated + * ones are protected from each other by the runState lock, but + * the array is otherwise concurrently readable, and accessed + * directly. We also ensure that reads of the array reference + * itself never become too stale. To simplify index-based + * operations, the array size is always a power of two, and all + * readers must tolerate null slots. Worker queues are at odd + * indices. Shared (submission) queues are at even indices, up to + * a maximum of 64 slots, to limit growth even if array needs to + * expand to add more workers. Grouping them together in this way + * simplifies and speeds up task scanning. * * All worker thread creation is on-demand, triggered by task * submissions, replacement of terminated workers, and/or * compensation for blocked workers. However, all other support * code is set up to work with other policies. To ensure that we - * do not hold on to worker references that would prevent GC, ALL + * do not hold on to worker references that would prevent GC, All * accesses to workQueues are via indices into the workQueues * array (which is one source of some of the messy code * constructions here). In essence, the workQueues array serves as - * a weak reference mechanism. Thus for example the wait queue - * field of ctl stores indices, not references. Access to the - * workQueues in associated methods (for example signalWork) must - * both index-check and null-check the IDs. All such accesses - * ignore bad IDs by returning out early from what they are doing, - * since this can only be associated with termination, in which - * case it is OK to give up. All uses of the workQueues array - * also check that it is non-null (even if previously - * non-null). This allows nulling during termination, which is - * currently not necessary, but remains an option for - * resource-revocation-based shutdown schemes. It also helps - * reduce JIT issuance of uncommon-trap code, which tends to - * unnecessarily complicate control flow in some methods. + * a weak reference mechanism. Thus for example the stack top + * subfield of ctl stores indices, not references. * - * Event Queuing. Unlike HPC work-stealing frameworks, we cannot - * let workers spin indefinitely scanning for tasks when none can - * be found immediately, and we cannot start/resume workers unless - * there appear to be tasks available. On the other hand, we must - * quickly prod them into action when new tasks are submitted or - * generated. In many usages, ramp-up time to activate workers is - * the main limiting factor in overall performance (this is - * compounded at program start-up by JIT compilation and - * allocation). So we try to streamline this as much as possible. - * We park/unpark workers after placing in an event wait queue - * when they cannot find work. This "queue" is actually a simple - * Treiber stack, headed by the "id" field of ctl, plus a 15bit - * counter value (that reflects the number of times a worker has - * been inactivated) to avoid ABA effects (we need only as many - * version numbers as worker threads). Successors are held in - * field WorkQueue.nextWait. Queuing deals with several intrinsic - * races, mainly that a task-producing thread can miss seeing (and - * signalling) another thread that gave up looking for work but - * has not yet entered the wait queue. We solve this by requiring - * a full sweep of all workers (via repeated calls to method - * scan()) both before and after a newly waiting worker is added - * to the wait queue. Because enqueued workers may actually be - * rescanning rather than waiting, we set and clear the "parker" + * Queuing Idle Workers. Unlike HPC work-stealing frameworks, we + * cannot let workers spin indefinitely scanning for tasks when + * none can be found immediately, and we cannot start/resume + * workers unless there appear to be tasks available. On the + * other hand, we must quickly prod them into action when new + * tasks are submitted or generated. In many usages, ramp-up time + * to activate workers is the main limiting factor in overall + * performance, which is compounded at program start-up by JIT + * compilation and allocation. So we streamline this as much as + * possible. + * + * The "ctl" field atomically maintains active and total worker + * counts as well as a queue to place waiting threads so they can + * be located for signalling. Active counts also play the role of + * quiescence indicators, so are decremented when workers believe + * that there are no more tasks to execute. The "queue" is + * actually a form of Treiber stack. A stack is ideal for + * activating threads in most-recently used order. This improves + * performance and locality, outweighing the disadvantages of + * being prone to contention and inability to release a worker + * unless it is topmost on stack. We park/unpark workers after + * pushing on the idle worker stack (represented by the lower + * 32bit subfield of ctl) when they cannot find work. The top + * stack state holds the value of the "scanState" field of the + * worker: its index and status, plus a version counter that, in + * addition to the count subfields (also serving as version + * stamps) provide protection against Treiber stack ABA effects. + * + * Field scanState is used by both workers and the pool to manage + * and track whether a worker is INACTIVE (possibly blocked + * waiting for a signal), or SCANNING for tasks (when neither hold + * it is busy running tasks). When a worker is inactivated, its + * scanState field is set, and is prevented from executing tasks, + * even though it must scan once for them to avoid queuing + * races. Note that scanState updates lag queue CAS releases so + * usage requires care. When queued, the lower 16 bits of + * scanState must hold its pool index. So we place the index there + * upon initialization (see registerWorker) and otherwise keep it + * there or restore it when necessary. + * + * Memory ordering. See "Correct and Efficient Work-Stealing for + * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013 + * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an + * analysis of memory ordering requirements in work-stealing + * algorithms similar to the one used here. We usually need + * stronger than minimal ordering because we must sometimes signal + * workers, requiring Dekker-like full-fences to avoid lost + * signals. Arranging for enough ordering without expensive + * over-fencing requires tradeoffs among the supported means of + * expressing access constraints. The most central operations, + * taking from queues and updating ctl state, require full-fence + * CAS. Array slots are read using the emulation of volatiles + * provided by Unsafe. Access from other threads to WorkQueue + * base, top, and array requires a volatile load of the first of + * any of these read. We use the convention of declaring the + * "base" index volatile, and always read it before other fields. + * The owner thread must ensure ordered updates, so writes use + * ordered intrinsics unless they can piggyback on those for other + * writes. Similar conventions and rationales hold for other + * WorkQueue fields (such as "currentSteal") that are only written + * by owners but observed by others. + * + * Creating workers. To create a worker, we pre-increment total + * count (serving as a reservation), and attempt to construct a + * ForkJoinWorkerThread via its factory. Upon construction, the + * new thread invokes registerWorker, where it constructs a + * WorkQueue and is assigned an index in the workQueues array + * (expanding the array if necessary). The thread is then + * started. Upon any exception across these steps, or null return + * from factory, deregisterWorker adjusts counts and records + * accordingly. If a null return, the pool continues running with + * fewer than the target number workers. If exceptional, the + * exception is propagated, generally to some external caller. + * Worker index assignment avoids the bias in scanning that would + * occur if entries were sequentially packed starting at the front + * of the workQueues array. We treat the array as a simple + * power-of-two hash table, expanding as needed. The seedIndex + * increment ensures no collisions until a resize is needed or a + * worker is deregistered and replaced, and thereafter keeps + * probability of collision low. We cannot use + * ThreadLocalRandom.getProbe() for similar purposes here because + * the thread has not started yet, but do so for creating + * submission queues for existing external threads. + * + * Deactivation and waiting. Queuing encounters several intrinsic + * races; most notably that a task-producing thread can miss + * seeing (and signalling) another thread that gave up looking for + * work but has not yet entered the wait queue. When a worker + * cannot find a task to steal, it deactivates and enqueues. Very + * often, the lack of tasks is transient due to GC or OS + * scheduling. To reduce false-alarm deactivation, scanners + * compute checksums of queue states during sweeps. (The + * stability checks used here and elsewhere are probabilistic + * variants of snapshot techniques -- see Herlihy & Shavit.) + * Workers give up and try to deactivate only after the sum is + * stable across scans. Further, to avoid missed signals, they + * repeat this scanning process after successful enqueuing until + * again stable. In this state, the worker cannot take/run a task + * it sees until it is released from the queue, so the worker + * itself eventually tries to release itself or any successor (see + * tryRelease). Otherwise, upon an empty scan, a deactivated + * worker uses an adaptive local spin construction (see awaitWork) + * before blocking (via park). Note the unusual conventions about + * Thread.interrupts surrounding parking and other blocking: + * Because interrupts are used solely to alert threads to check + * termination, which is checked anyway upon blocking, we clear + * status (using Thread.interrupted) before any call to park, so + * that park does not immediately return due to status being set + * via some other unrelated call to interrupt in user code. + * + * Signalling and activation. Workers are created or activated + * only when there appears to be at least one task they might be + * able to find and execute. Upon push (either by a worker or an + * external submission) to a previously (possibly) empty queue, + * workers are signalled if idle, or created if fewer exist than + * the given parallelism level. These primary signals are + * buttressed by others whenever other threads remove a task from + * a queue and notice that there are other tasks there as well. + * On most platforms, signalling (unpark) overhead time is + * noticeably long, and the time between signalling a thread and + * it actually making progress can be very noticeably long, so it + * is worth offloading these delays from critical paths as much as + * possible. Also, because inactive workers are often rescanning + * or spinning rather than blocking, we set and clear the "parker" * field of WorkQueues to reduce unnecessary calls to unpark. * (This requires a secondary recheck to avoid missed signals.) - * Note the unusual conventions about Thread.interrupts - * surrounding parking and other blocking: Because interrupts are - * used solely to alert threads to check termination, which is - * checked anyway upon blocking, we clear status (using - * Thread.interrupted) before any call to park, so that park does - * not immediately return due to status being set via some other - * unrelated call to interrupt in user code. - * - * Signalling. We create or wake up workers only when there - * appears to be at least one task they might be able to find and - * execute. When a submission is added or another worker adds a - * task to a queue that has fewer than two tasks, they signal - * waiting workers (or trigger creation of new ones if fewer than - * the given parallelism level -- signalWork). These primary - * signals are buttressed by others whenever other threads remove - * a task from a queue and notice that there are other tasks there - * as well. So in general, pools will be over-signalled. On most - * platforms, signalling (unpark) overhead time is noticeably - * long, and the time between signalling a thread and it actually - * making progress can be very noticeably long, so it is worth - * offloading these delays from critical paths as much as - * possible. Additionally, workers spin-down gradually, by staying - * alive so long as they see the ctl state changing. Similar - * stability-sensing techniques are also used before blocking in - * awaitJoin and helpComplete. * * Trimming workers. To release resources after periods of lack of * use, a worker starting to wait when the pool is quiescent will - * time out and terminate if the pool has remained quiescent for a - * given period -- a short period if there are more threads than - * parallelism, longer as the number of threads decreases. This - * will slowly propagate, eventually terminating all workers after - * periods of non-use. + * time out and terminate (see awaitWork) if the pool has remained + * quiescent for period IDLE_TIMEOUT, increasing the period as the + * number of threads decreases, eventually removing all workers. + * Also, when more than two spare threads exist, excess threads + * are immediately terminated at the next quiescent point. + * (Padding by two avoids hysteresis.) + * + * Shutdown and Termination. A call to shutdownNow invokes + * tryTerminate to atomically set a runState bit. The calling + * thread, as well as every other worker thereafter terminating, + * helps terminate others by setting their (qlock) status, + * cancelling their unprocessed tasks, and waking them up, doing + * so repeatedly until stable (but with a loop bounded by the + * number of workers). Calls to non-abrupt shutdown() preface + * this by checking whether termination should commence. This + * relies primarily on the active count bits of "ctl" maintaining + * consensus -- tryTerminate is called from awaitWork whenever + * quiescent. However, external submitters do not take part in + * this consensus. So, tryTerminate sweeps through queues (until + * stable) to ensure lack of in-flight submissions and workers + * about to process them before triggering the "STOP" phase of + * termination. (Note: there is an intrinsic conflict if + * helpQuiescePool is called when shutdown is enabled. Both wait + * for quiescence, but tryTerminate is biased to not trigger until + * helpQuiescePool completes.) * - * Shutdown and Termination. A call to shutdownNow atomically sets - * a plock bit and then (non-atomically) sets each worker's - * qlock status, cancels all unprocessed tasks, and wakes up - * all waiting workers. Detecting whether termination should - * commence after a non-abrupt shutdown() call requires more work - * and bookkeeping. We need consensus about quiescence (i.e., that - * there is no more work). The active count provides a primary - * indication but non-abrupt shutdown still requires a rechecking - * scan for any workers that are inactive but not queued. * * Joining Tasks * ============= @@ -403,9 +531,9 @@ public class ForkJoinPool extends AbstractExecutorService { * just let them block (as in Thread.join). We also cannot just * reassign the joiner's run-time stack with another and replace * it later, which would be a form of "continuation", that even if - * possible is not necessarily a good idea since we sometimes need - * both an unblocked task and its continuation to progress. - * Instead we combine two tactics: + * possible is not necessarily a good idea since we may need both + * an unblocked task and its continuation to progress. Instead we + * combine two tactics: * * Helping: Arranging for the joiner to execute some task that it * would be running if the steal had not occurred. @@ -425,16 +553,16 @@ public class ForkJoinPool extends AbstractExecutorService { * The ManagedBlocker extension API can't use helping so relies * only on compensation in method awaitBlocker. * - * The algorithm in tryHelpStealer entails a form of "linear" - * helping: Each worker records (in field currentSteal) the most - * recent task it stole from some other worker. Plus, it records - * (in field currentJoin) the task it is currently actively - * joining. Method tryHelpStealer uses these markers to try to - * find a worker to help (i.e., steal back a task from and execute - * it) that could hasten completion of the actively joined task. - * In essence, the joiner executes a task that would be on its own - * local deque had the to-be-joined task not been stolen. This may - * be seen as a conservative variant of the approach in Wagner & + * The algorithm in helpStealer entails a form of "linear + * helping". Each worker records (in field currentSteal) the most + * recent task it stole from some other worker (or a submission). + * It also records (in field currentJoin) the task it is currently + * actively joining. Method helpStealer uses these markers to try + * to find a worker to help (i.e., steal back a task from and + * execute it) that could hasten completion of the actively joined + * task. Thus, the joiner executes a task that would be on its + * own local deque had the to-be-joined task not been stolen. This + * is a conservative variant of the approach described in Wagner & * Calder "Leapfrogging: a portable technique for implementing * efficient futures" SIGPLAN Notices, 1993 * (http://portal.acm.org/citation.cfm?id=155354). It differs in @@ -452,37 +580,40 @@ public class ForkJoinPool extends AbstractExecutorService { * which means that we miss links in the chain during long-lived * tasks, GC stalls etc (which is OK since blocking in such cases * is usually a good idea). (4) We bound the number of attempts - * to find work (see MAX_HELP) and fall back to suspending the + * to find work using checksums and fall back to suspending the * worker and if necessary replacing it with another. * - * Helping actions for CountedCompleters are much simpler: Method - * helpComplete can take and execute any task with the same root - * as the task being waited on. However, this still entails some - * traversal of completer chains, so is less efficient than using - * CountedCompleters without explicit joins. + * Helping actions for CountedCompleters do not require tracking + * currentJoins: Method helpComplete takes and executes any task + * with the same root as the task being waited on (preferring + * local pops to non-local polls). However, this still entails + * some traversal of completer chains, so is less efficient than + * using CountedCompleters without explicit joins. * - * It is impossible to keep exactly the target parallelism number - * of threads running at any given time. Determining the - * existence of conservatively safe helping targets, the - * availability of already-created spares, and the apparent need - * to create new spares are all racy, so we rely on multiple - * retries of each. Compensation in the apparent absence of - * helping opportunities is challenging to control on JVMs, where - * GC and other activities can stall progress of tasks that in - * turn stall out many other dependent tasks, without us being - * able to determine whether they will ever require compensation. - * Even though work-stealing otherwise encounters little - * degradation in the presence of more threads than cores, - * aggressively adding new threads in such cases entails risk of - * unwanted positive feedback control loops in which more threads - * cause more dependent stalls (as well as delayed progress of - * unblocked threads to the point that we know they are available) - * leading to more situations requiring more threads, and so - * on. This aspect of control can be seen as an (analytically - * intractable) game with an opponent that may choose the worst - * (for us) active thread to stall at any time. We take several - * precautions to bound losses (and thus bound gains), mainly in - * methods tryCompensate and awaitJoin. + * Compensation does not aim to keep exactly the target + * parallelism number of unblocked threads running at any given + * time. Some previous versions of this class employed immediate + * compensations for any blocked join. However, in practice, the + * vast majority of blockages are transient byproducts of GC and + * other JVM or OS activities that are made worse by replacement. + * Currently, compensation is attempted only after validating that + * all purportedly active threads are processing tasks by checking + * field WorkQueue.scanState, which eliminates most false + * positives. Also, compensation is bypassed (tolerating fewer + * threads) in the most common case in which it is rarely + * beneficial: when a worker with an empty queue (thus no + * continuation tasks) blocks on a join and there still remain + * enough threads to ensure liveness. + * + * The compensation mechanism may be bounded. Bounds for the + * commonPool (see commonMaxSpares) better enable JVMs to cope + * with programming errors and abuse before running out of + * resources to do so. In other cases, users may supply factories + * that limit thread construction. The effects of bounding in this + * pool (like all others) is imprecise. Total worker counts are + * decremented when threads deregister, not when they exit and + * resources are reclaimed by the JVM and OS. So the number of + * simultaneously live threads may transiently exceed bounds. * * Common Pool * =========== @@ -492,34 +623,52 @@ public class ForkJoinPool extends AbstractExecutorService { * never be used, we minimize initial construction overhead and * footprint to the setup of about a dozen fields, with no nested * allocation. Most bootstrapping occurs within method - * fullExternalPush during the first submission to the pool. + * externalSubmit during the first submission to the pool. * * When external threads submit to the common pool, they can - * perform subtask processing (see externalHelpJoin and related - * methods). This caller-helps policy makes it sensible to set - * common pool parallelism level to one (or more) less than the - * total number of available cores, or even zero for pure - * caller-runs. We do not need to record whether external - * submissions are to the common pool -- if not, externalHelpJoin - * returns quickly (at the most helping to signal some common pool - * workers). These submitters would otherwise be blocked waiting - * for completion, so the extra effort (with liberally sprinkled - * task status checks) in inapplicable cases amounts to an odd - * form of limited spin-wait before blocking in ForkJoinTask.join. + * perform subtask processing (see externalHelpComplete and + * related methods) upon joins. This caller-helps policy makes it + * sensible to set common pool parallelism level to one (or more) + * less than the total number of available cores, or even zero for + * pure caller-runs. We do not need to record whether external + * submissions are to the common pool -- if not, external help + * methods return quickly. These submitters would otherwise be + * blocked waiting for completion, so the extra effort (with + * liberally sprinkled task status checks) in inapplicable cases + * amounts to an odd form of limited spin-wait before blocking in + * ForkJoinTask.join. * * As a more appropriate default in managed environments, unless * overridden by system properties, we use workers of subclass * InnocuousForkJoinWorkerThread when there is a SecurityManager * present. These workers have no permissions set, do not belong * to any user-defined ThreadGroup, and erase all ThreadLocals - * after executing any top-level task (see WorkQueue.runTask). The - * associated mechanics (mainly in ForkJoinWorkerThread) may be - * JVM-dependent and must access particular Thread class fields to - * achieve this effect. + * after executing any top-level task (see WorkQueue.runTask). + * The associated mechanics (mainly in ForkJoinWorkerThread) may + * be JVM-dependent and must access particular Thread class fields + * to achieve this effect. * * Style notes * =========== * + * Memory ordering relies mainly on Unsafe intrinsics that carry + * the further responsibility of explicitly performing null- and + * bounds- checks otherwise carried out implicitly by JVMs. This + * can be awkward and ugly, but also reflects the need to control + * outcomes across the unusual cases that arise in very racy code + * with very few invariants. So these explicit checks would exist + * in some form anyway. All fields are read into locals before + * use, and null-checked if they are references. This is usually + * done in a "C"-like style of listing declarations at the heads + * of methods or blocks, and using inline assignments on first + * encounter. Array bounds-checks are usually performed by + * masking with array.length-1, which relies on the invariant that + * these arrays are created with positive lengths, which is itself + * paranoically checked. Nearly all explicit checks lead to + * bypass/return, not exception throws, because they may + * legitimately arise due to cancellation/revocation during + * shutdown. + * * There is a lot of representation-level coupling among classes * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The * fields of WorkQueue maintain data structures managed by @@ -527,22 +676,13 @@ public class ForkJoinPool extends AbstractExecutorService { * trying to reduce this, since any associated future changes in * representations will need to be accompanied by algorithmic * changes anyway. Several methods intrinsically sprawl because - * they must accumulate sets of consistent reads of volatiles held - * in local variables. Methods signalWork() and scan() are the - * main bottlenecks, so are especially heavily - * micro-optimized/mangled. There are lots of inline assignments - * (of form "while ((local = field) != 0)") which are usually the - * simplest way to ensure the required read orderings (which are - * sometimes critical). This leads to a "C"-like style of listing - * declarations of these locals at the heads of methods or blocks. - * There are several occurrences of the unusual "do {} while - * (!cas...)" which is the simplest way to force an update of a - * CAS'ed variable. There are also other coding oddities (including - * several unnecessary-looking hoisted null checks) that help - * some methods perform reasonably even when interpreted (not - * compiled). + * they must accumulate sets of consistent reads of fields held in + * local variables. There are also other coding oddities + * (including several unnecessary-looking hoisted null checks) + * that help some methods perform reasonably even when interpreted + * (not compiled). * - * The order of declarations in this file is: + * The order of declarations in this file is (with a few exceptions): * (1) Static utility functions * (2) Nested (static) classes * (3) Static fields @@ -609,56 +749,37 @@ public class ForkJoinPool extends AbstractExecutorService { public final boolean exec() { return true; } } + // Constants shared across ForkJoinPool and WorkQueue + + // Bounds + static final int SMASK = 0xffff; // short bits == max index + static final int MAX_CAP = 0x7fff; // max #workers - 1 + static final int EVENMASK = 0xfffe; // even short bits + static final int SQMASK = 0x007e; // max 64 (even) slots + + // Masks and units for WorkQueue.scanState and ctl sp subfield + static final int SCANNING = 1; // false when running tasks + static final int INACTIVE = 1 << 31; // must be negative + static final int SS_SEQ = 1 << 16; // version count + + // Mode bits for ForkJoinPool.config and WorkQueue.config + static final int MODE_MASK = 0xffff << 16; // top half of int + static final int LIFO_QUEUE = 0; + static final int FIFO_QUEUE = 1 << 16; + static final int SHARED_QUEUE = 1 << 31; // must be negative + /** * Queues supporting work-stealing as well as external task - * submission. See above for main rationale and algorithms. - * Implementation relies heavily on "Unsafe" intrinsics - * and selective use of "volatile": - * - * Field "base" is the index (mod array.length) of the least valid - * queue slot, which is always the next position to steal (poll) - * from if nonempty. Reads and writes require volatile orderings - * but not CAS, because updates are only performed after slot - * CASes. - * - * Field "top" is the index (mod array.length) of the next queue - * slot to push to or pop from. It is written only by owner thread - * for push, or under lock for external/shared push, and accessed - * by other threads only after reading (volatile) base. Both top - * and base are allowed to wrap around on overflow, but (top - - * base) (or more commonly -(base - top) to force volatile read of - * base before top) still estimates size. The lock ("qlock") is - * forced to -1 on termination, causing all further lock attempts - * to fail. (Note: we don't need CAS for termination state because - * upon pool shutdown, all shared-queues will stop being used - * anyway.) Nearly all lock bodies are set up so that exceptions - * within lock bodies are "impossible" (modulo JVM errors that - * would cause failure anyway.) - * - * The array slots are read and written using the emulation of - * volatiles/atomics provided by Unsafe. Insertions must in - * general use putOrderedObject as a form of releasing store to - * ensure that all writes to the task object are ordered before - * its publication in the queue. All removals entail a CAS to - * null. The array is always a power of two. To ensure safety of - * Unsafe array operations, all accesses perform explicit null - * checks and implicit bounds checks via power-of-two masking. - * - * In addition to basic queuing support, this class contains - * fields described elsewhere to control execution. It turns out - * to work better memory-layout-wise to include them in this class - * rather than a separate class. - * + * submission. See above for descriptions and algorithms. * Performance on most platforms is very sensitive to placement of * instances of both WorkQueues and their arrays -- we absolutely * do not want multiple WorkQueue instances or multiple queue - * arrays sharing cache lines. (It would be best for queue objects - * and their arrays to share, but there is nothing available to - * help arrange that). The @Contended annotation alerts JVMs to - * try to keep instances apart. + * arrays sharing cache lines. The @Contended annotation alerts + * JVMs to try to keep instances apart. */ @sun.misc.Contended static final class WorkQueue { + /** * Capacity of work-stealing queue array upon initialization. * Must be a power of two; at least 4, but should be larger to @@ -679,13 +800,13 @@ public class ForkJoinPool extends AbstractExecutorService { */ static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M - volatile int eventCount; // encoded inactivation count; < 0 if inactive - int nextWait; // encoded record of next event waiter + // Instance fields + volatile int scanState; // versioned, <0: inactive; odd:scanning + int stackPred; // pool stack (ctl) predecessor int nsteals; // number of steals - int hint; // steal index hint - short poolIndex; // index of this queue in pool - final short mode; // 0: lifo, > 0: fifo, < 0: shared - volatile int qlock; // 1: locked, -1: terminate; else 0 + int hint; // randomization and stealer index hint + int config; // pool index and mode + volatile int qlock; // 1: locked, < 0: terminate; else 0 volatile int base; // index of next slot for poll int top; // index of next slot for push ForkJoinTask[] array; // the elements (initially unallocated) @@ -693,18 +814,22 @@ public class ForkJoinPool extends AbstractExecutorService { final ForkJoinWorkerThread owner; // owning thread or null if shared volatile Thread parker; // == owner during call to park; else null volatile ForkJoinTask currentJoin; // task being joined in awaitJoin - ForkJoinTask currentSteal; // current non-local task being executed + volatile ForkJoinTask currentSteal; // mainly used by helpStealer - WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode, - int seed) { + WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) { this.pool = pool; this.owner = owner; - this.mode = (short)mode; - this.hint = seed; // store initial seed for runWorker // Place indices in the center of array (that is not yet allocated) base = top = INITIAL_QUEUE_CAPACITY >>> 1; } + /** + * Returns an exportable index (used by ForkJoinWorkerThread). + */ + final int getPoolIndex() { + return (config & 0xffff) >>> 1; // ignore odd/even tag bit + } + /** * Returns the approximate number of tasks in the queue. */ @@ -719,12 +844,10 @@ public class ForkJoinPool extends AbstractExecutorService { * near-empty queue has at least one unclaimed task. */ final boolean isEmpty() { - ForkJoinTask[] a; int m, s; - int n = base - (s = top); - return (n >= 0 || - (n == -1 && - ((a = array) == null || - (m = a.length - 1) < 0 || + ForkJoinTask[] a; int n, m, s; + return ((n = base - (s = top)) >= 0 || + (n == -1 && // possibly one task + ((a = array) == null || (m = a.length - 1) < 0 || U.getObject (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null))); } @@ -738,12 +861,15 @@ public class ForkJoinPool extends AbstractExecutorService { */ final void push(ForkJoinTask task) { ForkJoinTask[] a; ForkJoinPool p; - int s = top, n; + int b = base, s = top, n; if ((a = array) != null) { // ignore if queue removed - int m = a.length - 1; + int m = a.length - 1; // fenced write for task visibility U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task); - if ((n = (top = s + 1) - base) <= 2) - (p = pool).signalWork(p.workQueues, this); + U.putOrderedInt(this, QTOP, s + 1); + if ((n = s - b) <= 1) { + if ((p = pool) != null) + p.signalWork(p.workQueues, this); + } else if (n >= m) growArray(); } @@ -764,7 +890,7 @@ public class ForkJoinPool extends AbstractExecutorService { if (oldA != null && (oldMask = oldA.length - 1) >= 0 && (t = top) - (b = base) > 0) { int mask = size - 1; - do { + do { // emulate poll from old array, push to new array ForkJoinTask x; int oldj = ((b & oldMask) << ASHIFT) + ABASE; int j = ((b & mask) << ASHIFT) + ABASE; @@ -789,7 +915,7 @@ public class ForkJoinPool extends AbstractExecutorService { if ((t = (ForkJoinTask)U.getObject(a, j)) == null) break; if (U.compareAndSwapObject(a, j, t, null)) { - top = s; + U.putOrderedInt(this, QTOP, s); return t; } } @@ -800,7 +926,7 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Takes a task in FIFO order if b is base of queue and a task * can be claimed without contention. Specialized versions - * appear in ForkJoinPool methods scan and tryHelpStealer. + * appear in ForkJoinPool methods scan and helpStealer. */ final ForkJoinTask pollAt(int b) { ForkJoinTask t; ForkJoinTask[] a; @@ -808,7 +934,7 @@ public class ForkJoinPool extends AbstractExecutorService { int j = (((a.length - 1) & b) << ASHIFT) + ABASE; if ((t = (ForkJoinTask)U.getObjectVolatile(a, j)) != null && base == b && U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QBASE, b + 1); + base = b + 1; return t; } } @@ -823,16 +949,15 @@ public class ForkJoinPool extends AbstractExecutorService { while ((b = base) - top < 0 && (a = array) != null) { int j = (((a.length - 1) & b) << ASHIFT) + ABASE; t = (ForkJoinTask)U.getObjectVolatile(a, j); - if (t != null) { - if (U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QBASE, b + 1); - return t; + if (base == b) { + if (t != null) { + if (U.compareAndSwapObject(a, j, t, null)) { + base = b + 1; + return t; + } } - } - else if (base == b) { - if (b + 1 == top) + else if (b + 1 == top) // now empty break; - Thread.yield(); // wait for lagging update (very rare) } } return null; @@ -842,7 +967,7 @@ public class ForkJoinPool extends AbstractExecutorService { * Takes next task, if one exists, in order specified by mode. */ final ForkJoinTask nextLocalTask() { - return mode == 0 ? pop() : poll(); + return (config & FIFO_QUEUE) == 0 ? pop() : poll(); } /** @@ -852,7 +977,7 @@ public class ForkJoinPool extends AbstractExecutorService { ForkJoinTask[] a = array; int m; if (a == null || (m = a.length - 1) < 0) return null; - int i = mode == 0 ? top - 1 : base; + int i = (config & FIFO_QUEUE) == 0 ? top - 1 : base; int j = ((i & m) << ASHIFT) + ABASE; return (ForkJoinTask)U.getObjectVolatile(a, j); } @@ -860,13 +985,13 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Pops the given task only if it is at the current top. * (A shared version is available only via FJP.tryExternalUnpush) - */ + */ final boolean tryUnpush(ForkJoinTask t) { ForkJoinTask[] a; int s; if ((a = array) != null && (s = top) != base && U.compareAndSwapObject (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { - top = s; + U.putOrderedInt(this, QTOP, s); return true; } return false; @@ -876,9 +1001,16 @@ public class ForkJoinPool extends AbstractExecutorService { * Removes and cancels all known tasks, ignoring any exceptions. */ final void cancelAll() { - ForkJoinTask.cancelIgnoringExceptions(currentJoin); - ForkJoinTask.cancelIgnoringExceptions(currentSteal); - for (ForkJoinTask t; (t = poll()) != null; ) + ForkJoinTask t; + if ((t = currentJoin) != null) { + currentJoin = null; + ForkJoinTask.cancelIgnoringExceptions(t); + } + if ((t = currentSteal) != null) { + currentSteal = null; + ForkJoinTask.cancelIgnoringExceptions(t); + } + while ((t = poll()) != null) ForkJoinTask.cancelIgnoringExceptions(t); } @@ -893,167 +1025,186 @@ public class ForkJoinPool extends AbstractExecutorService { } /** - * Executes a top-level task and any local tasks remaining - * after execution. + * Removes and executes all local tasks. If LIFO, invokes + * pollAndExecAll. Otherwise implements a specialized pop loop + * to exec until empty. */ - final void runTask(ForkJoinTask task) { - if ((currentSteal = task) != null) { - ForkJoinWorkerThread thread; - task.doExec(); - ForkJoinTask[] a = array; - int md = mode; - ++nsteals; - currentSteal = null; - if (md != 0) - pollAndExecAll(); - else if (a != null) { - int s, m = a.length - 1; - ForkJoinTask t; - while ((s = top - 1) - base >= 0 && - (t = (ForkJoinTask)U.getAndSetObject - (a, ((m & s) << ASHIFT) + ABASE, null)) != null) { - top = s; + final void execLocalTasks() { + int b = base, m, s; + ForkJoinTask[] a = array; + if (b - (s = top - 1) <= 0 && a != null && + (m = a.length - 1) >= 0) { + if ((config & FIFO_QUEUE) == 0) { + for (ForkJoinTask t;;) { + if ((t = (ForkJoinTask)U.getAndSetObject + (a, ((m & s) << ASHIFT) + ABASE, null)) == null) + break; + U.putOrderedInt(this, QTOP, s); t.doExec(); + if (base - (s = top - 1) > 0) + break; } } - if ((thread = owner) != null) // no need to do in finally clause + else + pollAndExecAll(); + } + } + + /** + * Executes the given task and any remaining local tasks. + */ + final void runTask(ForkJoinTask task) { + if (task != null) { + scanState &= ~SCANNING; // mark as busy + (currentSteal = task).doExec(); + U.putOrderedObject(this, QCURRENTSTEAL, null); // release for GC + execLocalTasks(); + ForkJoinWorkerThread thread = owner; + if (++nsteals < 0) // collect on overflow + transferStealCount(pool); + scanState |= SCANNING; + if (thread != null) thread.afterTopLevelExec(); } } + /** + * Adds steal count to pool stealCounter if it exists, and resets. + */ + final void transferStealCount(ForkJoinPool p) { + AtomicLong sc; + if (p != null && (sc = p.stealCounter) != null) { + int s = nsteals; + nsteals = 0; // if negative, correct for overflow + sc.getAndAdd((long)(s < 0 ? Integer.MAX_VALUE : s)); + } + } + /** * If present, removes from queue and executes the given task, - * or any other cancelled task. Returns (true) on any CAS - * or consistency check failure so caller can retry. + * or any other cancelled task. Used only by awaitJoin. * - * @return false if no progress can be made, else true + * @return true if queue empty and task not known to be done */ final boolean tryRemoveAndExec(ForkJoinTask task) { - boolean stat; ForkJoinTask[] a; int m, s, b, n; - if (task != null && (a = array) != null && (m = a.length - 1) >= 0 && - (n = (s = top) - (b = base)) > 0) { - boolean removed = false, empty = true; - stat = true; - for (ForkJoinTask t;;) { // traverse from s to b - long j = ((--s & m) << ASHIFT) + ABASE; - t = (ForkJoinTask)U.getObject(a, j); - if (t == null) // inconsistent length - break; - else if (t == task) { - if (s + 1 == top) { // pop - if (!U.compareAndSwapObject(a, j, task, null)) - break; - top = s; - removed = true; + if ((a = array) != null && (m = a.length - 1) >= 0 && + task != null) { + while ((n = (s = top) - (b = base)) > 0) { + for (ForkJoinTask t;;) { // traverse from s to b + long j = ((--s & m) << ASHIFT) + ABASE; + if ((t = (ForkJoinTask)U.getObject(a, j)) == null) + return s + 1 == top; // shorter than expected + else if (t == task) { + boolean removed = false; + if (s + 1 == top) { // pop + if (U.compareAndSwapObject(a, j, task, null)) { + U.putOrderedInt(this, QTOP, s); + removed = true; + } + } + else if (base == b) // replace with proxy + removed = U.compareAndSwapObject( + a, j, task, new EmptyTask()); + if (removed) + task.doExec(); + break; } - else if (base == b) // replace with proxy - removed = U.compareAndSwapObject(a, j, task, - new EmptyTask()); - break; - } - else if (t.status >= 0) - empty = false; - else if (s + 1 == top) { // pop and throw away - if (U.compareAndSwapObject(a, j, t, null)) - top = s; - break; - } - if (--n == 0) { - if (!empty && base == b) - stat = false; - break; + else if (t.status < 0 && s + 1 == top) { + if (U.compareAndSwapObject(a, j, t, null)) + U.putOrderedInt(this, QTOP, s); + break; // was cancelled + } + if (--n == 0) + return false; } + if (task.status < 0) + return false; } - if (removed) - task.doExec(); } - else - stat = false; - return stat; + return true; } /** - * Tries to poll for and execute the given task or any other - * task in its CountedCompleter computation. + * Pops task if in the same CC computation as the given task, + * in either shared or owned mode. Used only by helpComplete. */ - final boolean pollAndExecCC(CountedCompleter root) { - ForkJoinTask[] a; int b; Object o; CountedCompleter t, r; - if ((b = base) - top < 0 && (a = array) != null) { + final CountedCompleter popCC(CountedCompleter task, int mode) { + int s; ForkJoinTask[] a; Object o; + if (base - (s = top) < 0 && (a = array) != null) { + long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; + if ((o = U.getObjectVolatile(a, j)) != null && + (o instanceof CountedCompleter)) { + CountedCompleter t = (CountedCompleter)o; + for (CountedCompleter r = t;;) { + if (r == task) { + if (mode < 0) { // must lock + if (U.compareAndSwapInt(this, QLOCK, 0, 1)) { + if (top == s && array == a && + U.compareAndSwapObject(a, j, t, null)) { + U.putOrderedInt(this, QTOP, s - 1); + U.putOrderedInt(this, QLOCK, 0); + return t; + } + U.compareAndSwapInt(this, QLOCK, 1, 0); + } + } + else if (U.compareAndSwapObject(a, j, t, null)) { + U.putOrderedInt(this, QTOP, s - 1); + return t; + } + break; + } + else if ((r = r.completer) == null) // try parent + break; + } + } + } + return null; + } + + /** + * Steals and runs a task in the same CC computation as the + * given task if one exists and can be taken without + * contention. Otherwise returns a checksum/control value for + * use by method helpComplete. + * + * @return 1 if successful, 2 if retryable (lost to another + * stealer), -1 if non-empty but no matching task found, else + * the base index, forced negative. + */ + final int pollAndExecCC(CountedCompleter task) { + int b, h; ForkJoinTask[] a; Object o; + if ((b = base) - top >= 0 || (a = array) == null) + h = b | Integer.MIN_VALUE; // to sense movement on re-poll + else { long j = (((a.length - 1) & b) << ASHIFT) + ABASE; if ((o = U.getObjectVolatile(a, j)) == null) - return true; // retry - if (o instanceof CountedCompleter) { - for (t = (CountedCompleter)o, r = t;;) { - if (r == root) { + h = 2; // retryable + else if (!(o instanceof CountedCompleter)) + h = -1; // unmatchable + else { + CountedCompleter t = (CountedCompleter)o; + for (CountedCompleter r = t;;) { + if (r == task) { if (base == b && U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QBASE, b + 1); + base = b + 1; t.doExec(); + h = 1; // success } - return true; - } - else if ((r = r.completer) == null) - break; // not part of root computation - } - } - } - return false; - } - - /** - * Tries to pop and execute the given task or any other task - * in its CountedCompleter computation. - */ - final boolean externalPopAndExecCC(CountedCompleter root) { - ForkJoinTask[] a; int s; Object o; CountedCompleter t, r; - if (base - (s = top) < 0 && (a = array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if ((o = U.getObject(a, j)) instanceof CountedCompleter) { - for (t = (CountedCompleter)o, r = t;;) { - if (r == root) { - if (U.compareAndSwapInt(this, QLOCK, 0, 1)) { - if (top == s && array == a && - U.compareAndSwapObject(a, j, t, null)) { - top = s - 1; - qlock = 0; - t.doExec(); - } - else - qlock = 0; - } - return true; - } - else if ((r = r.completer) == null) + else + h = 2; // lost CAS break; - } - } - } - return false; - } - - /** - * Internal version - */ - final boolean internalPopAndExecCC(CountedCompleter root) { - ForkJoinTask[] a; int s; Object o; CountedCompleter t, r; - if (base - (s = top) < 0 && (a = array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if ((o = U.getObject(a, j)) instanceof CountedCompleter) { - for (t = (CountedCompleter)o, r = t;;) { - if (r == root) { - if (U.compareAndSwapObject(a, j, t, null)) { - top = s - 1; - t.doExec(); - } - return true; } - else if ((r = r.completer) == null) + else if ((r = r.completer) == null) { + h = -1; // unmatched break; + } } } } - return false; + return h; } /** @@ -1061,28 +1212,31 @@ public class ForkJoinPool extends AbstractExecutorService { */ final boolean isApparentlyUnblocked() { Thread wt; Thread.State s; - return (eventCount >= 0 && + return (scanState >= 0 && (wt = owner) != null && (s = wt.getState()) != Thread.State.BLOCKED && s != Thread.State.WAITING && s != Thread.State.TIMED_WAITING); } - // Unsafe mechanics + // Unsafe mechanics. Note that some are (and must be) the same as in FJP private static final sun.misc.Unsafe U; - private static final long QBASE; + private static final int ABASE; + private static final int ASHIFT; + private static final long QTOP; private static final long QLOCK; - private static final int ABASE; - private static final int ASHIFT; + private static final long QCURRENTSTEAL; static { try { U = sun.misc.Unsafe.getUnsafe(); - Class k = WorkQueue.class; + Class wk = WorkQueue.class; Class ak = ForkJoinTask[].class; - QBASE = U.objectFieldOffset - (k.getDeclaredField("base")); + QTOP = U.objectFieldOffset + (wk.getDeclaredField("top")); QLOCK = U.objectFieldOffset - (k.getDeclaredField("qlock")); + (wk.getDeclaredField("qlock")); + QCURRENTSTEAL = U.objectFieldOffset + (wk.getDeclaredField("currentSteal")); ABASE = U.arrayBaseOffset(ak); int scale = U.arrayIndexScale(ak); if ((scale & (scale - 1)) != 0) @@ -1125,6 +1279,11 @@ public class ForkJoinPool extends AbstractExecutorService { */ static final int commonParallelism; + /** + * Limit on spare thread construction in tryCompensate. + */ + private static int commonMaxSpares; + /** * Sequence number for creating workerNamePrefix. */ @@ -1138,7 +1297,7 @@ public class ForkJoinPool extends AbstractExecutorService { return ++poolNumberSequence; } - // static constants + // static configuration constants /** * Initial timeout value (in nanoseconds) for the thread @@ -1148,27 +1307,34 @@ public class ForkJoinPool extends AbstractExecutorService { * aggressive shrinkage during most transient stalls (long GCs * etc). */ - private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec - - /** - * Timeout value when there are more threads than parallelism level - */ - private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L; + private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec /** * Tolerance for idle timeouts, to cope with timer undershoots */ - private static final long TIMEOUT_SLOP = 2000000L; + private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms /** - * The maximum stolen->joining link depth allowed in method - * tryHelpStealer. Must be a power of two. Depths for legitimate - * chains are unbounded, but we use a fixed constant to avoid - * (otherwise unchecked) cycles and to bound staleness of - * traversal parameters at the expense of sometimes blocking when - * we could be helping. + * The initial value for commonMaxSpares during static + * initialization unless overridden using System property + * "java.util.concurrent.ForkJoinPool.common.maximumSpares". The + * default value is far in excess of normal requirements, but also + * far short of MAX_CAP and typical OS thread limits, so allows + * JVMs to catch misuse/abuse before running out of resources + * needed to do so. */ - private static final int MAX_HELP = 64; + private static final int DEFAULT_COMMON_MAX_SPARES = 256; + + /** + * Number of times to spin-wait before blocking. The spins (in + * awaitRunStateLock and awaitWork) currently use randomized + * spins. If/when MWAIT-like intrinsics becomes available, they + * may allow quieter spinning. The value of SPINS must be a power + * of two, at least 4. The current value causes spinning for a + * small fraction of typical context-switch times, well worthwhile + * given the typical likelihoods that blocking is not necessary. + */ + private static final int SPINS = 1 << 11; /** * Increment for seed generators. See class ThreadLocal for @@ -1177,209 +1343,212 @@ public class ForkJoinPool extends AbstractExecutorService { private static final int SEED_INCREMENT = 0x9e3779b9; /* - * Bits and masks for control variables + * Bits and masks for field ctl, packed with 4 16 bit subfields: + * AC: Number of active running workers minus target parallelism + * TC: Number of total workers minus target parallelism + * SS: version count and status of top waiting thread + * ID: poolIndex of top of Treiber stack of waiters * - * Field ctl is a long packed with: - * AC: Number of active running workers minus target parallelism (16 bits) - * TC: Number of total workers minus target parallelism (16 bits) - * ST: true if pool is terminating (1 bit) - * EC: the wait count of top waiting thread (15 bits) - * ID: poolIndex of top of Treiber stack of waiters (16 bits) + * When convenient, we can extract the lower 32 stack top bits + * (including version bits) as sp=(int)ctl. The offsets of counts + * by the target parallelism and the positionings of fields makes + * it possible to perform the most common checks via sign tests of + * fields: When ac is negative, there are not enough active + * workers, when tc is negative, there are not enough total + * workers. When sp is non-zero, there are waiting workers. To + * deal with possibly negative fields, we use casts in and out of + * "short" and/or signed shifts to maintain signedness. * - * When convenient, we can extract the upper 32 bits of counts and - * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e = - * (int)ctl. The ec field is never accessed alone, but always - * together with id and st. The offsets of counts by the target - * parallelism and the positionings of fields makes it possible to - * perform the most common checks via sign tests of fields: When - * ac is negative, there are not enough active workers, when tc is - * negative, there are not enough total workers, and when e is - * negative, the pool is terminating. To deal with these possibly - * negative fields, we use casts in and out of "short" and/or - * signed shifts to maintain signedness. - * - * When a thread is queued (inactivated), its eventCount field is - * set negative, which is the only way to tell if a worker is - * prevented from executing tasks, even though it must continue to - * scan for them to avoid queuing races. Note however that - * eventCount updates lag releases so usage requires care. - * - * Field plock is an int packed with: - * SHUTDOWN: true if shutdown is enabled (1 bit) - * SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits) - * SIGNAL: set when threads may be waiting on the lock (1 bit) - * - * The sequence number enables simple consistency checks: - * Staleness of read-only operations on the workQueues array can - * be checked by comparing plock before vs after the reads. + * Because it occupies uppermost bits, we can add one active count + * using getAndAddLong of AC_UNIT, rather than CAS, when returning + * from a blocked join. Other updates entail multiple subfields + * and masking, requiring CAS. */ - // bit positions/shifts for fields + // Lower and upper word masks + private static final long SP_MASK = 0xffffffffL; + private static final long UC_MASK = ~SP_MASK; + + // Active counts private static final int AC_SHIFT = 48; + private static final long AC_UNIT = 0x0001L << AC_SHIFT; + private static final long AC_MASK = 0xffffL << AC_SHIFT; + + // Total counts private static final int TC_SHIFT = 32; - private static final int ST_SHIFT = 31; - private static final int EC_SHIFT = 16; + private static final long TC_UNIT = 0x0001L << TC_SHIFT; + private static final long TC_MASK = 0xffffL << TC_SHIFT; + private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign - // bounds - private static final int SMASK = 0xffff; // short bits - private static final int MAX_CAP = 0x7fff; // max #workers - 1 - private static final int EVENMASK = 0xfffe; // even short bits - private static final int SQMASK = 0x007e; // max 64 (even) slots - private static final int SHORT_SIGN = 1 << 15; - private static final int INT_SIGN = 1 << 31; - - // masks - private static final long STOP_BIT = 0x0001L << ST_SHIFT; - private static final long AC_MASK = ((long)SMASK) << AC_SHIFT; - private static final long TC_MASK = ((long)SMASK) << TC_SHIFT; - - // units for incrementing and decrementing - private static final long TC_UNIT = 1L << TC_SHIFT; - private static final long AC_UNIT = 1L << AC_SHIFT; - - // masks and units for dealing with u = (int)(ctl >>> 32) - private static final int UAC_SHIFT = AC_SHIFT - 32; - private static final int UTC_SHIFT = TC_SHIFT - 32; - private static final int UAC_MASK = SMASK << UAC_SHIFT; - private static final int UTC_MASK = SMASK << UTC_SHIFT; - private static final int UAC_UNIT = 1 << UAC_SHIFT; - private static final int UTC_UNIT = 1 << UTC_SHIFT; - - // masks and units for dealing with e = (int)ctl - private static final int E_MASK = 0x7fffffff; // no STOP_BIT - private static final int E_SEQ = 1 << EC_SHIFT; - - // plock bits - private static final int SHUTDOWN = 1 << 31; - private static final int PL_LOCK = 2; - private static final int PL_SIGNAL = 1; - private static final int PL_SPINS = 1 << 8; - - // access mode for WorkQueue - static final int LIFO_QUEUE = 0; - static final int FIFO_QUEUE = 1; - static final int SHARED_QUEUE = -1; + // runState bits: SHUTDOWN must be negative, others arbitrary powers of two + private static final int RSLOCK = 1; + private static final int RSIGNAL = 1 << 1; + private static final int STARTED = 1 << 2; + private static final int STOP = 1 << 29; + private static final int TERMINATED = 1 << 30; + private static final int SHUTDOWN = 1 << 31; // Instance fields - volatile long stealCount; // collects worker counts - volatile long ctl; // main pool control - volatile int plock; // shutdown status and seqLock - volatile int indexSeed; // worker/submitter index seed - final short parallelism; // parallelism level - final short mode; // LIFO/FIFO - WorkQueue[] workQueues; // main registry + volatile long ctl; // main pool control + volatile int runState; // lockable status + final int config; // parallelism, mode + int indexSeed; // to generate worker index + volatile WorkQueue[] workQueues; // main registry final ForkJoinWorkerThreadFactory factory; - final UncaughtExceptionHandler ueh; // per-worker UEH - final String workerNamePrefix; // to create worker name string + final UncaughtExceptionHandler ueh; // per-worker UEH + final String workerNamePrefix; // to create worker name string + volatile AtomicLong stealCounter; // also used as sync monitor /** - * Acquires the plock lock to protect worker array and related - * updates. This method is called only if an initial CAS on plock - * fails. This acts as a spinlock for normal cases, but falls back - * to builtin monitor to block when (rarely) needed. This would be - * a terrible idea for a highly contended lock, but works fine as - * a more conservative alternative to a pure spinlock. + * Acquires the runState lock; returns current (locked) runState. */ - private int acquirePlock() { - int spins = PL_SPINS, ps, nps; - for (;;) { - if (((ps = plock) & PL_LOCK) == 0 && - U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK)) - return nps; - else if (spins >= 0) { - if (ThreadLocalRandom.nextSecondarySeed() >= 0) + private int lockRunState() { + int rs; + return ((((rs = runState) & RSLOCK) != 0 || + !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ? + awaitRunStateLock() : rs); + } + + /** + * Spins and/or blocks until runstate lock is available. See + * above for explanation. + */ + private int awaitRunStateLock() { + Object lock; + boolean wasInterrupted = false; + for (int spins = SPINS, r = 0, rs, ns;;) { + if (((rs = runState) & RSLOCK) == 0) { + if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK)) { + if (wasInterrupted) { + try { + Thread.currentThread().interrupt(); + } catch (SecurityException ignore) { + } + } + return ns; + } + } + else if (r == 0) + r = ThreadLocalRandom.nextSecondarySeed(); + else if (spins > 0) { + r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // xorshift + if (r >= 0) --spins; } - else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) { - synchronized (this) { - if ((plock & PL_SIGNAL) != 0) { + else if ((rs & STARTED) == 0 || (lock = stealCounter) == null) + Thread.yield(); // initialization race + else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) { + synchronized (lock) { + if ((runState & RSIGNAL) != 0) { try { - wait(); + lock.wait(); } catch (InterruptedException ie) { - try { - Thread.currentThread().interrupt(); - } catch (SecurityException ignore) { - } + if (!(Thread.currentThread() instanceof + ForkJoinWorkerThread)) + wasInterrupted = true; } } else - notifyAll(); + lock.notifyAll(); } } } } /** - * Unlocks and signals any thread waiting for plock. Called only - * when CAS of seq value for unlock fails. + * Unlocks and sets runState to newRunState. + * + * @param oldRunState a value returned from lockRunState + * @param newRunState the next value (must have lock bit clear). */ - private void releasePlock(int ps) { - plock = ps; - synchronized (this) { notifyAll(); } - } - - /** - * Tries to create and start one worker if fewer than target - * parallelism level exist. Adjusts counts etc on failure. - */ - private void tryAddWorker() { - long c; int u, e; - while ((u = (int)((c = ctl) >>> 32)) < 0 && - (u & SHORT_SIGN) != 0 && (e = (int)c) >= 0) { - long nc = ((long)(((u + UTC_UNIT) & UTC_MASK) | - ((u + UAC_UNIT) & UAC_MASK)) << 32) | (long)e; - if (U.compareAndSwapLong(this, CTL, c, nc)) { - ForkJoinWorkerThreadFactory fac; - Throwable ex = null; - ForkJoinWorkerThread wt = null; - try { - if ((fac = factory) != null && - (wt = fac.newThread(this)) != null) { - wt.start(); - break; - } - } catch (Throwable rex) { - ex = rex; - } - deregisterWorker(wt, ex); - break; - } + private void unlockRunState(int oldRunState, int newRunState) { + if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState)) { + Object lock = stealCounter; + runState = newRunState; // clears RSIGNAL bit + if (lock != null) + synchronized (lock) { lock.notifyAll(); } } } - // Registering and deregistering workers + // Creating, registering and deregistering workers /** - * Callback from ForkJoinWorkerThread to establish and record its - * WorkQueue. To avoid scanning bias due to packing entries in - * front of the workQueues array, we treat the array as a simple - * power-of-two hash table using per-thread seed as hash, - * expanding as needed. + * Tries to construct and start one worker. Assumes that total + * count has already been incremented as a reservation. Invokes + * deregisterWorker on any failure. + * + * @return true if successful + */ + private boolean createWorker() { + ForkJoinWorkerThreadFactory fac = factory; + Throwable ex = null; + ForkJoinWorkerThread wt = null; + try { + if (fac != null && (wt = fac.newThread(this)) != null) { + wt.start(); + return true; + } + } catch (Throwable rex) { + ex = rex; + } + deregisterWorker(wt, ex); + return false; + } + + /** + * Tries to add one worker, incrementing ctl counts before doing + * so, relying on createWorker to back out on failure. + * + * @param c incoming ctl value, with total count negative and no + * idle workers. On CAS failure, c is refreshed and retried if + * this holds (otherwise, a new worker is not needed). + */ + private void tryAddWorker(long c) { + boolean add = false; + do { + long nc = ((AC_MASK & (c + AC_UNIT)) | + (TC_MASK & (c + TC_UNIT))); + if (ctl == c) { + int rs, stop; // check if terminating + if ((stop = (rs = lockRunState()) & STOP) == 0) + add = U.compareAndSwapLong(this, CTL, c, nc); + unlockRunState(rs, rs & ~RSLOCK); + if (stop != 0) + break; + if (add) { + createWorker(); + break; + } + } + } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0); + } + + /** + * Callback from ForkJoinWorkerThread constructor to establish and + * record its WorkQueue. * * @param wt the worker thread * @return the worker's queue */ final WorkQueue registerWorker(ForkJoinWorkerThread wt) { - UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps; - wt.setDaemon(true); + UncaughtExceptionHandler handler; + wt.setDaemon(true); // configure thread if ((handler = ueh) != null) wt.setUncaughtExceptionHandler(handler); - do {} while (!U.compareAndSwapInt(this, INDEXSEED, s = indexSeed, - s += SEED_INCREMENT) || - s == 0); // skip 0 - WorkQueue w = new WorkQueue(this, wt, mode, s); - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + WorkQueue w = new WorkQueue(this, wt); + int i = 0; // assign a pool index + int mode = config & MODE_MASK; + int rs = lockRunState(); try { - if ((ws = workQueues) != null) { // skip if shutting down - int n = ws.length, m = n - 1; - int r = (s << 1) | 1; // use odd-numbered indices - if (ws[r &= m] != null) { // collision - int probes = 0; // step by approx half size + WorkQueue[] ws; int n; // skip if no array + if ((ws = workQueues) != null && (n = ws.length) > 0) { + int s = indexSeed += SEED_INCREMENT; // unlikely to collide + int m = n - 1; + i = ((s << 1) | 1) & m; // odd-numbered indices + if (ws[i] != null) { // collision + int probes = 0; // step by approx half n int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; - while (ws[r = (r + step) & m] != null) { + while (ws[i = (i + step) & m] != null) { if (++probes >= n) { workQueues = ws = Arrays.copyOf(ws, n <<= 1); m = n - 1; @@ -1387,15 +1556,15 @@ public class ForkJoinPool extends AbstractExecutorService { } } } - w.poolIndex = (short)r; - w.eventCount = r; // volatile write orders - ws[r] = w; + w.hint = s; // use as random seed + w.config = i | mode; + w.scanState = i; // publication fence + ws[i] = w; } } finally { - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); + unlockRunState(rs, rs & ~RSLOCK); } - wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex >>> 1))); + wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1))); return w; } @@ -1411,384 +1580,322 @@ public class ForkJoinPool extends AbstractExecutorService { final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) { WorkQueue w = null; if (wt != null && (w = wt.workQueue) != null) { - int ps; - w.qlock = -1; // ensure set - U.getAndAddLong(this, STEALCOUNT, w.nsteals); // collect steals - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - try { - int idx = w.poolIndex; - WorkQueue[] ws = workQueues; - if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w) - ws[idx] = null; - } finally { - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); - } + WorkQueue[] ws; // remove index from array + int idx = w.config & SMASK; + int rs = lockRunState(); + if ((ws = workQueues) != null && ws.length > idx && ws[idx] == w) + ws[idx] = null; + unlockRunState(rs, rs & ~RSLOCK); } - - long c; // adjust ctl counts + long c; // decrement counts do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) | - ((c - TC_UNIT) & TC_MASK) | - (c & ~(AC_MASK|TC_MASK))))); - - if (!tryTerminate(false, false) && w != null && w.array != null) { - w.cancelAll(); // cancel remaining tasks - WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e; - while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) { - if (e > 0) { // activate or create replacement - if ((ws = workQueues) == null || - (i = e & SMASK) >= ws.length || - (v = ws[i]) == null) - break; - long nc = (((long)(v.nextWait & E_MASK)) | - ((long)(u + UAC_UNIT) << 32)); - if (v.eventCount != (e | INT_SIGN)) - break; - if (U.compareAndSwapLong(this, CTL, c, nc)) { - v.eventCount = (e + E_SEQ) & E_MASK; - if ((p = v.parker) != null) - U.unpark(p); - break; - } - } - else { - if ((short)u < 0) - tryAddWorker(); - break; - } - } + (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) | + (TC_MASK & (c - TC_UNIT)) | + (SP_MASK & c)))); + if (w != null) { + w.qlock = -1; // ensure set + w.transferStealCount(this); + w.cancelAll(); // cancel remaining tasks } - if (ex == null) // help clean refs on way out + for (;;) { // possibly replace + WorkQueue[] ws; int m, sp; + if (tryTerminate(false, false) || w == null || w.array == null || + (runState & STOP) != 0 || (ws = workQueues) == null || + (m = ws.length - 1) < 0) // already terminating + break; + if ((sp = (int)(c = ctl)) != 0) { // wake up replacement + if (tryRelease(c, ws[sp & m], AC_UNIT)) + break; + } + else if (ex != null && (c & ADD_WORKER) != 0L) { + tryAddWorker(c); // create replacement + break; + } + else // don't need replacement + break; + } + if (ex == null) // help clean on way out ForkJoinTask.helpExpungeStaleExceptions(); - else // rethrow + else // rethrow ForkJoinTask.rethrow(ex); } - // Submissions - - /** - * Unless shutting down, adds the given task to a submission queue - * at submitter's current queue index (modulo submission - * range). Only the most common path is directly handled in this - * method. All others are relayed to fullExternalPush. - * - * @param task the task. Caller must ensure non-null. - */ - final void externalPush(ForkJoinTask task) { - WorkQueue q; int m, s, n, am; ForkJoinTask[] a; - int r = ThreadLocalRandom.getProbe(); - int ps = plock; - WorkQueue[] ws = workQueues; - if (ps > 0 && ws != null && (m = (ws.length - 1)) >= 0 && - (q = ws[m & r & SQMASK]) != null && r != 0 && - U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock - if ((a = q.array) != null && - (am = a.length - 1) > (n = (s = q.top) - q.base)) { - int j = ((am & s) << ASHIFT) + ABASE; - U.putOrderedObject(a, j, task); - q.top = s + 1; // push on to deque - q.qlock = 0; - if (n <= 1) - signalWork(ws, q); - return; - } - q.qlock = 0; - } - fullExternalPush(task); - } - - /** - * Full version of externalPush. This method is called, among - * other times, upon the first submission of the first task to the - * pool, so must perform secondary initialization. It also - * detects first submission by an external thread by looking up - * its ThreadLocal, and creates a new shared queue if the one at - * index if empty or contended. The plock lock body must be - * exception-free (so no try/finally) so we optimistically - * allocate new queues outside the lock and throw them away if - * (very rarely) not needed. - * - * Secondary initialization occurs when plock is zero, to create - * workQueue array and set plock to a valid value. This lock body - * must also be exception-free. Because the plock seq value can - * eventually wrap around zero, this method harmlessly fails to - * reinitialize if workQueues exists, while still advancing plock. - */ - private void fullExternalPush(ForkJoinTask task) { - int r; - if ((r = ThreadLocalRandom.getProbe()) == 0) { - ThreadLocalRandom.localInit(); - r = ThreadLocalRandom.getProbe(); - } - for (;;) { - WorkQueue[] ws; WorkQueue q; int ps, m, k; - boolean move = false; - if ((ps = plock) < 0) - throw new RejectedExecutionException(); - else if (ps == 0 || (ws = workQueues) == null || - (m = ws.length - 1) < 0) { // initialize workQueues - int p = parallelism; // find power of two table size - int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots - n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; - n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; - WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ? - new WorkQueue[n] : null); - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (((ws = workQueues) == null || ws.length == 0) && nws != null) - workQueues = nws; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); - } - else if ((q = ws[k = r & m & SQMASK]) != null) { - if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { - ForkJoinTask[] a = q.array; - int s = q.top; - boolean submitted = false; - try { // locked version of push - if ((a != null && a.length > s + 1 - q.base) || - (a = q.growArray()) != null) { // must presize - int j = (((a.length - 1) & s) << ASHIFT) + ABASE; - U.putOrderedObject(a, j, task); - q.top = s + 1; - submitted = true; - } - } finally { - q.qlock = 0; // unlock - } - if (submitted) { - signalWork(ws, q); - return; - } - } - move = true; // move on failure - } - else if (((ps = plock) & PL_LOCK) == 0) { // create new queue - q = new WorkQueue(this, null, SHARED_QUEUE, r); - q.poolIndex = (short)k; - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if ((ws = workQueues) != null && k < ws.length && ws[k] == null) - ws[k] = q; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); - } - else - move = true; // move if busy - if (move) - r = ThreadLocalRandom.advanceProbe(r); - } - } - - // Maintaining ctl counts - - /** - * Increments active count; mainly called upon return from blocking. - */ - final void incrementActiveCount() { - long c; - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); - } + // Signalling /** * Tries to create or activate a worker if too few are active. * * @param ws the worker array to use to find signallees - * @param q if non-null, the queue holding tasks to be processed + * @param q a WorkQueue --if non-null, don't retry if now empty */ final void signalWork(WorkQueue[] ws, WorkQueue q) { - for (;;) { - long c; int e, u, i; WorkQueue w; Thread p; - if ((u = (int)((c = ctl) >>> 32)) >= 0) - break; - if ((e = (int)c) <= 0) { - if ((short)u < 0) - tryAddWorker(); + long c; int sp, i; WorkQueue v; Thread p; + while ((c = ctl) < 0L) { // too few active + if ((sp = (int)c) == 0) { // no idle workers + if ((c & ADD_WORKER) != 0L) // too few workers + tryAddWorker(c); break; } - if (ws == null || ws.length <= (i = e & SMASK) || - (w = ws[i]) == null) + if (ws == null) // unstarted/terminated break; - long nc = (((long)(w.nextWait & E_MASK)) | - ((long)(u + UAC_UNIT)) << 32); - int ne = (e + E_SEQ) & E_MASK; - if (w.eventCount == (e | INT_SIGN) && - U.compareAndSwapLong(this, CTL, c, nc)) { - w.eventCount = ne; - if ((p = w.parker) != null) + if (ws.length <= (i = sp & SMASK)) // terminated + break; + if ((v = ws[i]) == null) // terminating + break; + int vs = (sp + SS_SEQ) & ~INACTIVE; // next scanState + int d = sp - v.scanState; // screen CAS + long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred); + if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) { + v.scanState = vs; // activate v + if ((p = v.parker) != null) U.unpark(p); break; } - if (q != null && q.base >= q.top) + if (q != null && q.base == q.top) // no more work break; } } + /** + * Signals and releases worker v if it is top of idle worker + * stack. This performs a one-shot version of signalWork only if + * there is (apparently) at least one idle worker. + * + * @param c incoming ctl value + * @param v if non-null, a worker + * @param inc the increment to active count (zero when compensating) + * @return true if successful + */ + private boolean tryRelease(long c, WorkQueue v, long inc) { + int sp = (int)c, vs = (sp + SS_SEQ) & ~INACTIVE; Thread p; + if (v != null && v.scanState == sp) { // v is at top of stack + long nc = (UC_MASK & (c + inc)) | (SP_MASK & v.stackPred); + if (U.compareAndSwapLong(this, CTL, c, nc)) { + v.scanState = vs; + if ((p = v.parker) != null) + U.unpark(p); + return true; + } + } + return false; + } + // Scanning for tasks /** * Top-level runloop for workers, called by ForkJoinWorkerThread.run. */ final void runWorker(WorkQueue w) { - w.growArray(); // allocate queue - for (int r = w.hint; scan(w, r) == 0; ) { + w.growArray(); // allocate queue + int seed = w.hint; // initially holds randomization hint + int r = (seed == 0) ? 1 : seed; // avoid 0 for xorShift + for (ForkJoinTask t;;) { + if ((t = scan(w, r)) != null) + w.runTask(t); + else if (!awaitWork(w, r)) + break; r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift } } /** - * Scans for and, if found, runs one task, else possibly - * inactivates the worker. This method operates on single reads of - * volatile state and is designed to be re-invoked continuously, - * in part because it returns upon detecting inconsistencies, - * contention, or state changes that indicate possible success on - * re-invocation. - * - * The scan searches for tasks across queues starting at a random - * index, checking each at least twice. The scan terminates upon - * either finding a non-empty queue, or completing the sweep. If - * the worker is not inactivated, it takes and runs a task from - * this queue. Otherwise, if not activated, it tries to activate - * itself or some other worker by signalling. On failure to find a - * task, returns (for retry) if pool state may have changed during - * an empty scan, or tries to inactivate if active, else possibly - * blocks or terminates via method awaitWork. + * Scans for and tries to steal a top-level task. Scans start at a + * random location, randomly moving on apparent contention, + * otherwise continuing linearly until reaching two consecutive + * empty passes over all queues with the same checksum (summing + * each base index of each queue, that moves on each steal), at + * which point the worker tries to inactivate and then re-scans, + * attempting to re-activate (itself or some other worker) if + * finding a task; otherwise returning null to await work. Scans + * otherwise touch as little memory as possible, to reduce + * disruption on other scanning threads. * * @param w the worker (via its WorkQueue) * @param r a random seed - * @return worker qlock status if would have waited, else 0 + * @return a task, or null if none found */ - private final int scan(WorkQueue w, int r) { + private ForkJoinTask scan(WorkQueue w, int r) { WorkQueue[] ws; int m; - long c = ctl; // for consistency check - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && w != null) { - for (int j = m + m + 1, ec = w.eventCount;;) { - WorkQueue q; int b, e; ForkJoinTask[] a; ForkJoinTask t; - if ((q = ws[(r - j) & m]) != null && - (b = q.base) - q.top < 0 && (a = q.array) != null) { - long i = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((t = ((ForkJoinTask) - U.getObjectVolatile(a, i))) != null) { - if (ec < 0) - helpRelease(c, ws, w, q, b); - else if (q.base == b && - U.compareAndSwapObject(a, i, t, null)) { - U.putOrderedInt(q, QBASE, b + 1); - if ((b + 1) - q.top < 0) - signalWork(ws, q); - w.runTask(t); + if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) { + int ss = w.scanState; // initially non-negative + for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) { + WorkQueue q; ForkJoinTask[] a; ForkJoinTask t; + int b, n; long c; + if ((q = ws[k]) != null) { + if ((n = (b = q.base) - q.top) < 0 && + (a = q.array) != null) { // non-empty + long i = (((a.length - 1) & b) << ASHIFT) + ABASE; + if ((t = ((ForkJoinTask) + U.getObjectVolatile(a, i))) != null && + q.base == b) { + if (ss >= 0) { + if (U.compareAndSwapObject(a, i, t, null)) { + q.base = b + 1; + if (n < -1) // signal others + signalWork(ws, q); + return t; + } + } + else if (oldSum == 0 && // try to activate + w.scanState < 0) + tryRelease(c = ctl, ws[m & (int)c], AC_UNIT); } + if (ss < 0) // refresh + ss = w.scanState; + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; + origin = k = r & m; // move and rescan + oldSum = checkSum = 0; + continue; } - break; + checkSum += b; } - else if (--j < 0) { - if ((ec | (e = (int)c)) < 0) // inactive or terminating - return awaitWork(w, c, ec); - else if (ctl == c) { // try to inactivate and enqueue - long nc = (long)ec | ((c - AC_UNIT) & (AC_MASK|TC_MASK)); - w.nextWait = e; - w.eventCount = ec | INT_SIGN; - if (!U.compareAndSwapLong(this, CTL, c, nc)) - w.eventCount = ec; // back out + if ((k = (k + 1) & m) == origin) { // continue until stable + if ((ss >= 0 || (ss == (ss = w.scanState))) && + oldSum == (oldSum = checkSum)) { + if (ss < 0 || w.qlock < 0) // already inactive + break; + int ns = ss | INACTIVE; // try to inactivate + long nc = ((SP_MASK & ns) | + (UC_MASK & ((c = ctl) - AC_UNIT))); + w.stackPred = (int)c; // hold prev stack top + U.putInt(w, QSCANSTATE, ns); + if (U.compareAndSwapLong(this, CTL, c, nc)) + ss = ns; + else + w.scanState = ss; // back out } - break; + checkSum = 0; } } } - return 0; + return null; } /** - * A continuation of scan(), possibly blocking or terminating - * worker w. Returns without blocking if pool state has apparently - * changed since last invocation. Also, if inactivating w has - * caused the pool to become quiescent, checks for pool + * Possibly blocks worker w waiting for a task to steal, or + * returns false if the worker should terminate. If inactivating + * w has caused the pool to become quiescent, checks for pool * termination, and, so long as this is not the only worker, waits - * for event for up to a given duration. On timeout, if ctl has - * not changed, terminates the worker, which will in turn wake up + * for up to a given duration. On timeout, if ctl has not + * changed, terminates the worker, which will in turn wake up * another worker to possibly repeat this process. * * @param w the calling worker - * @param c the ctl value on entry to scan - * @param ec the worker's eventCount on entry to scan + * @param r a random seed (for spins) + * @return false if the worker should terminate */ - private final int awaitWork(WorkQueue w, long c, int ec) { - int stat, ns; long parkTime, deadline; - if ((stat = w.qlock) >= 0 && w.eventCount == ec && ctl == c && - !Thread.interrupted()) { - int e = (int)c; - int u = (int)(c >>> 32); - int d = (u >> UAC_SHIFT) + parallelism; // active count - - if (e < 0 || (d <= 0 && tryTerminate(false, false))) - stat = w.qlock = -1; // pool is terminating - else if ((ns = w.nsteals) != 0) { // collect steals and retry - w.nsteals = 0; - U.getAndAddLong(this, STEALCOUNT, (long)ns); + private boolean awaitWork(WorkQueue w, int r) { + if (w == null || w.qlock < 0) // w is terminating + return false; + for (int pred = w.stackPred, spins = SPINS, ss;;) { + if ((ss = w.scanState) >= 0) + break; + else if (spins > 0) { + r ^= r << 6; r ^= r >>> 21; r ^= r << 7; + if (r >= 0 && --spins == 0) { // randomize spins + WorkQueue v; WorkQueue[] ws; int s, j; AtomicLong sc; + if (pred != 0 && (ws = workQueues) != null && + (j = pred & SMASK) < ws.length && + (v = ws[j]) != null && // see if pred parking + (v.parker == null || v.scanState >= 0)) + spins = SPINS; // continue spinning + } } - else { - long pc = ((d > 0 || ec != (e | INT_SIGN)) ? 0L : - ((long)(w.nextWait & E_MASK)) | // ctl to restore - ((long)(u + UAC_UNIT)) << 32); - if (pc != 0L) { // timed wait if last waiter - int dc = -(short)(c >>> TC_SHIFT); - parkTime = (dc < 0 ? FAST_IDLE_TIMEOUT: - (dc + 1) * IDLE_TIMEOUT); + else if (w.qlock < 0) // recheck after spins + return false; + else if (!Thread.interrupted()) { + long c, prevctl, parkTime, deadline; + int ac = (int)((c = ctl) >> AC_SHIFT) + (config & SMASK); + if ((ac <= 0 && tryTerminate(false, false)) || + (runState & STOP) != 0) // pool terminating + return false; + if (ac <= 0 && ss == (int)c) { // is last waiter + prevctl = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & pred); + int t = (short)(c >>> TC_SHIFT); // shrink excess spares + if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl)) + return false; // else use timed wait + parkTime = IDLE_TIMEOUT * ((t >= 0) ? 1 : 1 - t); deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; } else - parkTime = deadline = 0L; - if (w.eventCount == ec && ctl == c) { - Thread wt = Thread.currentThread(); - U.putObject(wt, PARKBLOCKER, this); - w.parker = wt; // emulate LockSupport.park - if (w.eventCount == ec && ctl == c) - U.park(false, parkTime); // must recheck before park - w.parker = null; - U.putObject(wt, PARKBLOCKER, null); - if (parkTime != 0L && ctl == c && - deadline - System.nanoTime() <= 0L && - U.compareAndSwapLong(this, CTL, c, pc)) - stat = w.qlock = -1; // shrink pool + prevctl = parkTime = deadline = 0L; + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport + w.parker = wt; + if (w.scanState < 0 && ctl == c) // recheck before park + U.park(false, parkTime); + U.putOrderedObject(w, QPARKER, null); + U.putObject(wt, PARKBLOCKER, null); + if (w.scanState >= 0) + break; + if (parkTime != 0L && ctl == c && + deadline - System.nanoTime() <= 0L && + U.compareAndSwapLong(this, CTL, c, prevctl)) + return false; // shrink pool + } + } + return true; + } + + // Joining tasks + + /** + * Tries to steal and run tasks within the target's computation. + * Uses a variant of the top-level algorithm, restricted to tasks + * with the given task as ancestor: It prefers taking and running + * eligible tasks popped from the worker's own queue (via + * popCC). Otherwise it scans others, randomly moving on + * contention or execution, deciding to give up based on a + * checksum (via return codes frob pollAndExecCC). The maxTasks + * argument supports external usages; internal calls use zero, + * allowing unbounded steps (external calls trap non-positive + * values). + * + * @param w caller + * @param maxTasks if non-zero, the maximum number of other tasks to run + * @return task status on exit + */ + final int helpComplete(WorkQueue w, CountedCompleter task, + int maxTasks) { + WorkQueue[] ws; int s = 0, m; + if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && + task != null && w != null) { + int mode = w.config; // for popCC + int r = w.hint ^ w.top; // arbitrary seed for origin + int origin = r & m; // first queue to scan + int h = 1; // 1:ran, >1:contended, <0:hash + for (int k = origin, oldSum = 0, checkSum = 0;;) { + CountedCompleter p; WorkQueue q; + if ((s = task.status) < 0) + break; + if (h == 1 && (p = w.popCC(task, mode)) != null) { + p.doExec(); // run local task + if (maxTasks != 0 && --maxTasks == 0) + break; + origin = k; // reset + oldSum = checkSum = 0; + } + else { // poll other queues + if ((q = ws[k]) == null) + h = 0; + else if ((h = q.pollAndExecCC(task)) < 0) + checkSum += h; + if (h > 0) { + if (h == 1 && maxTasks != 0 && --maxTasks == 0) + break; + r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift + origin = k = r & m; // move and restart + oldSum = checkSum = 0; + } + else if ((k = (k + 1) & m) == origin) { + if (oldSum == (oldSum = checkSum)) + break; + checkSum = 0; + } } } } - return stat; - } - - /** - * Possibly releases (signals) a worker. Called only from scan() - * when a worker with apparently inactive status finds a non-empty - * queue. This requires revalidating all of the associated state - * from caller. - */ - private final void helpRelease(long c, WorkQueue[] ws, WorkQueue w, - WorkQueue q, int b) { - WorkQueue v; int e, i; Thread p; - if (w != null && w.eventCount < 0 && (e = (int)c) > 0 && - ws != null && ws.length > (i = e & SMASK) && - (v = ws[i]) != null && ctl == c) { - long nc = (((long)(v.nextWait & E_MASK)) | - ((long)((int)(c >>> 32) + UAC_UNIT)) << 32); - int ne = (e + E_SEQ) & E_MASK; - if (q != null && q.base == b && w.eventCount < 0 && - v.eventCount == (e | INT_SIGN) && - U.compareAndSwapLong(this, CTL, c, nc)) { - v.eventCount = ne; - if ((p = v.parker) != null) - U.unpark(p); - } - } + return s; } /** @@ -1799,268 +1906,167 @@ public class ForkJoinPool extends AbstractExecutorService { * execute tasks from. The first call to this method upon a * waiting join will often entail scanning/search, (which is OK * because the joiner has nothing better to do), but this method - * leaves hints in workers to speed up subsequent calls. The - * implementation is very branchy to cope with potential - * inconsistencies or loops encountering chains that are stale, - * unknown, or so long that they are likely cyclic. + * leaves hints in workers to speed up subsequent calls. * - * @param joiner the joining worker + * @param w caller * @param task the task to join - * @return 0 if no progress can be made, negative if task - * known complete, else positive */ - private int tryHelpStealer(WorkQueue joiner, ForkJoinTask task) { - int stat = 0, steps = 0; // bound to avoid cycles - if (task != null && joiner != null && - joiner.base - joiner.top >= 0) { // hoist checks - restart: for (;;) { - ForkJoinTask subtask = task; // current target - for (WorkQueue j = joiner, v;;) { // v is stealer of subtask - WorkQueue[] ws; int m, s, h; - if ((s = task.status) < 0) { - stat = s; - break restart; - } - if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) - break restart; // shutting down - if ((v = ws[h = (j.hint | 1) & m]) == null || - v.currentSteal != subtask) { - for (int origin = h;;) { // find stealer - if (((h = (h + 2) & m) & 15) == 1 && - (subtask.status < 0 || j.currentJoin != subtask)) - continue restart; // occasional staleness check - if ((v = ws[h]) != null && - v.currentSteal == subtask) { - j.hint = h; // save hint + private void helpStealer(WorkQueue w, ForkJoinTask task) { + WorkQueue[] ws = workQueues; + int oldSum = 0, checkSum, m; + if (ws != null && (m = ws.length - 1) >= 0 && w != null && + task != null) { + do { // restart point + checkSum = 0; // for stability check + ForkJoinTask subtask; + WorkQueue j = w, v; // v is subtask stealer + descent: for (subtask = task; subtask.status >= 0; ) { + for (int h = j.hint | 1, k = 0, i; ; k += 2) { + if (k > m) // can't find stealer + break descent; + if ((v = ws[i = (h + k) & m]) != null) { + if (v.currentSteal == subtask) { + j.hint = i; break; } - if (h == origin) - break restart; // cannot find stealer + checkSum += v.base; } } - for (;;) { // help stealer or descend to its stealer + for (;;) { // help v or descend ForkJoinTask[] a; int b; - if (subtask.status < 0) // surround probes with - continue restart; // consistency checks - if ((b = v.base) - v.top < 0 && (a = v.array) != null) { - int i = (((a.length - 1) & b) << ASHIFT) + ABASE; - ForkJoinTask t = - (ForkJoinTask)U.getObjectVolatile(a, i); - if (subtask.status < 0 || j.currentJoin != subtask || - v.currentSteal != subtask) - continue restart; // stale - stat = 1; // apparent progress - if (v.base == b) { - if (t == null) - break restart; - if (U.compareAndSwapObject(a, i, t, null)) { - U.putOrderedInt(v, QBASE, b + 1); - ForkJoinTask ps = joiner.currentSteal; - int jt = joiner.top; - do { - joiner.currentSteal = t; - t.doExec(); // clear local tasks too - } while (task.status >= 0 && - joiner.top != jt && - (t = joiner.pop()) != null); - joiner.currentSteal = ps; - break restart; - } - } + checkSum += (b = v.base); + ForkJoinTask next = v.currentJoin; + if (subtask.status < 0 || j.currentJoin != subtask || + v.currentSteal != subtask) // stale + break descent; + if (b - v.top >= 0 || (a = v.array) == null) { + if ((subtask = next) == null) + break descent; + j = v; + break; } - else { // empty -- try to descend - ForkJoinTask next = v.currentJoin; - if (subtask.status < 0 || j.currentJoin != subtask || - v.currentSteal != subtask) - continue restart; // stale - else if (next == null || ++steps == MAX_HELP) - break restart; // dead-end or maybe cyclic - else { - subtask = next; - j = v; - break; + int i = (((a.length - 1) & b) << ASHIFT) + ABASE; + ForkJoinTask t = ((ForkJoinTask) + U.getObjectVolatile(a, i)); + if (v.base == b) { + if (t == null) // stale + break descent; + if (U.compareAndSwapObject(a, i, t, null)) { + v.base = b + 1; + ForkJoinTask ps = w.currentSteal; + int top = w.top; + do { + U.putOrderedObject(w, QCURRENTSTEAL, t); + t.doExec(); // clear local tasks too + } while (task.status >= 0 && + w.top != top && + (t = w.pop()) != null); + U.putOrderedObject(w, QCURRENTSTEAL, ps); + if (w.base != w.top) + return; // can't further help } } } } - } + } while (task.status >= 0 && oldSum != (oldSum = checkSum)); } - return stat; - } - - /** - * Analog of tryHelpStealer for CountedCompleters. Tries to steal - * and run tasks within the target's computation. - * - * @param task the task to join - * @param maxTasks the maximum number of other tasks to run - */ - final int helpComplete(WorkQueue joiner, CountedCompleter task, - int maxTasks) { - WorkQueue[] ws; int m; - int s = 0; - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && - joiner != null && task != null) { - int j = joiner.poolIndex; - int scans = m + m + 1; - long c = 0L; // for stability check - for (int k = scans; ; j += 2) { - WorkQueue q; - if ((s = task.status) < 0) - break; - else if (joiner.internalPopAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if ((s = task.status) < 0) - break; - else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if (--k < 0) { - if (c == (c = ctl)) - break; - k = scans; - } - } - } - return s; } /** * Tries to decrement active count (sometimes implicitly) and * possibly release or create a compensating worker in preparation - * for blocking. Fails on contention or termination. Otherwise, - * adds a new thread if no idle workers are available and pool - * may become starved. + * for blocking. Returns false (retryable by caller), on + * contention, detected staleness, instability, or termination. * - * @param c the assumed ctl value + * @param w caller */ - final boolean tryCompensate(long c) { - WorkQueue[] ws = workQueues; - int pc = parallelism, e = (int)c, m, tc; - if (ws != null && (m = ws.length - 1) >= 0 && e >= 0 && ctl == c) { - WorkQueue w = ws[e & m]; - if (e != 0 && w != null) { - Thread p; - long nc = ((long)(w.nextWait & E_MASK) | - (c & (AC_MASK|TC_MASK))); - int ne = (e + E_SEQ) & E_MASK; - if (w.eventCount == (e | INT_SIGN) && - U.compareAndSwapLong(this, CTL, c, nc)) { - w.eventCount = ne; - if ((p = w.parker) != null) - U.unpark(p); - return true; // replace with idle worker + private boolean tryCompensate(WorkQueue w) { + boolean canBlock; + WorkQueue[] ws; long c; int m, pc, sp; + if (w == null || w.qlock < 0 || // caller terminating + (ws = workQueues) == null || (m = ws.length - 1) <= 0 || + (pc = config & SMASK) == 0) // parallelism disabled + canBlock = false; + else if ((sp = (int)(c = ctl)) != 0) // release idle worker + canBlock = tryRelease(c, ws[sp & m], 0L); + else { + int ac = (int)(c >> AC_SHIFT) + pc; + int tc = (short)(c >> TC_SHIFT) + pc; + int nbusy = 0; // validate saturation + for (int i = 0; i <= m; ++i) { // two passes of odd indices + WorkQueue v; + if ((v = ws[((i << 1) | 1) & m]) != null) { + if ((v.scanState & SCANNING) != 0) + break; + ++nbusy; } } - else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 && - (int)(c >> AC_SHIFT) + pc > 1) { - long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK); - if (U.compareAndSwapLong(this, CTL, c, nc)) - return true; // no compensation + if (nbusy != (tc << 1) || ctl != c) + canBlock = false; // unstable or stale + else if (tc >= pc && ac > 1 && w.isEmpty()) { + long nc = ((AC_MASK & (c - AC_UNIT)) | + (~AC_MASK & c)); // uncompensated + canBlock = U.compareAndSwapLong(this, CTL, c, nc); } - else if (tc + pc < MAX_CAP) { - long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); - if (U.compareAndSwapLong(this, CTL, c, nc)) { - ForkJoinWorkerThreadFactory fac; - Throwable ex = null; - ForkJoinWorkerThread wt = null; - try { - if ((fac = factory) != null && - (wt = fac.newThread(this)) != null) { - wt.start(); - return true; - } - } catch (Throwable rex) { - ex = rex; - } - deregisterWorker(wt, ex); // clean up and return false - } + else if (tc >= MAX_CAP || + (this == common && tc >= pc + commonMaxSpares)) + throw new RejectedExecutionException( + "Thread limit exceeded replacing blocked worker"); + else { // similar to tryAddWorker + boolean add = false; int rs; // CAS within lock + long nc = ((AC_MASK & c) | + (TC_MASK & (c + TC_UNIT))); + if (((rs = lockRunState()) & STOP) == 0) + add = U.compareAndSwapLong(this, CTL, c, nc); + unlockRunState(rs, rs & ~RSLOCK); + canBlock = add && createWorker(); // throws on exception } } - return false; + return canBlock; } /** - * Helps and/or blocks until the given task is done. + * Helps and/or blocks until the given task is done or timeout. * - * @param joiner the joining worker + * @param w caller * @param task the task + * @param deadline for timed waits, if nonzero * @return task status on exit */ - final int awaitJoin(WorkQueue joiner, ForkJoinTask task) { + final int awaitJoin(WorkQueue w, ForkJoinTask task, long deadline) { int s = 0; - if (task != null && (s = task.status) >= 0 && joiner != null) { - ForkJoinTask prevJoin = joiner.currentJoin; - joiner.currentJoin = task; - do {} while (joiner.tryRemoveAndExec(task) && // process local tasks - (s = task.status) >= 0); - if (s >= 0 && (task instanceof CountedCompleter)) - s = helpComplete(joiner, (CountedCompleter)task, Integer.MAX_VALUE); - long cc = 0; // for stability checks - while (s >= 0 && (s = task.status) >= 0) { - if ((s = tryHelpStealer(joiner, task)) == 0 && - (s = task.status) >= 0) { - if (!tryCompensate(cc)) - cc = ctl; - else { - if (task.trySetSignal() && (s = task.status) >= 0) { - synchronized (task) { - if (task.status >= 0) { - try { // see ForkJoinTask - task.wait(); // for explanation - } catch (InterruptedException ie) { - } - } - else - task.notifyAll(); - } - } - long c; // reactivate - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, - ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); - } + if (task != null && w != null) { + ForkJoinTask prevJoin = w.currentJoin; + U.putOrderedObject(w, QCURRENTJOIN, task); + CountedCompleter cc = (task instanceof CountedCompleter) ? + (CountedCompleter)task : null; + for (;;) { + if ((s = task.status) < 0) + break; + if (cc != null) + helpComplete(w, cc, 0); + else if (w.base == w.top || w.tryRemoveAndExec(task)) + helpStealer(w, task); + if ((s = task.status) < 0) + break; + long ms, ns; + if (deadline == 0L) + ms = 0L; + else if ((ns = deadline - System.nanoTime()) <= 0L) + break; + else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L) + ms = 1L; + if (tryCompensate(w)) { + task.internalWait(ms); + U.getAndAddLong(this, CTL, AC_UNIT); } } - joiner.currentJoin = prevJoin; + U.putOrderedObject(w, QCURRENTJOIN, prevJoin); } return s; } - /** - * Stripped-down variant of awaitJoin used by timed joins. Tries - * to help join only while there is continuous progress. (Caller - * will then enter a timed wait.) - * - * @param joiner the joining worker - * @param task the task - */ - final void helpJoinOnce(WorkQueue joiner, ForkJoinTask task) { - int s; - if (joiner != null && task != null && (s = task.status) >= 0) { - ForkJoinTask prevJoin = joiner.currentJoin; - joiner.currentJoin = task; - do {} while (joiner.tryRemoveAndExec(task) && // process local tasks - (s = task.status) >= 0); - if (s >= 0) { - if (task instanceof CountedCompleter) - helpComplete(joiner, (CountedCompleter)task, Integer.MAX_VALUE); - do {} while (task.status >= 0 && - tryHelpStealer(joiner, task) > 0); - } - joiner.currentJoin = prevJoin; - } - } + // Specialized scanning /** * Returns a (probably) non-empty steal queue, if one is found @@ -2068,19 +2074,24 @@ public class ForkJoinPool extends AbstractExecutorService { * caller if, by the time it tries to use the queue, it is empty. */ private WorkQueue findNonEmptyStealQueue() { + WorkQueue[] ws; int m; // one-shot version of scan loop int r = ThreadLocalRandom.nextSecondarySeed(); - for (;;) { - int ps = plock, m; WorkQueue[] ws; WorkQueue q; - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) { - for (int j = (m + 1) << 2; j >= 0; --j) { - if ((q = ws[(((r - j) << 1) | 1) & m]) != null && - q.base - q.top < 0) + if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) { + for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) { + WorkQueue q; int b; + if ((q = ws[k]) != null) { + if ((b = q.base) - q.top < 0) return q; + checkSum += b; + } + if ((k = (k + 1) & m) == origin) { + if (oldSum == (oldSum = checkSum)) + break; + checkSum = 0; } } - if (plock == ps) - return null; } + return null; } /** @@ -2090,35 +2101,34 @@ public class ForkJoinPool extends AbstractExecutorService { * find tasks either. */ final void helpQuiescePool(WorkQueue w) { - ForkJoinTask ps = w.currentSteal; + ForkJoinTask ps = w.currentSteal; // save context for (boolean active = true;;) { long c; WorkQueue q; ForkJoinTask t; int b; - while ((t = w.nextLocalTask()) != null) - t.doExec(); + w.execLocalTasks(); // run locals before each scan if ((q = findNonEmptyStealQueue()) != null) { if (!active) { // re-establish active count active = true; - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, - ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); + U.getAndAddLong(this, CTL, AC_UNIT); + } + if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) { + U.putOrderedObject(w, QCURRENTSTEAL, t); + t.doExec(); + if (++w.nsteals < 0) + w.transferStealCount(this); } - if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) - w.runTask(t); } else if (active) { // decrement active count without queuing - long nc = ((c = ctl) & ~AC_MASK) | ((c & AC_MASK) - AC_UNIT); - if ((int)(nc >> AC_SHIFT) + parallelism == 0) + long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c); + if ((int)(nc >> AC_SHIFT) + (config & SMASK) <= 0) break; // bypass decrement-then-increment if (U.compareAndSwapLong(this, CTL, c, nc)) active = false; } - else if ((int)((c = ctl) >> AC_SHIFT) + parallelism <= 0 && - U.compareAndSwapLong - (this, CTL, c, ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))) + else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 && + U.compareAndSwapLong(this, CTL, c, c + AC_UNIT)) break; } + U.putOrderedObject(w, QCURRENTSTEAL, ps); } /** @@ -2141,7 +2151,7 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Returns a cheap heuristic guide for task partitioning when * programmers, frameworks, tools, or languages have little or no - * idea about task granularity. In essence by offering this + * idea about task granularity. In essence, by offering this * method, we ask users only about tradeoffs in overhead vs * expected throughput and its variance, rather than how finely to * partition tasks. @@ -2179,15 +2189,12 @@ public class ForkJoinPool extends AbstractExecutorService { * many of these by further considering the number of "idle" * threads, that are known to have zero queued tasks, so * compensate by a factor of (#idle/#active) threads. - * - * Note: The approximation of #busy workers as #active workers is - * not very good under current signalling scheme, and should be - * improved. */ static int getSurplusQueuedTaskCount() { Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q; if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) { - int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).parallelism; + int p = (pool = (wt = (ForkJoinWorkerThread)t).pool). + config & SMASK; int n = (q = wt.workQueue).top - q.base; int a = (int)(pool.ctl >> AC_SHIFT) + p; return n - (a > (p >>>= 1) ? 0 : @@ -2202,13 +2209,7 @@ public class ForkJoinPool extends AbstractExecutorService { // Termination /** - * Possibly initiates and/or completes termination. The caller - * triggering termination runs three passes through workQueues: - * (0) Setting termination status, followed by wakeups of queued - * workers; (1) cancelling all tasks; (2) interrupting lagging - * threads (likely in external tasks, but possibly also blocked in - * joins). Each pass repeats previous steps because of potential - * lagging thread creation. + * Possibly initiates and/or completes termination. * * @param now if true, unconditionally terminate, else only * if no work and no active workers @@ -2216,166 +2217,256 @@ public class ForkJoinPool extends AbstractExecutorService { * @return true if now terminating or terminated */ private boolean tryTerminate(boolean now, boolean enable) { - int ps; - if (this == common) // cannot shut down + int rs; + if (this == common) // cannot shut down return false; - if ((ps = plock) >= 0) { // enable by setting plock + if ((rs = runState) >= 0) { if (!enable) return false; - if ((ps & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN; - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); + rs = lockRunState(); // enter SHUTDOWN phase + unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN); } - for (long c;;) { - if (((c = ctl) & STOP_BIT) != 0) { // already terminating - if ((short)(c >>> TC_SHIFT) + parallelism <= 0) { - synchronized (this) { - notifyAll(); // signal when 0 workers - } - } - return true; - } - if (!now) { // check if idle & no tasks - WorkQueue[] ws; WorkQueue w; - if ((int)(c >> AC_SHIFT) + parallelism > 0) - return false; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; ++i) { - if ((w = ws[i]) != null && - (!w.isEmpty() || - ((i & 1) != 0 && w.eventCount >= 0))) { - signalWork(ws, w); - return false; + + if ((rs & STOP) == 0) { + if (!now) { // check quiescence + for (long oldSum = 0L;;) { // repeat until stable + WorkQueue[] ws; WorkQueue w; int m, b; long c; + long checkSum = ctl; + if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0) + return false; // still active workers + if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) + break; // check queues + for (int i = 0; i <= m; ++i) { + if ((w = ws[i]) != null) { + if ((b = w.base) != w.top || w.scanState >= 0 || + w.currentSteal != null) { + tryRelease(c = ctl, ws[m & (int)c], AC_UNIT); + return false; // arrange for recheck + } + checkSum += b; + if ((i & 1) == 0) + w.qlock = -1; // try to disable external } } + if (oldSum == (oldSum = checkSum)) + break; } } - if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) { - for (int pass = 0; pass < 3; ++pass) { - WorkQueue[] ws; WorkQueue w; Thread wt; - if ((ws = workQueues) != null) { - int n = ws.length; - for (int i = 0; i < n; ++i) { - if ((w = ws[i]) != null) { - w.qlock = -1; - if (pass > 0) { - w.cancelAll(); - if (pass > 1 && (wt = w.owner) != null) { - if (!wt.isInterrupted()) { - try { - wt.interrupt(); - } catch (Throwable ignore) { - } - } - U.unpark(wt); - } + if ((runState & STOP) == 0) { + rs = lockRunState(); // enter STOP phase + unlockRunState(rs, (rs & ~RSLOCK) | STOP); + } + } + + int pass = 0; // 3 passes to help terminate + for (long oldSum = 0L;;) { // or until done or stable + WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt; int m; + long checkSum = ctl; + if ((short)(checkSum >>> TC_SHIFT) + (config & SMASK) <= 0 || + (ws = workQueues) == null || (m = ws.length - 1) <= 0) { + if ((runState & TERMINATED) == 0) { + rs = lockRunState(); // done + unlockRunState(rs, (rs & ~RSLOCK) | TERMINATED); + synchronized (this) { notifyAll(); } // for awaitTermination + } + break; + } + for (int i = 0; i <= m; ++i) { + if ((w = ws[i]) != null) { + checkSum += w.base; + w.qlock = -1; // try to disable + if (pass > 0) { + w.cancelAll(); // clear queue + if (pass > 1 && (wt = w.owner) != null) { + if (!wt.isInterrupted()) { + try { // unblock join + wt.interrupt(); + } catch (Throwable ignore) { } } - } - // Wake up workers parked on event queue - int i, e; long cc; Thread p; - while ((e = (int)(cc = ctl) & E_MASK) != 0 && - (i = e & SMASK) < n && i >= 0 && - (w = ws[i]) != null) { - long nc = ((long)(w.nextWait & E_MASK) | - ((cc + AC_UNIT) & AC_MASK) | - (cc & (TC_MASK|STOP_BIT))); - if (w.eventCount == (e | INT_SIGN) && - U.compareAndSwapLong(this, CTL, cc, nc)) { - w.eventCount = (e + E_SEQ) & E_MASK; - w.qlock = -1; - if ((p = w.parker) != null) - U.unpark(p); - } + if (w.scanState < 0) + U.unpark(wt); // wake up } } } } + if (checkSum != oldSum) { // unstable + oldSum = checkSum; + pass = 0; + } + else if (pass > 3 && pass > m) // can't further help + break; + else if (++pass > 1) { // try to dequeue + long c; int j = 0, sp; // bound attempts + while (j++ <= m && (sp = (int)(c = ctl)) != 0) + tryRelease(c, ws[sp & m], AC_UNIT); + } + } + return true; + } + + // External operations + + /** + * Full version of externalPush, handling uncommon cases, as well + * as performing secondary initialization upon the first + * submission of the first task to the pool. It also detects + * first submission by an external thread and creates a new shared + * queue if the one at index if empty or contended. + * + * @param task the task. Caller must ensure non-null. + */ + private void externalSubmit(ForkJoinTask task) { + int r; // initialize caller's probe + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); + r = ThreadLocalRandom.getProbe(); + } + for (;;) { + WorkQueue[] ws; WorkQueue q; int rs, m, k; + boolean move = false; + if ((rs = runState) < 0) { + tryTerminate(false, false); // help terminate + throw new RejectedExecutionException(); + } + else if ((rs & STARTED) == 0 || // initialize + ((ws = workQueues) == null || (m = ws.length - 1) < 0)) { + int ns = 0; + rs = lockRunState(); + try { + if ((rs & STARTED) == 0) { + U.compareAndSwapObject(this, STEALCOUNTER, null, + new AtomicLong()); + // create workQueues array with size a power of two + int p = config & SMASK; // ensure at least 2 slots + int n = (p > 1) ? p - 1 : 1; + n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; + n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; + workQueues = new WorkQueue[n]; + ns = STARTED; + } + } finally { + unlockRunState(rs, (rs & ~RSLOCK) | ns); + } + } + else if ((q = ws[k = r & m & SQMASK]) != null) { + if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { + ForkJoinTask[] a = q.array; + int s = q.top; + boolean submitted = false; // initial submission or resizing + try { // locked version of push + if ((a != null && a.length > s + 1 - q.base) || + (a = q.growArray()) != null) { + int j = (((a.length - 1) & s) << ASHIFT) + ABASE; + U.putOrderedObject(a, j, task); + U.putOrderedInt(q, QTOP, s + 1); + submitted = true; + } + } finally { + U.compareAndSwapInt(q, QLOCK, 1, 0); + } + if (submitted) { + signalWork(ws, q); + return; + } + } + move = true; // move on failure + } + else if (((rs = runState) & RSLOCK) == 0) { // create new queue + q = new WorkQueue(this, null); + q.hint = r; + q.config = k | SHARED_QUEUE; + q.scanState = INACTIVE; + rs = lockRunState(); // publish index + if (rs > 0 && (ws = workQueues) != null && + k < ws.length && ws[k] == null) + ws[k] = q; // else terminated + unlockRunState(rs, rs & ~RSLOCK); + } + else + move = true; // move if busy + if (move) + r = ThreadLocalRandom.advanceProbe(r); } } - // external operations on common pool + /** + * Tries to add the given task to a submission queue at + * submitter's current queue. Only the (vastly) most common path + * is directly handled in this method, while screening for need + * for externalSubmit. + * + * @param task the task. Caller must ensure non-null. + */ + final void externalPush(ForkJoinTask task) { + WorkQueue[] ws; WorkQueue q; int m; + int r = ThreadLocalRandom.getProbe(); + int rs = runState; + if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 && + (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 && + U.compareAndSwapInt(q, QLOCK, 0, 1)) { + ForkJoinTask[] a; int am, n, s; + if ((a = q.array) != null && + (am = a.length - 1) > (n = (s = q.top) - q.base)) { + int j = ((am & s) << ASHIFT) + ABASE; + U.putOrderedObject(a, j, task); + U.putOrderedInt(q, QTOP, s + 1); + U.putOrderedInt(q, QLOCK, 0); + if (n <= 1) + signalWork(ws, q); + return; + } + U.compareAndSwapInt(q, QLOCK, 1, 0); + } + externalSubmit(task); + } /** - * Returns common pool queue for a thread that has submitted at - * least one task. + * Returns common pool queue for an external thread. */ static WorkQueue commonSubmitterQueue() { - ForkJoinPool p; WorkQueue[] ws; int m, z; - return ((z = ThreadLocalRandom.getProbe()) != 0 && - (p = common) != null && - (ws = p.workQueues) != null && + ForkJoinPool p = common; + int r = ThreadLocalRandom.getProbe(); + WorkQueue[] ws; int m; + return (p != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0) ? - ws[m & z & SQMASK] : null; + ws[m & r & SQMASK] : null; } /** - * Tries to pop the given task from submitter's queue in common pool. + * Performs tryUnpush for an external submitter: Finds queue, + * locks if apparently non-empty, validates upon locking, and + * adjusts top. Each check can fail but rarely does. */ final boolean tryExternalUnpush(ForkJoinTask task) { - WorkQueue joiner; ForkJoinTask[] a; int m, s; - WorkQueue[] ws = workQueues; - int z = ThreadLocalRandom.getProbe(); - boolean popped = false; - if (ws != null && (m = ws.length - 1) >= 0 && - (joiner = ws[z & m & SQMASK]) != null && - joiner.base != (s = joiner.top) && - (a = joiner.array) != null) { + WorkQueue[] ws; WorkQueue w; ForkJoinTask[] a; int m, s; + int r = ThreadLocalRandom.getProbe(); + if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && + (w = ws[m & r & SQMASK]) != null && + (a = w.array) != null && (s = w.top) != w.base) { long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if (U.getObject(a, j) == task && - U.compareAndSwapInt(joiner, QLOCK, 0, 1)) { - if (joiner.top == s && joiner.array == a && + if (U.compareAndSwapInt(w, QLOCK, 0, 1)) { + if (w.top == s && w.array == a && + U.getObject(a, j) == task && U.compareAndSwapObject(a, j, task, null)) { - joiner.top = s - 1; - popped = true; + U.putOrderedInt(w, QTOP, s - 1); + U.putOrderedInt(w, QLOCK, 0); + return true; } - joiner.qlock = 0; + U.compareAndSwapInt(w, QLOCK, 1, 0); } } - return popped; + return false; } + /** + * Performs helpComplete for an external submitter. + */ final int externalHelpComplete(CountedCompleter task, int maxTasks) { - WorkQueue joiner; int m; - WorkQueue[] ws = workQueues; - int j = ThreadLocalRandom.getProbe(); - int s = 0; - if (ws != null && (m = ws.length - 1) >= 0 && - (joiner = ws[j & m & SQMASK]) != null && task != null) { - int scans = m + m + 1; - long c = 0L; // for stability check - j |= 1; // poll odd queues - for (int k = scans; ; j += 2) { - WorkQueue q; - if ((s = task.status) < 0) - break; - else if (joiner.externalPopAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if ((s = task.status) < 0) - break; - else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if (--k < 0) { - if (c == (c = ctl)) - break; - k = scans; - } - } - } - return s; + WorkQueue[] ws; int n; + int r = ThreadLocalRandom.getProbe(); + return ((ws = workQueues) == null || (n = ws.length) == 0) ? 0 : + helpComplete(ws[(n - 1) & r & SQMASK], task, maxTasks); } // Exported methods @@ -2447,7 +2538,7 @@ public class ForkJoinPool extends AbstractExecutorService { this(checkParallelism(parallelism), checkFactory(factory), handler, - (asyncMode ? FIFO_QUEUE : LIFO_QUEUE), + asyncMode ? FIFO_QUEUE : LIFO_QUEUE, "ForkJoinPool-" + nextPoolId() + "-worker-"); checkPermission(); } @@ -2478,8 +2569,7 @@ public class ForkJoinPool extends AbstractExecutorService { this.workerNamePrefix = workerNamePrefix; this.factory = factory; this.ueh = handler; - this.mode = (short)mode; - this.parallelism = (short)parallelism; + this.config = (parallelism & SMASK) | mode; long np = (long)(-parallelism); // offset ctl counts this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); } @@ -2624,7 +2714,7 @@ public class ForkJoinPool extends AbstractExecutorService { // In previous versions of this class, this method constructed // a task to run ForkJoinTask.invokeAll, but now external // invocation of multiple tasks is at least as efficient. - ArrayList> futures = new ArrayList>(tasks.size()); + ArrayList> futures = new ArrayList<>(tasks.size()); boolean done = false; try { @@ -2670,7 +2760,7 @@ public class ForkJoinPool extends AbstractExecutorService { */ public int getParallelism() { int par; - return ((par = parallelism) > 0) ? par : 1; + return ((par = config & SMASK) > 0) ? par : 1; } /** @@ -2692,7 +2782,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of worker threads */ public int getPoolSize() { - return parallelism + (short)(ctl >>> TC_SHIFT); + return (config & SMASK) + (short)(ctl >>> TC_SHIFT); } /** @@ -2702,7 +2792,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if this pool uses async mode */ public boolean getAsyncMode() { - return mode == FIFO_QUEUE; + return (config & FIFO_QUEUE) != 0; } /** @@ -2733,7 +2823,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of active threads */ public int getActiveThreadCount() { - int r = parallelism + (int)(ctl >> AC_SHIFT); + int r = (config & SMASK) + (int)(ctl >> AC_SHIFT); return (r <= 0) ? 0 : r; // suppress momentarily negative values } @@ -2749,7 +2839,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if all threads are currently idle */ public boolean isQuiescent() { - return parallelism + (int)(ctl >> AC_SHIFT) <= 0; + return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0; } /** @@ -2764,7 +2854,8 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of steals */ public long getStealCount() { - long count = stealCount; + AtomicLong sc = stealCounter; + long count = (sc == null) ? 0L : sc.get(); WorkQueue[] ws; WorkQueue w; if ((ws = workQueues) != null) { for (int i = 1; i < ws.length; i += 2) { @@ -2894,7 +2985,8 @@ public class ForkJoinPool extends AbstractExecutorService { public String toString() { // Use a single pass through workQueues to collect counts long qt = 0L, qs = 0L; int rc = 0; - long st = stealCount; + AtomicLong sc = stealCounter; + long st = (sc == null) ? 0L : sc.get(); long c = ctl; WorkQueue[] ws; WorkQueue w; if ((ws = workQueues) != null) { @@ -2912,16 +3004,16 @@ public class ForkJoinPool extends AbstractExecutorService { } } } - int pc = parallelism; + int pc = (config & SMASK); int tc = pc + (short)(c >>> TC_SHIFT); int ac = pc + (int)(c >> AC_SHIFT); if (ac < 0) // ignore transient negative ac = 0; - String level; - if ((c & STOP_BIT) != 0) - level = (tc == 0) ? "Terminated" : "Terminating"; - else - level = plock < 0 ? "Shutting down" : "Running"; + int rs = runState; + String level = ((rs & TERMINATED) != 0 ? "Terminated" : + (rs & STOP) != 0 ? "Terminating" : + (rs & SHUTDOWN) != 0 ? "Shutting down" : + "Running"); return super.toString() + "[" + level + ", parallelism = " + pc + @@ -2983,9 +3075,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if all tasks have completed following shut down */ public boolean isTerminated() { - long c = ctl; - return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) + parallelism <= 0); + return (runState & TERMINATED) != 0; } /** @@ -3002,9 +3092,8 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if terminating but not yet terminated */ public boolean isTerminating() { - long c = ctl; - return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) + parallelism > 0); + int rs = runState; + return (rs & STOP) != 0 && (rs & TERMINATED) == 0; } /** @@ -3013,7 +3102,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if this pool has been shut down */ public boolean isShutdown() { - return plock < 0; + return (runState & SHUTDOWN) != 0; } /** @@ -3090,8 +3179,9 @@ public class ForkJoinPool extends AbstractExecutorService { } found = false; for (int j = (m + 1) << 2; j >= 0; --j) { - ForkJoinTask t; WorkQueue q; int b; - if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) { + ForkJoinTask t; WorkQueue q; int b, k; + if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null && + (b = q.base) - q.top < 0) { found = true; if ((t = q.pollAt(b)) != null) t.doExec(); @@ -3115,8 +3205,8 @@ public class ForkJoinPool extends AbstractExecutorService { * in {@link ForkJoinPool}s. * *

    A {@code ManagedBlocker} provides two methods. Method - * {@code isReleasable} must return {@code true} if blocking is - * not necessary. Method {@code block} blocks the current thread + * {@link #isReleasable} must return {@code true} if blocking is + * not necessary. Method {@link #block} blocks the current thread * if necessary (perhaps internally invoking {@code isReleasable} * before actually blocking). These actions are performed by any * thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}. @@ -3185,37 +3275,46 @@ public class ForkJoinPool extends AbstractExecutorService { } /** - * Blocks in accord with the given blocker. If the current thread - * is a {@link ForkJoinWorkerThread}, this method possibly - * arranges for a spare thread to be activated if necessary to - * ensure sufficient parallelism while the current thread is blocked. + * Runs the given possibly blocking task. When {@linkplain + * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this + * method possibly arranges for a spare thread to be activated if + * necessary to ensure sufficient parallelism while the current + * thread is blocked in {@link ManagedBlocker#block blocker.block()}. * - *

    If the caller is not a {@link ForkJoinTask}, this method is + *

    This method repeatedly calls {@code blocker.isReleasable()} and + * {@code blocker.block()} until either method returns {@code true}. + * Every call to {@code blocker.block()} is preceded by a call to + * {@code blocker.isReleasable()} that returned {@code false}. + * + *

    If not running in a ForkJoinPool, this method is * behaviorally equivalent to *

     {@code
          * while (!blocker.isReleasable())
          *   if (blocker.block())
    -     *     return;
    -     * }
    + * break;}
  • * - * If the caller is a {@code ForkJoinTask}, then the pool may - * first be expanded to ensure parallelism, and later adjusted. + * If running in a ForkJoinPool, the pool may first be expanded to + * ensure sufficient parallelism available during the call to + * {@code blocker.block()}. * - * @param blocker the blocker - * @throws InterruptedException if blocker.block did so + * @param blocker the blocker task + * @throws InterruptedException if {@code blocker.block()} did so */ public static void managedBlock(ManagedBlocker blocker) throws InterruptedException { + ForkJoinPool p; + ForkJoinWorkerThread wt; Thread t = Thread.currentThread(); - if (t instanceof ForkJoinWorkerThread) { - ForkJoinPool p = ((ForkJoinWorkerThread)t).pool; + if ((t instanceof ForkJoinWorkerThread) && + (p = (wt = (ForkJoinWorkerThread)t).pool) != null) { + WorkQueue w = wt.workQueue; while (!blocker.isReleasable()) { - if (p.tryCompensate(p.ctl)) { + if (p.tryCompensate(w)) { try { do {} while (!blocker.isReleasable() && !blocker.block()); } finally { - p.incrementActiveCount(); + U.getAndAddLong(p, CTL, AC_UNIT); } break; } @@ -3241,15 +3340,18 @@ public class ForkJoinPool extends AbstractExecutorService { // Unsafe mechanics private static final sun.misc.Unsafe U; + private static final int ABASE; + private static final int ASHIFT; private static final long CTL; + private static final long RUNSTATE; + private static final long STEALCOUNTER; private static final long PARKBLOCKER; - private static final int ABASE; - private static final int ASHIFT; - private static final long STEALCOUNT; - private static final long PLOCK; - private static final long INDEXSEED; - private static final long QBASE; + private static final long QTOP; private static final long QLOCK; + private static final long QSCANSTATE; + private static final long QPARKER; + private static final long QCURRENTSTEAL; + private static final long QCURRENTJOIN; static { // initialize field offsets for CAS etc @@ -3258,20 +3360,26 @@ public class ForkJoinPool extends AbstractExecutorService { Class k = ForkJoinPool.class; CTL = U.objectFieldOffset (k.getDeclaredField("ctl")); - STEALCOUNT = U.objectFieldOffset - (k.getDeclaredField("stealCount")); - PLOCK = U.objectFieldOffset - (k.getDeclaredField("plock")); - INDEXSEED = U.objectFieldOffset - (k.getDeclaredField("indexSeed")); + RUNSTATE = U.objectFieldOffset + (k.getDeclaredField("runState")); + STEALCOUNTER = U.objectFieldOffset + (k.getDeclaredField("stealCounter")); Class tk = Thread.class; PARKBLOCKER = U.objectFieldOffset (tk.getDeclaredField("parkBlocker")); Class wk = WorkQueue.class; - QBASE = U.objectFieldOffset - (wk.getDeclaredField("base")); + QTOP = U.objectFieldOffset + (wk.getDeclaredField("top")); QLOCK = U.objectFieldOffset (wk.getDeclaredField("qlock")); + QSCANSTATE = U.objectFieldOffset + (wk.getDeclaredField("scanState")); + QPARKER = U.objectFieldOffset + (wk.getDeclaredField("parker")); + QCURRENTSTEAL = U.objectFieldOffset + (wk.getDeclaredField("currentSteal")); + QCURRENTJOIN = U.objectFieldOffset + (wk.getDeclaredField("currentJoin")); Class ak = ForkJoinTask[].class; ABASE = U.arrayBaseOffset(ak); int scale = U.arrayIndexScale(ak); @@ -3282,6 +3390,7 @@ public class ForkJoinPool extends AbstractExecutorService { throw new Error(e); } + commonMaxSpares = DEFAULT_COMMON_MAX_SPARES; defaultForkJoinWorkerThreadFactory = new DefaultForkJoinWorkerThreadFactory(); modifyThreadPermission = new RuntimePermission("modifyThread"); @@ -3289,7 +3398,7 @@ public class ForkJoinPool extends AbstractExecutorService { common = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction() { public ForkJoinPool run() { return makeCommonPool(); }}); - int par = common.parallelism; // report 1 even if threads disabled + int par = common.config & SMASK; // report 1 even if threads disabled commonParallelism = par > 0 ? par : 1; } @@ -3308,6 +3417,8 @@ public class ForkJoinPool extends AbstractExecutorService { ("java.util.concurrent.ForkJoinPool.common.threadFactory"); String hp = System.getProperty ("java.util.concurrent.ForkJoinPool.common.exceptionHandler"); + String mp = System.getProperty + ("java.util.concurrent.ForkJoinPool.common.maximumSpares"); if (pp != null) parallelism = Integer.parseInt(pp); if (fp != null) @@ -3316,6 +3427,8 @@ public class ForkJoinPool extends AbstractExecutorService { if (hp != null) handler = ((UncaughtExceptionHandler)ClassLoader. getSystemClassLoader().loadClass(hp).newInstance()); + if (mp != null) + commonMaxSpares = Integer.parseInt(mp); } catch (Exception ignore) { } if (factory == null) { diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 936bfc23a33..4439c2407da 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -297,15 +297,22 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Tries to set SIGNAL status unless already completed. Used by - * ForkJoinPool. Other variants are directly incorporated into - * externalAwaitDone etc. + * If not done, sets SIGNAL status and performs Object.wait(timeout). + * This task may or may not be done on exit. Ignores interrupts. * - * @return true if successful + * @param timeout using Object.wait conventions. */ - final boolean trySetSignal() { - int s = status; - return s >= 0 && U.compareAndSwapInt(this, STATUS, s, s | SIGNAL); + final void internalWait(long timeout) { + int s; + if ((s = status) >= 0 && // force completer to issue notify + U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) + try { wait(timeout); } catch (InterruptedException ie) { } + else + notifyAll(); + } + } } /** @@ -313,35 +320,29 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return status upon completion */ private int externalAwaitDone() { - int s; - ForkJoinPool cp = ForkJoinPool.common; - if ((s = status) >= 0) { - if (cp != null) { - if (this instanceof CountedCompleter) - s = cp.externalHelpComplete((CountedCompleter)this, Integer.MAX_VALUE); - else if (cp.tryExternalUnpush(this)) - s = doExec(); - } - if (s >= 0 && (s = status) >= 0) { - boolean interrupted = false; - do { - if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { - synchronized (this) { - if (status >= 0) { - try { - wait(); - } catch (InterruptedException ie) { - interrupted = true; - } + int s = ((this instanceof CountedCompleter) ? // try helping + ForkJoinPool.common.externalHelpComplete( + (CountedCompleter)this, 0) : + ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0); + if (s >= 0 && (s = status) >= 0) { + boolean interrupted = false; + do { + if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) { + try { + wait(0L); + } catch (InterruptedException ie) { + interrupted = true; } - else - notifyAll(); } + else + notifyAll(); } - } while ((s = status) >= 0); - if (interrupted) - Thread.currentThread().interrupt(); - } + } + } while ((s = status) >= 0); + if (interrupted) + Thread.currentThread().interrupt(); } return s; } @@ -351,22 +352,22 @@ public abstract class ForkJoinTask implements Future, Serializable { */ private int externalInterruptibleAwaitDone() throws InterruptedException { int s; - ForkJoinPool cp = ForkJoinPool.common; if (Thread.interrupted()) throw new InterruptedException(); - if ((s = status) >= 0 && cp != null) { - if (this instanceof CountedCompleter) - cp.externalHelpComplete((CountedCompleter)this, Integer.MAX_VALUE); - else if (cp.tryExternalUnpush(this)) - doExec(); - } - while ((s = status) >= 0) { - if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { - synchronized (this) { - if (status >= 0) - wait(); - else - notifyAll(); + if ((s = status) >= 0 && + (s = ((this instanceof CountedCompleter) ? + ForkJoinPool.common.externalHelpComplete( + (CountedCompleter)this, 0) : + ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : + 0)) >= 0) { + while ((s = status) >= 0) { + if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) + wait(0L); + else + notifyAll(); + } } } } @@ -386,7 +387,7 @@ public abstract class ForkJoinTask implements Future, Serializable { ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? (w = (wt = (ForkJoinWorkerThread)t).workQueue). tryUnpush(this) && (s = doExec()) < 0 ? s : - wt.pool.awaitJoin(w, this) : + wt.pool.awaitJoin(w, this, 0L) : externalAwaitDone(); } @@ -399,7 +400,8 @@ public abstract class ForkJoinTask implements Future, Serializable { int s; Thread t; ForkJoinWorkerThread wt; return (s = doExec()) < 0 ? s : ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? - (wt = (ForkJoinWorkerThread)t).pool.awaitJoin(wt.workQueue, this) : + (wt = (ForkJoinWorkerThread)t).pool. + awaitJoin(wt.workQueue, this, 0L) : externalAwaitDone(); } @@ -577,7 +579,7 @@ public abstract class ForkJoinTask implements Future, Serializable { Throwable ex; if (e == null || (ex = e.ex) == null) return null; - if (false && e.thrower != Thread.currentThread().getId()) { + if (e.thrower != Thread.currentThread().getId()) { Class ec = ex.getClass(); try { Constructor noArgCtor = null; @@ -587,13 +589,17 @@ public abstract class ForkJoinTask implements Future, Serializable { Class[] ps = c.getParameterTypes(); if (ps.length == 0) noArgCtor = c; - else if (ps.length == 1 && ps[0] == Throwable.class) - return (Throwable)(c.newInstance(ex)); + else if (ps.length == 1 && ps[0] == Throwable.class) { + Throwable wx = (Throwable)c.newInstance(ex); + return (wx == null) ? ex : wx; + } } if (noArgCtor != null) { Throwable wx = (Throwable)(noArgCtor.newInstance()); - wx.initCause(ex); - return wx; + if (wx != null) { + wx.initCause(ex); + return wx; + } } } catch (Exception ignore) { } @@ -1017,67 +1023,40 @@ public abstract class ForkJoinTask implements Future, Serializable { */ public final V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + int s; + long nanos = unit.toNanos(timeout); if (Thread.interrupted()) throw new InterruptedException(); - // Messy in part because we measure in nanosecs, but wait in millisecs - int s; long ms; - long ns = unit.toNanos(timeout); - ForkJoinPool cp; - if ((s = status) >= 0 && ns > 0L) { - long deadline = System.nanoTime() + ns; - ForkJoinPool p = null; - ForkJoinPool.WorkQueue w = null; + if ((s = status) >= 0 && nanos > 0L) { + long d = System.nanoTime() + nanos; + long deadline = (d == 0L) ? 1L : d; // avoid 0 Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) { ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t; - p = wt.pool; - w = wt.workQueue; - p.helpJoinOnce(w, this); // no retries on failure + s = wt.pool.awaitJoin(wt.workQueue, this, deadline); } - else if ((cp = ForkJoinPool.common) != null) { - if (this instanceof CountedCompleter) - cp.externalHelpComplete((CountedCompleter)this, Integer.MAX_VALUE); - else if (cp.tryExternalUnpush(this)) - doExec(); - } - boolean canBlock = false; - boolean interrupted = false; - try { - while ((s = status) >= 0) { - if (w != null && w.qlock < 0) - cancelIgnoringExceptions(this); - else if (!canBlock) { - if (p == null || p.tryCompensate(p.ctl)) - canBlock = true; - } - else { - if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L && - U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { - synchronized (this) { - if (status >= 0) { - try { - wait(ms); - } catch (InterruptedException ie) { - if (p == null) - interrupted = true; - } - } - else - notifyAll(); - } + else if ((s = ((this instanceof CountedCompleter) ? + ForkJoinPool.common.externalHelpComplete( + (CountedCompleter)this, 0) : + ForkJoinPool.common.tryExternalUnpush(this) ? + doExec() : 0)) >= 0) { + long ns, ms; // measure in nanosecs, but wait in millisecs + while ((s = status) >= 0 && + (ns = deadline - System.nanoTime()) > 0L) { + if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L && + U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) + wait(ms); // OK to throw InterruptedException + else + notifyAll(); } - if ((s = status) < 0 || interrupted || - (ns = deadline - System.nanoTime()) <= 0L) - break; } } - } finally { - if (p != null && canBlock) - p.incrementActiveCount(); } - if (interrupted) - throw new InterruptedException(); } + if (s >= 0) + s = status; if ((s &= DONE_MASK) != NORMAL) { Throwable ex; if (s == CANCELLED) diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java index 404c47cc01a..8723f0aac69 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java @@ -66,7 +66,7 @@ public class ForkJoinWorkerThread extends Thread { * owning thread. * * Support for (non-public) subclass InnocuousForkJoinWorkerThread - * requires that we break quite a lot of encapulation (via Unsafe) + * requires that we break quite a lot of encapsulation (via Unsafe) * both here and in the subclass to access and set Thread fields. */ @@ -118,7 +118,7 @@ public class ForkJoinWorkerThread extends Thread { * @return the index number */ public int getPoolIndex() { - return workQueue.poolIndex >>> 1; // ignore odd/even tag bit + return workQueue.getPoolIndex(); } /** @@ -171,7 +171,7 @@ public class ForkJoinWorkerThread extends Thread { } /** - * Erases ThreadLocals by nulling out Thread maps + * Erases ThreadLocals by nulling out Thread maps. */ final void eraseThreadLocals() { U.putObject(this, THREADLOCALS, null); @@ -246,8 +246,8 @@ public class ForkJoinWorkerThread extends Thread { /** * Returns a new group with the system ThreadGroup (the - * topmost, parentless group) as parent. Uses Unsafe to - * traverse Thread group and ThreadGroup parent fields. + * topmost, parent-less group) as parent. Uses Unsafe to + * traverse Thread.group and ThreadGroup.parent fields. */ private static ThreadGroup createThreadGroup() { try { @@ -274,4 +274,3 @@ public class ForkJoinWorkerThread extends Thread { } } - diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java b/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java index e3095fce2d7..64b52f4569a 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java @@ -29,38 +29,34 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.EnumMap; -import java.util.List; public class ValueConversions { private static final Class THIS_CLASS = ValueConversions.class; - // Do not adjust this except for special platforms: - private static final int MAX_ARITY; - static { - final Object[] values = { 255 }; - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255); - return null; - } - }); - MAX_ARITY = (Integer) values[0]; - } - private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); - private static EnumMap[] newWrapperCaches(int n) { - @SuppressWarnings("unchecked") // generic array creation - EnumMap[] caches - = (EnumMap[]) new EnumMap[n]; + /** Thread-safe canonicalized mapping from Wrapper to MethodHandle + * with unsynchronized reads and synchronized writes. + * It's safe to publish MethodHandles by data race because they are immutable. */ + private static class WrapperCache { + /** EnumMap uses preconstructed array internally, which is constant during it's lifetime. */ + private final EnumMap map = new EnumMap<>(Wrapper.class); + + public MethodHandle get(Wrapper w) { + return map.get(w); + } + public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) { + // Simulate CAS to avoid racy duplication + MethodHandle prev = map.putIfAbsent(w, mh); + if (prev != null) return prev; + return mh; + } + } + + private static WrapperCache[] newWrapperCaches(int n) { + WrapperCache[] caches = new WrapperCache[n]; for (int i = 0; i < n; i++) - caches[i] = new EnumMap<>(Wrapper.class); + caches[i] = new WrapperCache(); return caches; } @@ -71,63 +67,92 @@ public class ValueConversions { // implicit conversions sanctioned by JLS 5.1.2, etc. // explicit conversions as allowed by explicitCastArguments + static int unboxInteger(Integer x) { + return x; + } static int unboxInteger(Object x, boolean cast) { if (x instanceof Integer) - return ((Integer) x).intValue(); + return (Integer) x; return primitiveConversion(Wrapper.INT, x, cast).intValue(); } + static byte unboxByte(Byte x) { + return x; + } static byte unboxByte(Object x, boolean cast) { if (x instanceof Byte) - return ((Byte) x).byteValue(); + return (Byte) x; return primitiveConversion(Wrapper.BYTE, x, cast).byteValue(); } + static short unboxShort(Short x) { + return x; + } static short unboxShort(Object x, boolean cast) { if (x instanceof Short) - return ((Short) x).shortValue(); + return (Short) x; return primitiveConversion(Wrapper.SHORT, x, cast).shortValue(); } + static boolean unboxBoolean(Boolean x) { + return x; + } static boolean unboxBoolean(Object x, boolean cast) { if (x instanceof Boolean) - return ((Boolean) x).booleanValue(); + return (Boolean) x; return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0; } + static char unboxCharacter(Character x) { + return x; + } static char unboxCharacter(Object x, boolean cast) { if (x instanceof Character) - return ((Character) x).charValue(); + return (Character) x; return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue(); } + static long unboxLong(Long x) { + return x; + } static long unboxLong(Object x, boolean cast) { if (x instanceof Long) - return ((Long) x).longValue(); + return (Long) x; return primitiveConversion(Wrapper.LONG, x, cast).longValue(); } + static float unboxFloat(Float x) { + return x; + } static float unboxFloat(Object x, boolean cast) { if (x instanceof Float) - return ((Float) x).floatValue(); + return (Float) x; return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue(); } + static double unboxDouble(Double x) { + return x; + } static double unboxDouble(Object x, boolean cast) { if (x instanceof Double) - return ((Double) x).doubleValue(); + return (Double) x; return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue(); } - private static MethodType unboxType(Wrapper wrap) { + private static MethodType unboxType(Wrapper wrap, int kind) { + if (kind == 0) + return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType()); return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class); } - private static final EnumMap[] - UNBOX_CONVERSIONS = newWrapperCaches(2); + private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4); - private static MethodHandle unbox(Wrapper wrap, boolean cast) { - EnumMap cache = UNBOX_CONVERSIONS[(cast?1:0)]; + private static MethodHandle unbox(Wrapper wrap, int kind) { + // kind 0 -> strongly typed with NPE + // kind 1 -> strongly typed but zero for null, + // kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE + // kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null + WrapperCache cache = UNBOX_CONVERSIONS[kind]; MethodHandle mh = cache.get(wrap); if (mh != null) { return mh; @@ -135,41 +160,59 @@ public class ValueConversions { // slow path switch (wrap) { case OBJECT: - mh = IDENTITY; break; case VOID: - mh = IGNORE; break; - } - if (mh != null) { - cache.put(wrap, mh); - return mh; + throw new IllegalArgumentException("unbox "+wrap); } // look up the method String name = "unbox" + wrap.wrapperSimpleName(); - MethodType type = unboxType(wrap); + MethodType type = unboxType(wrap, kind); try { mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); } catch (ReflectiveOperationException ex) { mh = null; } if (mh != null) { - mh = MethodHandles.insertArguments(mh, 1, cast); - cache.put(wrap, mh); - return mh; + if (kind > 0) { + boolean cast = (kind != 2); + mh = MethodHandles.insertArguments(mh, 1, cast); + } + if (kind == 1) { // casting but exact (null -> zero) + mh = mh.asType(unboxType(wrap, 0)); + } + return cache.put(wrap, mh); } throw new IllegalArgumentException("cannot find unbox adapter for " + wrap - + (cast ? " (cast)" : "")); + + (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : "")); } + /** Return an exact unboxer for the given primitive type. */ + public static MethodHandle unboxExact(Wrapper type) { + return unbox(type, 0); + } + + /** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion. + * The boolean says whether to throw an NPE on a null value (false means unbox a zero). + * The type of the unboxer is of a form like (Integer)int. + */ + public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) { + return unbox(type, throwNPE ? 0 : 1); + } + + /** Return a widening unboxer for the given primitive type. + * Widen narrower primitive boxes to the given type. + * Do not narrow any primitive values or convert null to zero. + * The type of the unboxer is of a form like (Object)int. + */ + public static MethodHandle unboxWiden(Wrapper type) { + return unbox(type, 2); + } + + /** Return a casting unboxer for the given primitive type. + * Widen or narrow primitive values to the given type, or convert null to zero, as needed. + * The type of the unboxer is of a form like (Object)int. + */ public static MethodHandle unboxCast(Wrapper type) { - return unbox(type, true); - } - - public static MethodHandle unbox(Class type) { - return unbox(Wrapper.forPrimitiveType(type), false); - } - - public static MethodHandle unboxCast(Class type) { - return unbox(Wrapper.forPrimitiveType(type), true); + return unbox(type, 3); } static private final Integer ZERO_INT = 0, ONE_INT = 1; @@ -266,57 +309,26 @@ public class ValueConversions { return MethodType.methodType(boxType, wrap.primitiveType()); } - private static final EnumMap[] - BOX_CONVERSIONS = newWrapperCaches(2); + private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1); - private static MethodHandle box(Wrapper wrap, boolean exact) { - EnumMap cache = BOX_CONVERSIONS[(exact?1:0)]; + public static MethodHandle boxExact(Wrapper wrap) { + WrapperCache cache = BOX_CONVERSIONS[0]; MethodHandle mh = cache.get(wrap); if (mh != null) { return mh; } - // slow path - switch (wrap) { - case OBJECT: - mh = IDENTITY; break; - case VOID: - mh = ZERO_OBJECT; - break; - } - if (mh != null) { - cache.put(wrap, mh); - return mh; - } // look up the method String name = "box" + wrap.wrapperSimpleName(); MethodType type = boxType(wrap); - if (exact) { - try { - mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); - } catch (ReflectiveOperationException ex) { - mh = null; - } - } else { - mh = box(wrap, !exact).asType(type.erase()); + try { + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); + } catch (ReflectiveOperationException ex) { + mh = null; } if (mh != null) { - cache.put(wrap, mh); - return mh; + return cache.put(wrap, mh); } - throw new IllegalArgumentException("cannot find box adapter for " - + wrap + (exact ? " (exact)" : "")); - } - - public static MethodHandle box(Class type) { - boolean exact = false; - // e.g., boxShort(short)Short if exact, - // e.g., boxShort(short)Object if !exact - return box(Wrapper.forPrimitiveType(type), exact); - } - - public static MethodHandle box(Wrapper type) { - boolean exact = false; - return box(type, exact); + throw new IllegalArgumentException("cannot find box adapter for " + wrap); } /// Constant functions @@ -348,11 +360,10 @@ public class ValueConversions { return 0; } - private static final EnumMap[] - CONSTANT_FUNCTIONS = newWrapperCaches(2); + private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2); public static MethodHandle zeroConstantFunction(Wrapper wrap) { - EnumMap cache = CONSTANT_FUNCTIONS[0]; + WrapperCache cache = CONSTANT_FUNCTIONS[0]; MethodHandle mh = cache.get(wrap); if (mh != null) { return mh; @@ -373,184 +384,37 @@ public class ValueConversions { break; } if (mh != null) { - cache.put(wrap, mh); - return mh; + return cache.put(wrap, mh); } // use zeroInt and cast the result if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) { mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type); - cache.put(wrap, mh); - return mh; + return cache.put(wrap, mh); } throw new IllegalArgumentException("cannot find zero constant for " + wrap); } - /// Converting references to references. - - /** - * Identity function. - * @param x an arbitrary reference value - * @return the same value x - */ - static T identity(T x) { - return x; - } - - static T[] identity(T[] x) { - return x; - } - - /** - * Identity function on ints. - * @param x an arbitrary int value - * @return the same value x - */ - static int identity(int x) { - return x; - } - - static byte identity(byte x) { - return x; - } - - static short identity(short x) { - return x; - } - - static boolean identity(boolean x) { - return x; - } - - static char identity(char x) { - return x; - } - - /** - * Identity function on longs. - * @param x an arbitrary long value - * @return the same value x - */ - static long identity(long x) { - return x; - } - - static float identity(float x) { - return x; - } - - static double identity(double x) { - return x; - } - - private static ClassCastException newClassCastException(Class t, Object obj) { - return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); - } - - private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY, - ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY; + private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY; static { try { MethodType idType = MethodType.genericMethodType(1); MethodType ignoreType = idType.changeReturnType(void.class); - MethodType zeroObjectType = MethodType.genericMethodType(0); - IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); - ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType); IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); - ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class)); - FILL_NEW_ARRAY = IMPL_LOOKUP - .findStatic(THIS_CLASS, "fillNewArray", - MethodType.methodType(Object[].class, Integer.class, Object[].class)); - FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP - .findStatic(THIS_CLASS, "fillNewTypedArray", - MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); } catch (NoSuchMethodException | IllegalAccessException ex) { throw newInternalError("uncaught exception", ex); } } - // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems. - static class LazyStatics { - private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST; - static { - try { - //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class)); - COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class)); - COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class)); - MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class)); - } catch (ReflectiveOperationException ex) { - throw newInternalError("uncaught exception", ex); - } - } + public static MethodHandle ignore() { + return IGNORE; } - private static final EnumMap[] WRAPPER_CASTS - = newWrapperCaches(1); - - /** Return a method that casts its sole argument (an Object) to the given type - * and returns it as the given type. - */ - public static MethodHandle cast(Class type) { - return cast(type, CAST_REFERENCE); - } - public static MethodHandle cast(Class type, MethodHandle castReference) { - if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type); - MethodHandle mh; - Wrapper wrap = null; - EnumMap cache = null; - if (Wrapper.isWrapperType(type)) { - wrap = Wrapper.forWrapperType(type); - cache = WRAPPER_CASTS[0]; - mh = cache.get(wrap); - if (mh != null) return mh; - } - mh = MethodHandles.insertArguments(castReference, 0, type); - if (cache != null) - cache.put(wrap, mh); - return mh; - } - - public static MethodHandle identity() { - return IDENTITY; - } - - public static MethodHandle identity(Class type) { - if (!type.isPrimitive()) - // Reference identity has been moved into MethodHandles: - return MethodHandles.identity(type); - return identity(Wrapper.findPrimitiveType(type)); - } - - public static MethodHandle identity(Wrapper wrap) { - EnumMap cache = CONSTANT_FUNCTIONS[1]; - MethodHandle mh = cache.get(wrap); - if (mh != null) { - return mh; - } - // slow path - MethodType type = MethodType.methodType(wrap.primitiveType()); - if (wrap != Wrapper.VOID) - type = type.appendParameterTypes(wrap.primitiveType()); - try { - mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type); - } catch (ReflectiveOperationException ex) { - mh = null; - } - if (mh == null && wrap == Wrapper.VOID) { - mh = EMPTY; // #(){} : #()void - } - if (mh != null) { - cache.put(wrap, mh); - return mh; - } - - if (mh != null) { - cache.put(wrap, mh); - return mh; - } - throw new IllegalArgumentException("cannot find identity for " + wrap); + /** Return a method that casts its second argument (an Object) to the given type (a Class). */ + public static MethodHandle cast() { + return CAST_REFERENCE; } /// Primitive conversions. @@ -759,11 +623,10 @@ public class ValueConversions { return (x ? (byte)1 : (byte)0); } - private static final EnumMap[] - CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length); + private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length); public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) { - EnumMap cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()]; + WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()]; MethodHandle mh = cache.get(wdst); if (mh != null) { return mh; @@ -771,17 +634,9 @@ public class ValueConversions { // slow path Class src = wsrc.primitiveType(); Class dst = wdst.primitiveType(); - MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src); + MethodType type = MethodType.methodType(dst, src); if (wsrc == wdst) { - mh = identity(src); - } else if (wsrc == Wrapper.VOID) { - mh = zeroConstantFunction(wdst); - } else if (wdst == Wrapper.VOID) { - mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles. - } else if (wsrc == Wrapper.OBJECT) { - mh = unboxCast(dst); - } else if (wdst == Wrapper.OBJECT) { - mh = box(src); + mh = MethodHandles.identity(src); } else { assert(src.isPrimitive() && dst.isPrimitive()); try { @@ -792,8 +647,7 @@ public class ValueConversions { } if (mh != null) { assert(mh.type() == type) : mh; - cache.put(wdst, mh); - return mh; + return cache.put(wdst, mh); } throw new IllegalArgumentException("cannot find primitive conversion function for " + @@ -808,363 +662,6 @@ public class ValueConversions { return Character.toUpperCase(x.charAt(0))+x.substring(1); } - /// Collection of multiple arguments. - - public static Object convertArrayElements(Class arrayType, Object array) { - Class src = array.getClass().getComponentType(); - Class dst = arrayType.getComponentType(); - if (src == null || dst == null) throw new IllegalArgumentException("not array type"); - Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null); - Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null); - int length; - if (sw == null) { - Object[] a = (Object[]) array; - length = a.length; - if (dw == null) - return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class)); - Object res = dw.makeArray(length); - dw.copyArrayUnboxing(a, 0, res, 0, length); - return res; - } - length = java.lang.reflect.Array.getLength(array); - Object[] res; - if (dw == null) { - res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class)); - } else { - res = new Object[length]; - } - sw.copyArrayBoxing(array, 0, res, 0, length); - if (dw == null) return res; - Object a = dw.makeArray(length); - dw.copyArrayUnboxing(res, 0, a, 0, length); - return a; - } - - private static MethodHandle findCollector(String name, int nargs, Class rtype, Class... ptypes) { - MethodType type = MethodType.genericMethodType(nargs) - .changeReturnType(rtype) - .insertParameterTypes(0, ptypes); - try { - return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); - } catch (ReflectiveOperationException ex) { - return null; - } - } - - private static final Object[] NO_ARGS_ARRAY = {}; - private static Object[] makeArray(Object... args) { return args; } - private static Object[] array() { return NO_ARGS_ARRAY; } - private static Object[] array(Object a0) - { return makeArray(a0); } - private static Object[] array(Object a0, Object a1) - { return makeArray(a0, a1); } - private static Object[] array(Object a0, Object a1, Object a2) - { return makeArray(a0, a1, a2); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3) - { return makeArray(a0, a1, a2, a3); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4) - { return makeArray(a0, a1, a2, a3, a4); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5) - { return makeArray(a0, a1, a2, a3, a4, a5); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6) - { return makeArray(a0, a1, a2, a3, a4, a5, a6); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7) - { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8) - { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - private static Object[] array(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) - { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - private static MethodHandle[] makeArrays() { - ArrayList mhs = new ArrayList<>(); - for (;;) { - MethodHandle mh = findCollector("array", mhs.size(), Object[].class); - if (mh == null) break; - mhs.add(mh); - } - assert(mhs.size() == 11); // current number of methods - return mhs.toArray(new MethodHandle[MAX_ARITY+1]); - } - private static final MethodHandle[] ARRAYS = makeArrays(); - - // filling versions of the above: - // using Integer len instead of int len and no varargs to avoid bootstrapping problems - private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { - Object[] a = new Object[len]; - fillWithArguments(a, 0, args); - return a; - } - private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { - Object[] a = Arrays.copyOf(example, len); - fillWithArguments(a, 0, args); - return a; - } - private static void fillWithArguments(Object[] a, int pos, Object... args) { - System.arraycopy(args, 0, a, pos, args.length); - } - // using Integer pos instead of int pos to avoid bootstrapping problems - private static Object[] fillArray(Integer pos, Object[] a, Object a0) - { fillWithArguments(a, pos, a0); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) - { fillWithArguments(a, pos, a0, a1); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) - { fillWithArguments(a, pos, a0, a1, a2); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) - { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } - private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) - { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } - private static MethodHandle[] makeFillArrays() { - ArrayList mhs = new ArrayList<>(); - mhs.add(null); // there is no empty fill; at least a0 is required - for (;;) { - MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); - if (mh == null) break; - mhs.add(mh); - } - assert(mhs.size() == 11); // current number of methods - return mhs.toArray(new MethodHandle[0]); - } - private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); - - private static Object[] copyAsReferenceArray(Class arrayType, Object... a) { - return Arrays.copyOf(a, a.length, arrayType); - } - private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { - Object a = w.makeArray(boxes.length); - w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); - return a; - } - - /** Return a method handle that takes the indicated number of Object - * arguments and returns an Object array of them, as if for varargs. - */ - public static MethodHandle varargsArray(int nargs) { - MethodHandle mh = ARRAYS[nargs]; - if (mh != null) return mh; - mh = findCollector("array", nargs, Object[].class); - if (mh != null) return ARRAYS[nargs] = mh; - mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs); - assert(assertCorrectArity(mh, nargs)); - return ARRAYS[nargs] = mh; - } - - private static boolean assertCorrectArity(MethodHandle mh, int arity) { - assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; - return true; - } - - private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { - // Build up the result mh as a sequence of fills like this: - // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) - // The various fill(_,10*I,___*[J]) are reusable. - int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately - int rightLen = nargs - leftLen; - MethodHandle leftCollector = newArray.bindTo(nargs); - leftCollector = leftCollector.asCollector(Object[].class, leftLen); - MethodHandle mh = finisher; - if (rightLen > 0) { - MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); - if (mh == ARRAY_IDENTITY) - mh = rightFiller; - else - mh = MethodHandles.collectArguments(mh, 0, rightFiller); - } - if (mh == ARRAY_IDENTITY) - mh = leftCollector; - else - mh = MethodHandles.collectArguments(mh, 0, leftCollector); - return mh; - } - - private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); - private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; - /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) - * fills a[L]..a[N-1] with corresponding arguments, - * and then returns a. The value L is a global constant (LEFT_ARGS). - */ - private static MethodHandle fillToRight(int nargs) { - MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; - if (filler != null) return filler; - filler = buildFiller(nargs); - assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); - return FILL_ARRAY_TO_RIGHT[nargs] = filler; - } - private static MethodHandle buildFiller(int nargs) { - if (nargs <= LEFT_ARGS) - return ARRAY_IDENTITY; // no args to fill; return the array unchanged - // we need room for both mh and a in mh.invoke(a, arg*[nargs]) - final int CHUNK = LEFT_ARGS; - int rightLen = nargs % CHUNK; - int midLen = nargs - rightLen; - if (rightLen == 0) { - midLen = nargs - (rightLen = CHUNK); - if (FILL_ARRAY_TO_RIGHT[midLen] == null) { - // build some precursors from left to right - for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) - if (j > LEFT_ARGS) fillToRight(j); - } - } - if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); - assert(rightLen > 0); - MethodHandle midFill = fillToRight(midLen); // recursive fill - MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] - assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); - assert(rightFill.type().parameterCount() == 1 + rightLen); - - // Combine the two fills: - // right(mid(a, x10..x19), x20..x23) - // The final product will look like this: - // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) - if (midLen == LEFT_ARGS) - return rightFill; - else - return MethodHandles.collectArguments(rightFill, 0, midFill); - } - - // Type-polymorphic version of varargs maker. - private static final ClassValue TYPED_COLLECTORS - = new ClassValue() { - @Override - protected MethodHandle[] computeValue(Class type) { - return new MethodHandle[256]; - } - }; - - static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM - - /** Return a method handle that takes the indicated number of - * typed arguments and returns an array of them. - * The type argument is the array type. - */ - public static MethodHandle varargsArray(Class arrayType, int nargs) { - Class elemType = arrayType.getComponentType(); - if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); - // FIXME: Need more special casing and caching here. - if (nargs >= MAX_JVM_ARITY/2 - 1) { - int slots = nargs; - final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH - if (arrayType == double[].class || arrayType == long[].class) - slots *= 2; - if (slots > MAX_ARRAY_SLOTS) - throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); - } - if (elemType == Object.class) - return varargsArray(nargs); - // other cases: primitive arrays, subtypes of Object[] - MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); - MethodHandle mh = nargs < cache.length ? cache[nargs] : null; - if (mh != null) return mh; - if (elemType.isPrimitive()) { - MethodHandle builder = FILL_NEW_ARRAY; - MethodHandle producer = buildArrayProducer(arrayType); - mh = buildVarargsArray(builder, producer, nargs); - } else { - @SuppressWarnings("unchecked") - Class objArrayType = (Class) arrayType; - Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); - MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); - MethodHandle producer = ARRAY_IDENTITY; - mh = buildVarargsArray(builder, producer, nargs); - } - mh = mh.asType(MethodType.methodType(arrayType, Collections.>nCopies(nargs, elemType))); - assert(assertCorrectArity(mh, nargs)); - if (nargs < cache.length) - cache[nargs] = mh; - return mh; - } - - private static MethodHandle buildArrayProducer(Class arrayType) { - Class elemType = arrayType.getComponentType(); - if (elemType.isPrimitive()) - return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType)); - else - return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType); - } - - // List version of varargs maker. - - private static final List NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); - private static List makeList(Object... args) { return Arrays.asList(args); } - private static List list() { return NO_ARGS_LIST; } - private static List list(Object a0) - { return makeList(a0); } - private static List list(Object a0, Object a1) - { return makeList(a0, a1); } - private static List list(Object a0, Object a1, Object a2) - { return makeList(a0, a1, a2); } - private static List list(Object a0, Object a1, Object a2, Object a3) - { return makeList(a0, a1, a2, a3); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4) - { return makeList(a0, a1, a2, a3, a4); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5) - { return makeList(a0, a1, a2, a3, a4, a5); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6) - { return makeList(a0, a1, a2, a3, a4, a5, a6); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7) - { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8) - { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - private static List list(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) - { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - private static MethodHandle[] makeLists() { - ArrayList mhs = new ArrayList<>(); - for (;;) { - MethodHandle mh = findCollector("list", mhs.size(), List.class); - if (mh == null) break; - mhs.add(mh); - } - assert(mhs.size() == 11); // current number of methods - return mhs.toArray(new MethodHandle[MAX_ARITY+1]); - } - private static final MethodHandle[] LISTS = makeLists(); - - /** Return a method handle that takes the indicated number of Object - * arguments and returns a List. - */ - public static MethodHandle varargsList(int nargs) { - MethodHandle mh = LISTS[nargs]; - if (mh != null) return mh; - mh = findCollector("list", nargs, List.class); - if (mh != null) return LISTS[nargs] = mh; - return LISTS[nargs] = buildVarargsList(nargs); - } - private static MethodHandle buildVarargsList(int nargs) { - return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST); - } - // handy shared exception makers (they simplify the common case code) private static InternalError newInternalError(String message, Throwable cause) { return new InternalError(message, cause); diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyType.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyType.java index 52b32c40e89..ce37b88c76d 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyType.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyType.java @@ -40,18 +40,38 @@ public class VerifyType { /** * True if a value can be stacked as the source type and unstacked as the * destination type, without violating the JVM's type consistency. + *

    + * If both types are references, we apply the verifier's subclass check + * (or subtyping, if keepInterfaces). + * If the src type is a type guaranteed to be null (Void) it can be converted + * to any other reference type. + *

    + * If both types are primitives, we apply the verifier's primitive conversions. + * These do not include Java conversions such as long to double, since those + * require computation and (in general) stack depth changes. + * But very simple 32-bit viewing changes, such as byte to int, + * are null conversions, because they do not require any computation. + * These conversions are from any type to a wider type up to 32 bits, + * as long as the conversion is not signed to unsigned (byte to char). + *

    + * The primitive type 'void' does not interconvert with any other type, + * even though it is legal to drop any type from the stack and "return void". + * The stack effects, though are different between void and any other type, + * so it is safer to report a non-trivial conversion. * * @param src the type of a stacked value * @param dst the type by which we'd like to treat it + * @param keepInterfaces if false, we treat any interface as if it were Object * @return whether the retyping can be done without motion or reformatting */ - public static boolean isNullConversion(Class src, Class dst) { + public static boolean isNullConversion(Class src, Class dst, boolean keepInterfaces) { if (src == dst) return true; // Verifier allows any interface to be treated as Object: - if (dst.isInterface()) dst = Object.class; - if (src.isInterface()) src = Object.class; - if (src == dst) return true; // check again - if (dst == void.class) return true; // drop any return value + if (!keepInterfaces) { + if (dst.isInterface()) dst = Object.class; + if (src.isInterface()) src = Object.class; + if (src == dst) return true; // check again + } if (isNullType(src)) return !dst.isPrimitive(); if (!src.isPrimitive()) return dst.isAssignableFrom(src); if (!dst.isPrimitive()) return false; @@ -82,25 +102,13 @@ public class VerifyType { * Is the given type java.lang.Null or an equivalent null-only type? */ public static boolean isNullType(Class type) { - if (type == null) return false; - return type == NULL_CLASS - // This one may also be used as a null type. - // TO DO: Decide if we really want to legitimize it here. - // Probably we do, unless java.lang.Null really makes it into Java 7 - //|| type == Void.class - // Locally known null-only class: - || type == Empty.class - ; - } - private static final Class NULL_CLASS; - static { - Class nullClass = null; - try { - nullClass = Class.forName("java.lang.Null"); - } catch (ClassNotFoundException ex) { - // OK, we'll cope - } - NULL_CLASS = nullClass; + // Any reference statically typed as Void is guaranteed to be null. + // Therefore, it can be safely treated as a value of any + // other type that admits null, i.e., a reference type. + if (type == Void.class) return true; + // Locally known null-only class: + if (type == Empty.class) return true; + return false; } /** @@ -111,14 +119,14 @@ public class VerifyType { * @param recv the type of the method handle receiving the call * @return whether the retyping can be done without motion or reformatting */ - public static boolean isNullConversion(MethodType call, MethodType recv) { + public static boolean isNullConversion(MethodType call, MethodType recv, boolean keepInterfaces) { if (call == recv) return true; int len = call.parameterCount(); if (len != recv.parameterCount()) return false; for (int i = 0; i < len; i++) - if (!isNullConversion(call.parameterType(i), recv.parameterType(i))) + if (!isNullConversion(call.parameterType(i), recv.parameterType(i), keepInterfaces)) return false; - return isNullConversion(recv.returnType(), call.returnType()); + return isNullConversion(recv.returnType(), call.returnType(), keepInterfaces); } /** diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java b/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java index 6c4be456aee..2732e28c8ed 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java @@ -230,14 +230,6 @@ public enum Wrapper { */ public T zero(Class type) { return convert(zero, type); } -// /** Produce a wrapper for the given wrapper or primitive type. */ -// public static Wrapper valueOf(Class type) { -// if (isPrimitiveType(type)) -// return forPrimitiveType(type); -// else -// return forWrapperType(type); -// } - /** Return the wrapper that wraps values of the given type. * The type may be {@code Object}, meaning the {@code OBJECT} wrapper. * Otherwise, the type must be a primitive. diff --git a/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java b/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java index 7f1ae50b126..96f64ec1847 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java +++ b/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java @@ -69,33 +69,34 @@ class AccessorGenerator implements ClassFileConstants { protected short codeIdx; protected short exceptionsIdx; // Boxing + protected short valueOfIdx; protected short booleanIdx; - protected short booleanCtorIdx; + protected short booleanBoxIdx; protected short booleanUnboxIdx; protected short byteIdx; - protected short byteCtorIdx; + protected short byteBoxIdx; protected short byteUnboxIdx; protected short characterIdx; - protected short characterCtorIdx; + protected short characterBoxIdx; protected short characterUnboxIdx; protected short doubleIdx; - protected short doubleCtorIdx; + protected short doubleBoxIdx; protected short doubleUnboxIdx; protected short floatIdx; - protected short floatCtorIdx; + protected short floatBoxIdx; protected short floatUnboxIdx; protected short integerIdx; - protected short integerCtorIdx; + protected short integerBoxIdx; protected short integerUnboxIdx; protected short longIdx; - protected short longCtorIdx; + protected short longBoxIdx; protected short longUnboxIdx; protected short shortIdx; - protected short shortCtorIdx; + protected short shortBoxIdx; protected short shortUnboxIdx; protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30; - protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 72; + protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73; // Requires that superClass has been set up protected void emitCommonConstantPoolEntries() { @@ -181,9 +182,10 @@ class AccessorGenerator implements ClassFileConstants { /** Constant pool entries required to be able to box/unbox primitive types. Note that we don't emit these if we don't need them. */ protected void emitBoxingContantPoolEntries() { + // * [UTF-8] "valueOf" // * [UTF-8] "java/lang/Boolean" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(Z)V" + // * [UTF-8] "(Z)Ljava/lang/Boolean;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "booleanValue" @@ -192,7 +194,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Byte" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(B)V" + // * [UTF-8] "(B)Ljava/lang/Byte;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "byteValue" @@ -201,7 +203,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Character" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(C)V" + // * [UTF-8] "(C)Ljava/lang/Character;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "charValue" @@ -210,7 +212,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Double" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(D)V" + // * [UTF-8] "(D)Ljava/lang/Double;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "doubleValue" @@ -219,7 +221,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Float" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(F)V" + // * [UTF-8] "(F)Ljava/lang/Float;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "floatValue" @@ -228,7 +230,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Integer" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(I)V" + // * [UTF-8] "(I)Ljava/lang/Integer;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "intValue" @@ -237,7 +239,7 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Long" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(J)V" + // * [UTF-8] "(J)Ljava/lang/Long;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "longValue" @@ -246,21 +248,26 @@ class AccessorGenerator implements ClassFileConstants { // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Short" // * [CONSTANT_Class_info] for above - // * [UTF-8] "(S)V" + // * [UTF-8] "(S)Ljava/lang/Short;" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "shortValue" // * [UTF-8] "()S" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above + + // valueOf-method name + asm.emitConstantPoolUTF8("valueOf"); + valueOfIdx = asm.cpi(); + // Boolean asm.emitConstantPoolUTF8("java/lang/Boolean"); asm.emitConstantPoolClass(asm.cpi()); booleanIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(Z)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - booleanCtorIdx = asm.cpi(); + booleanBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("booleanValue"); asm.emitConstantPoolUTF8("()Z"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -271,10 +278,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Byte"); asm.emitConstantPoolClass(asm.cpi()); byteIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(B)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - byteCtorIdx = asm.cpi(); + byteBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("byteValue"); asm.emitConstantPoolUTF8("()B"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -285,10 +292,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Character"); asm.emitConstantPoolClass(asm.cpi()); characterIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(C)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - characterCtorIdx = asm.cpi(); + characterBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("charValue"); asm.emitConstantPoolUTF8("()C"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -299,10 +306,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Double"); asm.emitConstantPoolClass(asm.cpi()); doubleIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(D)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - doubleCtorIdx = asm.cpi(); + doubleBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("doubleValue"); asm.emitConstantPoolUTF8("()D"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -313,10 +320,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Float"); asm.emitConstantPoolClass(asm.cpi()); floatIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(F)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - floatCtorIdx = asm.cpi(); + floatBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("floatValue"); asm.emitConstantPoolUTF8("()F"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -327,10 +334,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Integer"); asm.emitConstantPoolClass(asm.cpi()); integerIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(I)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - integerCtorIdx = asm.cpi(); + integerBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("intValue"); asm.emitConstantPoolUTF8("()I"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -341,10 +348,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Long"); asm.emitConstantPoolClass(asm.cpi()); longIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(J)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - longCtorIdx = asm.cpi(); + longBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("longValue"); asm.emitConstantPoolUTF8("()J"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -355,10 +362,10 @@ class AccessorGenerator implements ClassFileConstants { asm.emitConstantPoolUTF8("java/lang/Short"); asm.emitConstantPoolClass(asm.cpi()); shortIdx = asm.cpi(); - asm.emitConstantPoolUTF8("(S)V"); - asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;"); + asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); - shortCtorIdx = asm.cpi(); + shortBoxIdx = asm.cpi(); asm.emitConstantPoolUTF8("shortValue"); asm.emitConstantPoolUTF8("()S"); asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); @@ -515,23 +522,23 @@ class AccessorGenerator implements ClassFileConstants { throw new InternalError("Should have found primitive type"); } - protected short ctorIndexForPrimitiveType(Class type) { + protected short boxingMethodForPrimitiveType(Class type) { if (type == Boolean.TYPE) { - return booleanCtorIdx; + return booleanBoxIdx; } else if (type == Byte.TYPE) { - return byteCtorIdx; + return byteBoxIdx; } else if (type == Character.TYPE) { - return characterCtorIdx; + return characterBoxIdx; } else if (type == Double.TYPE) { - return doubleCtorIdx; + return doubleBoxIdx; } else if (type == Float.TYPE) { - return floatCtorIdx; + return floatBoxIdx; } else if (type == Integer.TYPE) { - return integerCtorIdx; + return integerBoxIdx; } else if (type == Long.TYPE) { - return longCtorIdx; + return longBoxIdx; } else if (type == Short.TYPE) { - return shortCtorIdx; + return shortBoxIdx; } throw new InternalError("Should have found primitive type"); } diff --git a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java b/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java index 55a71c84248..dfecd17423e 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java +++ b/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java @@ -660,9 +660,9 @@ class MethodAccessorGenerator extends AccessorGenerator { if (!isConstructor) { // Box return value if necessary if (isPrimitive(returnType)) { - cb.opc_invokespecial(ctorIndexForPrimitiveType(returnType), - typeSizeInStackSlots(returnType), - 0); + cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType), + typeSizeInStackSlots(returnType), + 0); } else if (returnType == Void.TYPE) { cb.opc_aconst_null(); } diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java index 8c7cdd451b5..cf929b762a9 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeBooleanFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Boolean(getBoolean(obj)); + return Boolean.valueOf(getBoolean(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java index 8095fc299e3..15564220ecf 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeByteFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Byte(getByte(obj)); + return Byte.valueOf(getByte(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java index bdf83bc27c1..bd27f00b1bd 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeCharacterFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Character(getChar(obj)); + return Character.valueOf(getChar(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java index df43f5967a6..a43ac29368b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeDoubleFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Double(getDouble(obj)); + return Double.valueOf(getDouble(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java index ca7789ac666..d2410987999 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeFloatFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Float(getFloat(obj)); + return Float.valueOf(getFloat(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java index 951a2202047..df802e3b2ad 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeIntegerFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Integer(getInt(obj)); + return Integer.valueOf(getInt(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java index 85fcf32847a..8e76ea193fe 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeLongFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Long(getLong(obj)); + return Long.valueOf(getLong(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java index 8e66c7fe0f1..cc31cb4910d 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedBooleanFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Boolean(getBoolean(obj)); + return Boolean.valueOf(getBoolean(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java index f3cc92808e5..ae239a807f4 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedByteFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Byte(getByte(obj)); + return Byte.valueOf(getByte(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java index 247e3b231e5..e322e1d3e04 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedCharacterFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Character(getChar(obj)); + return Character.valueOf(getChar(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java index c7b2ae1f258..1fb71f5c447 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedDoubleFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Double(getDouble(obj)); + return Double.valueOf(getDouble(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java index c06af79e501..0b7906d4830 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedFloatFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Float(getFloat(obj)); + return Float.valueOf(getFloat(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java index b675158352d..df737fd0119 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedIntegerFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Integer(getInt(obj)); + return Integer.valueOf(getInt(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java index 50fa38dcdd0..b77d4d1d9e9 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedLongFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Long(getLong(obj)); + return Long.valueOf(getLong(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java index fddfef24f5c..c5ea9bb6caa 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedShortFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Short(getShort(obj)); + return Short.valueOf(getShort(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java index 5b1e3f3ee8c..65dabb0fba6 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticBooleanFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Boolean(getBoolean(obj)); + return Boolean.valueOf(getBoolean(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java index a3e087e3469..136728b4594 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticByteFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Byte(getByte(obj)); + return Byte.valueOf(getByte(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java index c171064ec67..6015baf82a8 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticCharacterFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Character(getChar(obj)); + return Character.valueOf(getChar(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java index 4acd9f5221b..5433b4ec82a 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticDoubleFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Double(getDouble(obj)); + return Double.valueOf(getDouble(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java index 86eb74e89de..fe69684c1d8 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticFloatFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Float(getFloat(obj)); + return Float.valueOf(getFloat(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java index 7ddcd8c637c..3e420f92a39 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticIntegerFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Integer(getInt(obj)); + return Integer.valueOf(getInt(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java index 97da2f256c8..d25f4ac8a56 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticLongFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Long(getLong(obj)); + return Long.valueOf(getLong(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java index 4caf4d1da00..631bd7ae333 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java @@ -35,7 +35,7 @@ class UnsafeQualifiedStaticShortFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Short(getShort(obj)); + return Short.valueOf(getShort(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java index d8fe8dc96ec..05ea337f49c 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeShortFieldAccessorImpl extends UnsafeFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Short(getShort(obj)); + return Short.valueOf(getShort(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java index 741c5ff48c2..b7572b54e31 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticBooleanFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Boolean(getBoolean(obj)); + return Boolean.valueOf(getBoolean(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java index 726961ba8a2..78eeb86842f 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticByteFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Byte(getByte(obj)); + return Byte.valueOf(getByte(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java index 29b030375a7..2dd3a597681 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticCharacterFieldAccessorImpl extends UnsafeStaticFieldAccessorIm } public Object get(Object obj) throws IllegalArgumentException { - return new Character(getChar(obj)); + return Character.valueOf(getChar(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java index 34c9784466b..b07df4f987f 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticDoubleFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Double(getDouble(obj)); + return Double.valueOf(getDouble(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java index 780a794cf75..2929727b6ad 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticFloatFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Float(getFloat(obj)); + return Float.valueOf(getFloat(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java index 1b21b766d09..963620a06fb 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticIntegerFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl } public Object get(Object obj) throws IllegalArgumentException { - return new Integer(getInt(obj)); + return Integer.valueOf(getInt(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java index 7d50ac2db9c..a8dedd060cc 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticLongFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Long(getLong(obj)); + return Long.valueOf(getLong(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java index d56d621e227..9ac6cd6533b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java @@ -33,7 +33,7 @@ class UnsafeStaticShortFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl { } public Object get(Object obj) throws IllegalArgumentException { - return new Short(getShort(obj)); + return Short.valueOf(getShort(obj)); } public boolean getBoolean(Object obj) throws IllegalArgumentException { diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 4c423b703a7..78d9f3ed6cb 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -615,7 +615,9 @@ public final class ZoneInfoFile { // startTime=86400000 <= 24 hours // This: startDayOfWeek=6 // startTime=0 - // Below is the workaround, it probably slows down everyone a little + // Similar workaround needs to be applied to Africa/Cairo and + // its endDayOfWeek and endTime + // Below is the workarounds, it probably slows down everyone a little if (params[2] == 6 && params[3] == 0 && (zoneId.equals("Asia/Amman") || zoneId.equals("Asia/Gaza") || @@ -623,6 +625,13 @@ public final class ZoneInfoFile { params[2] = 5; params[3] = 86400000; } + //endDayOfWeek and endTime workaround + if (params[7] == 6 && params[8] == 0 && + (zoneId.equals("Africa/Cairo"))) { + params[7] = 5; + params[8] = 86400000; + } + } else if (nTrans > 0) { // only do this if there is something in table already if (lastyear < LASTYEAR) { // ZoneInfo has an ending entry for 2037 diff --git a/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java index 298a233d850..9ab92c93620 100644 --- a/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java +++ b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java @@ -47,9 +47,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String ACT[] = new String[] {"Acre Time", "ACT", "Acre Summer Time", "ACST", "Acre Time", "ACT"}; - String ADELAIDE[] = new String[] {"Central Standard Time (South Australia)", "CST", - "Central Summer Time (South Australia)", "CST", - "Central Time (South Australia)", "CT"}; + String ADELAIDE[] = new String[] {"Australian Central Standard Time (South Australia)", "ACST", + "Australian Central Daylight Time (South Australia)", "ACDT", + "Australian Central Time (South Australia)", "ACT"}; String AGT[] = new String[] {"Argentine Time", "ART", "Argentine Summer Time", "ARST", "Argentine Time", "ART"}; @@ -71,12 +71,12 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String BDT[] = new String[] {"Bangladesh Time", "BDT", "Bangladesh Summer Time", "BDST", "Bangladesh Time", "BDT"}; - String BRISBANE[] = new String[] {"Eastern Standard Time (Queensland)", "EST", - "Eastern Summer Time (Queensland)", "EST", - "Eastern Time (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Central Standard Time (South Australia/New South Wales)", "CST", - "Central Summer Time (South Australia/New South Wales)", "CST", - "Central Time (South Australia/New South Wales)", "CT"}; + String BRISBANE[] = new String[] {"Australian Eastern Standard Time (Queensland)", "AEST", + "Australian Eastern Daylight Time (Queensland)", "AEDT", + "Australian Eastern Time (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Australian Central Standard Time (South Australia/New South Wales)", "ACST", + "Australian Central Daylight Time (South Australia/New South Wales)", "ACDT", + "Australian Central Time (South Australia/New South Wales)", "ACT"}; String BRT[] = new String[] {"Brasilia Time", "BRT", "Brasilia Summer Time", "BRST", "Brasilia Time", "BRT"}; @@ -110,9 +110,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Cuba Standard Time", "CST", "Cuba Daylight Time", "CDT", "Cuba Time", "CT"}; - String DARWIN[] = new String[] {"Central Standard Time (Northern Territory)", "CST", - "Central Summer Time (Northern Territory)", "CST", - "Central Time (Northern Territory)", "CT"}; + String DARWIN[] = new String[] {"Australian Central Standard Time (Northern Territory)", "ACST", + "Australian Central Daylight Time (Northern Territory)", "ACDT", + "Australian Central Time (Northern Territory)", "ACT"}; String DUBLIN[] = new String[] {"Greenwich Mean Time", "GMT", "Irish Summer Time", "IST", "Irish Time", "IT"}; @@ -131,9 +131,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String EST[] = new String[] {"Eastern Standard Time", "EST", "Eastern Daylight Time", "EDT", "Eastern Time", "ET"}; - String EST_NSW[] = new String[] {"Eastern Standard Time (New South Wales)", "EST", - "Eastern Summer Time (New South Wales)", "EST", - "Eastern Time (New South Wales)", "ET"}; + String EST_NSW[] = new String[] {"Australian Eastern Standard Time (New South Wales)", "AEST", + "Australian Eastern Daylight Time (New South Wales)", "AEDT", + "Australian Eastern Time (New South Wales)", "AET"}; String FET[] = new String[] {"Further-eastern European Time", "FET", "Further-eastern European Summer Time", "FEST", "Further-eastern European Time", "FET"}; @@ -167,6 +167,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String IRT[] = new String[] {"Iran Standard Time", "IRST", "Iran Daylight Time", "IRDT", "Iran Time", "IRT"}; + String IRKT[] = new String[] {"Irkutsk Time", "IRKT", + "Irkutsk Summer Time", "IRKST", + "Irkutsk Time", "IRKT"}; String ISRAEL[] = new String[] {"Israel Standard Time", "IST", "Israel Daylight Time", "IDT", "Israel Time", "IT"}; @@ -176,11 +179,14 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String JST[] = new String[] {"Japan Standard Time", "JST", "Japan Daylight Time", "JDT", "Japan Time", "JT"}; + String KRAT[] = new String[] {"Krasnoyarsk Time", "KRAT", + "Krasnoyarsk Summer Time", "KRAST", + "Krasnoyarsk Time", "KRAT"}; String KST[] = new String[] {"Korea Standard Time", "KST", "Korea Daylight Time", "KDT", "Korea Time", "KT"}; String LORD_HOWE[] = new String[] {"Lord Howe Standard Time", "LHST", - "Lord Howe Summer Time", "LHST", + "Lord Howe Daylight Time", "LHDT", "Lord Howe Time", "LHT"}; String MHT[] = new String[] {"Marshall Islands Time", "MHT", "Marshall Islands Summer Time", "MHST", @@ -230,21 +236,15 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String SGT[] = new String[] {"Singapore Time", "SGT", "Singapore Summer Time", "SGST", "Singapore Time", "SGT"}; - String SLST[] = new String[] {"Greenwich Mean Time", "GMT", - "Sierra Leone Summer Time", "SLST", - "Sierra Leone Time", "SLT"}; - String TASMANIA[] = new String[] {"Eastern Standard Time (Tasmania)", "EST", - "Eastern Summer Time (Tasmania)", "EST", - "Eastern Time (Tasmania)", "ET"}; + String TASMANIA[] = new String[] {"Australian Eastern Standard Time (Tasmania)", "AEST", + "Australian Eastern Daylight Time (Tasmania)", "AEDT", + "Australian Eastern Time (Tasmania)", "AET"}; String TMT[] = new String[] {"Turkmenistan Time", "TMT", "Turkmenistan Summer Time", "TMST", "Turkmenistan Time", "TMT"}; String ULAT[]= new String[] {"Ulaanbaatar Time", "ULAT", "Ulaanbaatar Summer Time", "ULAST", "Ulaanbaatar Time", "ULAT"}; - String WART[] = new String[] {"Western Argentine Time", "WART", - "Western Argentine Summer Time", "WARST", - "Western Argentine Time", "WART"}; String WAT[] = new String[] {"Western African Time", "WAT", "Western African Summer Time", "WAST", "Western African Time", "WAT"}; @@ -254,27 +254,30 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { String WIT[] = new String[] {"West Indonesia Time", "WIB", "West Indonesia Summer Time", "WIST", "West Indonesia Time", "WIB"}; - String WST_AUS[] = new String[] {"Western Standard Time (Australia)", "WST", - "Western Summer Time (Australia)", "WST", - "Western Time (Australia)", "WT"}; + String WST_AUS[] = new String[] {"Australian Western Standard Time", "AWST", + "Australian Western Daylight Time", "AWDT", + "Australian Western Time", "AWT"}; String SAMOA[] = new String[] {"Samoa Standard Time", "SST", "Samoa Daylight Time", "SDT", "Samoa Time", "ST"}; - String WST_SAMOA[] = new String[] {"West Samoa Time", "WST", + String WST_SAMOA[] = new String[] {"West Samoa Standard Time", "WSST", "West Samoa Daylight Time", "WSDT", "West Samoa Time", "WST"}; String ChST[] = new String[] {"Chamorro Standard Time", "ChST", "Chamorro Daylight Time", "ChDT", "Chamorro Time", "ChT"}; - String VICTORIA[] = new String[] {"Eastern Standard Time (Victoria)", "EST", - "Eastern Summer Time (Victoria)", "EST", - "Eastern Time (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"Australian Eastern Standard Time (Victoria)", "AEST", + "Australian Eastern Daylight Time (Victoria)", "AEDT", + "Australian Eastern Time (Victoria)", "AET"}; String UTC[] = new String[] {"Coordinated Universal Time", "UTC", "Coordinated Universal Time", "UTC", "Coordinated Universal Time", "UTC"}; String UZT[] = new String[] {"Uzbekistan Time", "UZT", "Uzbekistan Summer Time", "UZST", "Uzbekistan Time", "UZT"}; + String XJT[] = new String[] {"Xinjiang Standard Time", "XJT", + "Xinjiang Daylight Time", "XJDT", + "Xinjiang Time", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +339,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +440,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { "Western Greenland Summer Time", "WGST", "Western Greenland Time", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +487,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST", - "Metlakatla Daylight Time", "MeDT", - "Metlakatla Time", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Pierre & Miquelon Standard Time", "PMST", "Pierre & Miquelon Daylight Time", "PMDT", @@ -555,8 +556,8 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville Time", "DDUT", "Dumont-d'Urville Summer Time", "DDUST", "Dumont-d'Urville Time", "DDUT"}}, - {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST", - "Macquarie Island Summer Time", "MIST", + {"Antarctica/Macquarie", new String[] {"Macquarie Island Standard Time", "MIST", + "Macquarie Island Daylight Time", "MIDT", "Macquarie Island Time", "MIST"}}, {"Antarctica/Mawson", new String[] {"Mawson Time", "MAWT", "Mawson Summer Time", "MAWST", @@ -607,6 +608,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { "Brunei Summer Time", "BNST", "Brunei Time", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Choibalsan Time", "CHOT", "Choibalsan Summer Time", "CHOST", "Choibalsan Time", "CHOT"}}, @@ -631,9 +633,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Hovd Time", "HOVT", "Hovd Summer Time", "HOVST", "Hovd Time", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Irkutsk Time", "IRKT", - "Irkutsk Summer Time", "IRKST", - "Irkutsk Time", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"East Indonesia Time", "WIT", @@ -646,7 +646,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { "Petropavlovsk-Kamchatski Summer Time", "PETST", "Petropavlovsk-Kamchatski Time", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Khandyga Time", "YAKT", @@ -654,9 +654,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { "Khandyga Time", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Krasnoyarsk Time", "KRAT", - "Krasnoyarsk Summer Time", "KRAST", - "Krasnoyarsk Time", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -671,7 +669,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { "Philippines Time", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Oral Time", "ORAT", "Oral Summer Time", "ORAST", @@ -697,6 +695,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -709,7 +710,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Ust-Nera Time", "VLAT", "Ust-Nera Summer Time", "VLAST", "Ust-Nera Time", "VLAT"}}, @@ -751,9 +752,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST", - "Central Western Time (Australia)", "CWT"}}, + {"Australia/Eucla", new String[] {"Australian Central Western Standard Time", "ACWST", + "Australian Central Western Daylight Time", "ACWDT", + "Australian Central Western Time", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -819,7 +820,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -854,9 +855,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Volgograd Time", "VOLT", - "Volgograd Summer Time", "VOLST", - "Volgograd Time", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index d20d12fb053..82a4bc3aecd 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -36,6 +36,17 @@ import sun.misc.Unsafe; class WindowsNativeDispatcher { private WindowsNativeDispatcher() { } + /** + * HANDLE CreateEvent( + * LPSECURITY_ATTRIBUTES lpEventAttributes, + * BOOL bManualReset, + * BOOL bInitialState, + * PCTSTR lpName + * ); + */ + static native long CreateEvent(boolean bManualReset, boolean bInitialState) + throws WindowsException; + /** * HANDLE CreateFile( * LPCTSTR lpFileName, @@ -1041,6 +1052,25 @@ class WindowsNativeDispatcher { long pOverlapped) throws WindowsException; + + /** + * CancelIo( + * HANDLE hFile + * ) + */ + static native void CancelIo(long hFile) throws WindowsException; + + /** + * GetOverlappedResult( + * HANDLE hFile, + * LPOVERLAPPED lpOverlapped, + * LPDWORD lpNumberOfBytesTransferred, + * BOOL bWait + * ); + */ + static native int GetOverlappedResult(long hFile, long lpOverlapped) + throws WindowsException; + /** * BackupRead( * HANDLE hFile, diff --git a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index 6677c874348..737c485698f 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -25,9 +25,16 @@ package sun.nio.fs; -import java.nio.file.*; import java.io.IOException; -import java.util.*; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + import com.sun.nio.file.ExtendedWatchEventModifier; import sun.misc.Unsafe; @@ -42,7 +49,6 @@ class WindowsWatchService extends AbstractWatchService { private final static int WAKEUP_COMPLETION_KEY = 0; - private final Unsafe unsafe = Unsafe.getUnsafe(); // background thread to service I/O completion port private final Poller poller; @@ -82,7 +88,7 @@ class WindowsWatchService /** * Windows implementation of WatchKey. */ - private class WindowsWatchKey extends AbstractWatchKey { + private static class WindowsWatchKey extends AbstractWatchKey { // file key (used to detect existing registrations) private final FileKey fileKey; @@ -169,15 +175,9 @@ class WindowsWatchService return completionKey; } - // close directory and release buffer - void releaseResources() { - CloseHandle(handle); - buffer.cleaner().clean(); - } - - // Invalidate key by closing directory and releasing buffer + // Invalidate the key, assumes that resources have been released void invalidate() { - releaseResources(); + ((WindowsWatchService)watcher()).poller.releaseResources(this); handle = INVALID_HANDLE_VALUE; buffer = null; countAddress = 0; @@ -193,7 +193,7 @@ class WindowsWatchService public void cancel() { if (isValid()) { // delegate to poller - poller.cancel(this); + ((WindowsWatchService)watcher()).poller.cancel(this); } } } @@ -241,18 +241,25 @@ class WindowsWatchService /** * Background thread to service I/O completion port. */ - private class Poller extends AbstractPoller { + private static class Poller extends AbstractPoller { + private final static Unsafe UNSAFE = Unsafe.getUnsafe(); + /* * typedef struct _OVERLAPPED { - * DWORD Internal; - * DWORD InternalHigh; - * DWORD Offset; - * DWORD OffsetHigh; - * HANDLE hEvent; + * ULONG_PTR Internal; + * ULONG_PTR InternalHigh; + * union { + * struct { DWORD Offset; DWORD OffsetHigh; }; + * PVOID Pointer; + * }; + * HANDLE hEvent; * } OVERLAPPED; */ private static final short SIZEOF_DWORD = 4; private static final short SIZEOF_OVERLAPPED = 32; // 20 on 32-bit + private static final short OFFSETOF_HEVENT = + (UNSAFE.addressSize() == 4) ? (short) 16 : 24; + /* * typedef struct _FILE_NOTIFY_INFORMATION { @@ -276,10 +283,10 @@ class WindowsWatchService private final long port; // maps completion key to WatchKey - private final Map ck2key; + private final Map ck2key; // maps file key to WatchKey - private final Map fk2key; + private final Map fk2key; // unique completion key for each directory // native completion key capacity is 64 bits on Win64. @@ -393,8 +400,13 @@ class WindowsWatchService long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED; long countAddress = overlappedAddress - SIZEOF_DWORD; + // zero the overlapped structure + UNSAFE.setMemory(overlappedAddress, SIZEOF_OVERLAPPED, (byte)0); + // start async read of changes to directory try { + createAndAttachEvent(overlappedAddress); + ReadDirectoryChangesW(handle, bufferAddress, CHANGES_BUFFER_SIZE, @@ -403,6 +415,7 @@ class WindowsWatchService countAddress, overlappedAddress); } catch (WindowsException x) { + closeAttachedEvent(overlappedAddress); buffer.release(); return new IOException(x.getMessage()); } @@ -421,7 +434,7 @@ class WindowsWatchService // 2. release existing key's resources (handle/buffer) // 3. re-initialize key with new handle/buffer ck2key.remove(existing.completionKey()); - existing.releaseResources(); + releaseResources(existing); watchKey = existing.init(handle, events, watchSubtree, buffer, countAddress, overlappedAddress, completionKey); } @@ -436,6 +449,42 @@ class WindowsWatchService } } + /** + * Cancels the outstanding I/O operation on the directory + * associated with the given key and releases the associated + * resources. + */ + private void releaseResources(WindowsWatchKey key) { + try { + CancelIo(key.handle()); + GetOverlappedResult(key.handle(), key.overlappedAddress()); + } catch (WindowsException expected) { + // expected as I/O operation has been cancelled + } + CloseHandle(key.handle()); + closeAttachedEvent(key.overlappedAddress()); + key.buffer().cleaner().clean(); + } + + /** + * Creates an unnamed event and set it as the hEvent field + * in the given OVERLAPPED structure + */ + private void createAndAttachEvent(long ov) throws WindowsException { + long hEvent = CreateEvent(false, false); + UNSAFE.putAddress(ov + OFFSETOF_HEVENT, hEvent); + } + + /** + * Closes the event attached to the given OVERLAPPED structure. A + * no-op if there isn't an event attached. + */ + private void closeAttachedEvent(long ov) { + long hEvent = UNSAFE.getAddress(ov + OFFSETOF_HEVENT); + if (hEvent != 0 && hEvent != INVALID_HANDLE_VALUE) + CloseHandle(hEvent); + } + // cancel single key @Override void implCancelKey(WatchKey obj) { @@ -451,9 +500,8 @@ class WindowsWatchService @Override void implCloseAll() { // cancel all keys - for (Map.Entry entry: ck2key.entrySet()) { - entry.getValue().invalidate(); - } + ck2key.values().forEach(WindowsWatchKey::invalidate); + fk2key.clear(); ck2key.clear(); @@ -462,8 +510,7 @@ class WindowsWatchService } // Translate file change action into watch event - private WatchEvent.Kind translateActionToEvent(int action) - { + private WatchEvent.Kind translateActionToEvent(int action) { switch (action) { case FILE_ACTION_MODIFIED : return StandardWatchEventKinds.ENTRY_MODIFY; @@ -487,18 +534,18 @@ class WindowsWatchService int nextOffset; do { - int action = unsafe.getInt(address + OFFSETOF_ACTION); + int action = UNSAFE.getInt(address + OFFSETOF_ACTION); // map action to event WatchEvent.Kind kind = translateActionToEvent(action); if (key.events().contains(kind)) { // copy the name - int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FILENAMELENGTH); + int nameLengthInBytes = UNSAFE.getInt(address + OFFSETOF_FILENAMELENGTH); if ((nameLengthInBytes % 2) != 0) { - throw new AssertionError("FileNameLength.FileNameLength is not a multiple of 2"); + throw new AssertionError("FileNameLength is not a multiple of 2"); } char[] nameAsArray = new char[nameLengthInBytes/2]; - unsafe.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray, + UNSAFE.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray, Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes); // create FileName and queue event @@ -508,7 +555,7 @@ class WindowsWatchService } // next event - nextOffset = unsafe.getInt(address + OFFSETOF_NEXTENTRYOFFSET); + nextOffset = UNSAFE.getInt(address + OFFSETOF_NEXTENTRYOFFSET); address += (long)nextOffset; } while (nextOffset != 0); } diff --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c index 50c7630ebf8..abc9418a245 100644 --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c @@ -493,6 +493,9 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, } } } else { + /* NET_BindV6() closes both sockets upon a failure */ + (*env)->SetObjectField(env, this, pdsi_fdID, NULL); + (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL); NET_ThrowCurrent (env, "Cannot bind"); return; } diff --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c index ff86b249c44..facab5923f9 100644 --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c @@ -467,6 +467,10 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1); } } + } else { + /* NET_BindV6() closes both sockets upon a failure */ + (*env)->SetObjectField(env, this, psi_fdID, NULL); + (*env)->SetObjectField(env, this, psi_fd1ID, NULL); } } else { rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind); diff --git a/jdk/src/java.base/windows/native/libnet/net_util_md.c b/jdk/src/java.base/windows/native/libnet/net_util_md.c index 5f00f49dfd5..523973ba50f 100644 --- a/jdk/src/java.base/windows/native/libnet/net_util_md.c +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c @@ -627,7 +627,7 @@ void dumpAddr (char *str, void *addr) { * and returns SOCKET_ERROR. Used in NET_BindV6 only. */ -#define CLOSE_SOCKETS_AND_RETURN { \ +#define CLOSE_SOCKETS_AND_RETURN do { \ if (fd != -1) { \ closesocket (fd); \ fd = -1; \ @@ -646,7 +646,7 @@ void dumpAddr (char *str, void *addr) { } \ b->ipv4_fd = b->ipv6_fd = -1; \ return SOCKET_ERROR; \ -} +} while(0) /* * if ipv6 is available, call NET_BindV6 to bind to the required address/port. diff --git a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 94e060fa193..8075d046763 100644 --- a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -195,6 +195,17 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) } } +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateEvent(JNIEnv* env, jclass this, + jboolean bManualReset, jboolean bInitialState) +{ + HANDLE hEvent = CreateEventW(NULL, bManualReset, bInitialState, NULL); + if (hEvent == NULL) { + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(hEvent); +} + JNIEXPORT jstring JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_FormatMessage(JNIEnv* env, jclass this, jint errorCode) { WCHAR message[255]; @@ -1229,6 +1240,31 @@ Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, } } +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CancelIo(JNIEnv* env, jclass this, jlong hFile) { + if (CancelIo((HANDLE)jlong_to_ptr(hFile)) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetOverlappedResult(JNIEnv *env, jclass this, + jlong hFile, jlong lpOverlapped) +{ + BOOL res; + DWORD bytesTransferred = -1; + + res = GetOverlappedResult((HANDLE)jlong_to_ptr(hFile), + (LPOVERLAPPED)jlong_to_ptr(lpOverlapped), + &bytesTransferred, + TRUE); + if (res == 0) { + throwWindowsException(env, GetLastError()); + } + + return (jint)bytesTransferred; +} + JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclass this, jlong hDirectory, jlong bufferAddress, jint bufferLength, jboolean watchSubTree, jint filter, @@ -1236,17 +1272,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclas { BOOL res; BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE; - - /* Any unused members of [OVERLAPPED] structure should always be initialized to zero - before the structure is used in a function call. - Otherwise, the function may fail and return ERROR_INVALID_PARAMETER. - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx - - The [Offset] and [OffsetHigh] members of this structure are not used. - http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx - - [hEvent] should be zero, other fields are the return values. */ - ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED)); + LPOVERLAPPED ov = (LPOVERLAPPED)jlong_to_ptr(pOverlapped); res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory), (LPVOID)jlong_to_ptr(bufferAddress), diff --git a/jdk/src/java.management/share/classes/javax/management/loading/MLet.java b/jdk/src/java.management/share/classes/javax/management/loading/MLet.java index f5689334ffe..1a3fb18527b 100644 --- a/jdk/src/java.management/share/classes/javax/management/loading/MLet.java +++ b/jdk/src/java.management/share/classes/javax/management/loading/MLet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -1313,11 +1313,11 @@ public class MLet extends java.net.URLClassLoader if (type.compareTo("java.lang.Long") == 0) return Long.valueOf(param); if (type.compareTo("java.lang.Integer") == 0) - return param; + return Integer.valueOf(param); if (type.compareTo("java.lang.Float") == 0) - return new Float(param); + return Float.valueOf(param); if (type.compareTo("java.lang.Double") == 0) - return new Double(param); + return Double.valueOf(param); if (type.compareTo("java.lang.String") == 0) return param; diff --git a/jdk/src/java.management/share/classes/sun/management/Agent.java b/jdk/src/java.management/share/classes/sun/management/Agent.java index 01fb9423f64..6a8f710ecc0 100644 --- a/jdk/src/java.management/share/classes/sun/management/Agent.java +++ b/jdk/src/java.management/share/classes/sun/management/Agent.java @@ -210,6 +210,8 @@ public class Agent { } else { throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, "No port specified"); } + } catch (JdpException e) { + error(e); } catch (AgentConfigurationError err) { error(err.getError(), err.getParams()); } @@ -273,7 +275,7 @@ public class Agent { } private static void startDiscoveryService(Properties props) - throws IOException { + throws IOException, JdpException { // Start discovery service if requested String discoveryPort = props.getProperty("com.sun.management.jdp.port"); String discoveryAddress = props.getProperty("com.sun.management.jdp.address"); @@ -291,7 +293,7 @@ public class Agent { try{ shouldStart = Boolean.parseBoolean(discoveryShouldStart); } catch (NumberFormatException e) { - throw new AgentConfigurationError("Couldn't parse autodiscovery argument"); + throw new AgentConfigurationError(AGENT_EXCEPTION, "Couldn't parse autodiscovery argument"); } } @@ -302,7 +304,7 @@ public class Agent { address = (discoveryAddress == null) ? InetAddress.getByName(JDP_DEFAULT_ADDRESS) : InetAddress.getByName(discoveryAddress); } catch (UnknownHostException e) { - throw new AgentConfigurationError("Unable to broadcast to requested address", e); + throw new AgentConfigurationError(AGENT_EXCEPTION, e, "Unable to broadcast to requested address"); } int port = JDP_DEFAULT_PORT; @@ -310,7 +312,7 @@ public class Agent { try { port = Integer.parseInt(discoveryPort); } catch (NumberFormatException e) { - throw new AgentConfigurationError("Couldn't parse JDP port argument"); + throw new AgentConfigurationError(AGENT_EXCEPTION, "Couldn't parse JDP port argument"); } } @@ -330,12 +332,7 @@ public class Agent { String instanceName = props.getProperty("com.sun.management.jdp.name"); - try{ - JdpController.startDiscoveryService(address, port, instanceName, jmxUrlStr); - } - catch(JdpException e){ - throw new AgentConfigurationError("Couldn't start JDP service", e); - } + JdpController.startDiscoveryService(address, port, instanceName, jmxUrlStr); } } diff --git a/jdk/src/java.management/share/classes/sun/management/jdp/JdpBroadcaster.java b/jdk/src/java.management/share/classes/sun/management/jdp/JdpBroadcaster.java index b1766e6f7f6..cdb33ef7afa 100644 --- a/jdk/src/java.management/share/classes/sun/management/jdp/JdpBroadcaster.java +++ b/jdk/src/java.management/share/classes/sun/management/jdp/JdpBroadcaster.java @@ -35,6 +35,7 @@ import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.UnsupportedAddressTypeException; +import java.util.Enumeration; /** * JdpBroadcaster is responsible for sending pre-built JDP packet across a Net @@ -79,13 +80,49 @@ public final class JdpBroadcaster { if (srcAddress != null) { // User requests particular interface to bind to NetworkInterface interf = NetworkInterface.getByInetAddress(srcAddress); + + if (interf == null) { + throw new JdpException("Unable to get network interface for " + srcAddress.toString()); + } + + if (!interf.isUp()) { + throw new JdpException(interf.getName() + " is not up."); + } + + if (!interf.supportsMulticast()) { + throw new JdpException(interf.getName() + " does not support multicast."); + } + try { channel.bind(new InetSocketAddress(srcAddress, 0)); } catch (UnsupportedAddressTypeException ex) { throw new JdpException("Unable to bind to source address"); } channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, interf); + } else { + Enumeration nics = NetworkInterface.getNetworkInterfaces(); + boolean succeed = false; + + while (nics.hasMoreElements()) { + NetworkInterface nic = nics.nextElement(); + + if (nic.isUp() && nic.supportsMulticast()) { + try { + channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, nic); + succeed = true; + } catch (IOException ex) { + // pass + } + } + + } + + if (!succeed) { + throw new JdpException("Unable to bind to any interfaces."); + } + } + } /** diff --git a/jdk/src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java b/jdk/src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java index 532c3db0a3d..56d76734da5 100644 --- a/jdk/src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java +++ b/jdk/src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java @@ -28,8 +28,6 @@ package sun.tools.attach; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import com.sun.tools.attach.AttachNotSupportedException; -import com.sun.tools.attach.spi.AttachProvider; - import java.io.IOException; // Based on linux/classes/sun/tools/attach/AttachProviderImpl.java. @@ -40,9 +38,6 @@ import java.io.IOException; */ public class AttachProviderImpl extends HotSpotAttachProvider { - // perf counter for the JVM version - private static final String JVM_VERSION = "java.property.java.vm.version"; - public AttachProviderImpl() { } diff --git a/jdk/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java b/jdk/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java index a76d0a99771..cf96c51e9a9 100644 --- a/jdk/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/jdk/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java @@ -25,14 +25,12 @@ */ package sun.tools.attach; -import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; import java.io.InputStream; import java.io.IOException; import java.io.File; -import java.util.Properties; // Based on linux/classes/sun/tools/attach/VirtualMachineImpl.java. diff --git a/jdk/src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java b/jdk/src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java index adf8b01e6b4..fd89af02511 100644 --- a/jdk/src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java +++ b/jdk/src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java @@ -27,8 +27,6 @@ package sun.tools.attach; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import com.sun.tools.attach.AttachNotSupportedException; -import com.sun.tools.attach.spi.AttachProvider; - import java.io.IOException; /* @@ -37,9 +35,6 @@ import java.io.IOException; */ public class AttachProviderImpl extends HotSpotAttachProvider { - // perf counter for the JVM version - private static final String JVM_VERSION = "java.property.java.vm.version"; - public AttachProviderImpl() { } diff --git a/jdk/src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java b/jdk/src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java index 0f129769c0e..d44684f81af 100644 --- a/jdk/src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java +++ b/jdk/src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java @@ -27,8 +27,6 @@ package sun.tools.attach; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import com.sun.tools.attach.AttachNotSupportedException; -import com.sun.tools.attach.spi.AttachProvider; - import java.io.IOException; /* @@ -37,9 +35,6 @@ import java.io.IOException; */ public class AttachProviderImpl extends HotSpotAttachProvider { - // perf counter for the JVM version - private static final String JVM_VERSION = "java.property.java.vm.version"; - public AttachProviderImpl() { } diff --git a/jdk/src/jdk.attach/share/classes/com/sun/tools/attach/VirtualMachine.java b/jdk/src/jdk.attach/share/classes/com/sun/tools/attach/VirtualMachine.java index e735c2c775f..d5e934a6e2d 100644 --- a/jdk/src/jdk.attach/share/classes/com/sun/tools/attach/VirtualMachine.java +++ b/jdk/src/jdk.attach/share/classes/com/sun/tools/attach/VirtualMachine.java @@ -636,7 +636,7 @@ public abstract class VirtualMachine { * @throws NullPointerException * If agentProperties is null. * - * @since 1.9 + * @since 1.8 */ public abstract void startManagementAgent(Properties agentProperties) throws IOException; @@ -662,7 +662,7 @@ public abstract class VirtualMachine { * that cannot be identified as an error to indicate that the * operation failed in the target VM. * - * @since 1.9 + * @since 1.8 */ public abstract String startLocalManagementAgent() throws IOException; diff --git a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotAttachProvider.java b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotAttachProvider.java index c28dddad9d7..95faea9429e 100644 --- a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotAttachProvider.java +++ b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotAttachProvider.java @@ -25,34 +25,25 @@ package sun.tools.attach; import com.sun.tools.attach.VirtualMachineDescriptor; -import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.AttachPermission; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; -import java.io.IOException; import java.util.List; -import java.util.Iterator; import java.util.ArrayList; import java.util.Set; -import java.net.URISyntaxException; import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.Monitor; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.VmIdentifier; -import sun.jvmstat.monitor.MonitorException; /* * Platform specific provider implementations extend this */ public abstract class HotSpotAttachProvider extends AttachProvider { - // perf count name for the JVM version - private static final String JVM_VERSION = "java.property.java.vm.version"; - public HotSpotAttachProvider() { } diff --git a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java index bf2e9516525..4a9562b069f 100644 --- a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java +++ b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java @@ -30,8 +30,10 @@ import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.spi.AttachProvider; +import java.io.BufferedReader; import java.io.InputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.util.Properties; import java.util.stream.Collectors; @@ -188,7 +190,7 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine { .filter(entry -> checkedKeyName(entry.getKey())) .map(entry -> stripKeyName(entry.getKey()) + "=" + escape(entry.getValue())) .collect(Collectors.joining(" ")); - executeJCmd("ManagementAgent.start " + args); + executeJCmd("ManagementAgent.start " + args).close(); } private String escape(Object arg) { @@ -201,7 +203,7 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine { @Override public String startLocalManagementAgent() throws IOException { - executeJCmd("ManagementAgent.start_local"); + executeJCmd("ManagementAgent.start_local").close(); return getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); } @@ -305,11 +307,11 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine { * Utility method to read data into a String. */ String readErrorMessage(InputStream sis) throws IOException { - byte b[] = new byte[1024]; - int n; - StringBuffer message = new StringBuffer(); - while ((n = sis.read(b)) != -1) { - message.append(new String(b, 0, n, "UTF-8")); + String s; + StringBuilder message = new StringBuilder(); + BufferedReader br = new BufferedReader(new InputStreamReader(sis)); + while ((s = br.readLine()) != null) { + message.append(s); } return message.toString(); } diff --git a/jdk/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java b/jdk/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java index b044bb6965f..df0d8dc248e 100644 --- a/jdk/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java +++ b/jdk/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java @@ -27,7 +27,6 @@ package sun.tools.attach; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import com.sun.tools.attach.AttachNotSupportedException; -import com.sun.tools.attach.spi.AttachProvider; import java.io.IOException; /* diff --git a/jdk/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java b/jdk/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java index 8eabefa403c..84d2a36c38d 100644 --- a/jdk/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/jdk/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java @@ -107,6 +107,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { if (status != 0) { // read from the stream and use that as the error message String message = readErrorMessage(is); + is.close(); // special case the load command so that the right exception is thrown if (cmd.equals("load")) { throw new AgentLoadException("Failed to load agent library"); diff --git a/jdk/src/java.base/share/conf/security/sunpkcs11-solaris.cfg b/jdk/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg similarity index 100% rename from jdk/src/java.base/share/conf/security/sunpkcs11-solaris.cfg rename to jdk/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/de/TimeZoneNames_de.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/de/TimeZoneNames_de.java index ea7ab573a71..9b4e6503d84 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/de/TimeZoneNames_de.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/de/TimeZoneNames_de.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String ACT[] = new String[] {"Acre Normalzeit", "ACT", "Acre Sommerzeit", "ACST", "Acre Normalzeit", "ACT"}; - String ADELAIDE[] = new String[] {"Zentrale Normalzeit (S\u00FCdaustralien)", "CST", - "Zentrale Sommerzeit (S\u00FCdaustralien)", "CST", - "Zentrale Zeitzone (S\u00FCdaustralien)", "CT"}; + String ADELAIDE[] = new String[] {"Zentrale Normalzeit (S\u00FCdaustralien)", "ACST", + "Zentrale Sommerzeit (S\u00FCdaustralien)", "ACDT", + "Zentrale Zeitzone (S\u00FCdaustralien)", "ACT"}; String AGT[] = new String[] {"Argentinische Zeit", "ART", "Argentinische Sommerzeit", "ARST", "Argentinische Zeit", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String BDT[] = new String[] {"Bangladesch Zeit", "BDT", "Bangladesch Sommerzeit", "BDST", "Bangladesch Zeit", "BDT"}; - String BRISBANE[] = new String[] {"\u00D6stliche Normalzeit (Queensland)", "EST", - "\u00D6stliche Sommerzeit (Queensland)", "EST", - "\u00D6stliche Zeitzone (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Zentrale Normalzeit (S\u00FCdaustralien/New South Wales)", "CST", - "Zentrale Sommerzeit (S\u00FCdaustralien/New South Wales)", "CST", - "Zentrale Zeitzone (S\u00FCdaustralien/New South Wales)", "CT"}; + String BRISBANE[] = new String[] {"\u00D6stliche Normalzeit (Queensland)", "AEST", + "\u00D6stliche Sommerzeit (Queensland)", "AEDT", + "\u00D6stliche Zeitzone (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Zentrale Normalzeit (S\u00FCdaustralien/New South Wales)", "ACST", + "Zentrale Sommerzeit (S\u00FCdaustralien/New South Wales)", "ACDT", + "Zentrale Zeitzone (S\u00FCdaustralien/New South Wales)", "ACT"}; String BRT[] = new String[] {"Brasilianische Zeit", "BRT", "Brasilianische Sommerzeit", "BRST", "Brasilianische Zeit", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Kubanische Normalzeit", "CST", "Kubanische Sommerzeit", "CDT", "Kubanische Normalzeit", "CT"}; - String DARWIN[] = new String[] {"Zentrale Normalzeit (Northern Territory)", "CST", - "Zentrale Sommerzeit (Northern Territory)", "CST", - "Zentrale Zeitzone (Northern Territory)", "CT"}; + String DARWIN[] = new String[] {"Zentrale Normalzeit (Northern Territory)", "ACST", + "Zentrale Sommerzeit (Northern Territory)", "ACDT", + "Zentrale Zeitzone (Northern Territory)", "ACT"}; String DUBLIN[] = new String[] {"Greenwich Zeit", "GMT", "Irische Sommerzeit", "IST", "Irische Zeit", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String EST[] = new String[] {"\u00d6stliche Normalzeit", "EST", "\u00d6stliche Sommerzeit", "EDT", "\u00D6stliche Zeitzone", "ET"}; - String EST_NSW[] = new String[] {"\u00D6stliche Normalzeit (New South Wales)", "EST", - "\u00D6stliche Sommerzeit (New South Wales)", "EST", - "\u00D6stliche Zeitzone (New South Wales)", "ET"}; + String EST_NSW[] = new String[] {"\u00D6stliche Normalzeit (New South Wales)", "AEST", + "\u00D6stliche Sommerzeit (New South Wales)", "AEDT", + "\u00D6stliche Zeitzone (New South Wales)", "AET"}; String FET[] = new String[] {"Kaliningrader Zeit", "FET", "Kaliningrader Sommerzeit", "FEST", "Kaliningrader Zeit", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String ICT[] = new String[] {"Indochina Zeit", "ICT", "Indochina Sommerzeit", "ICST", "Indochina Zeit", "ICT"}; + String IRKT[] = new String[] {"Irkutsk Zeit", "IRKT", + "Irkutsk Sommerzeit", "IRKST", + "Irkutsk Zeit", "IRKT"}; String IRT[] = new String[] {"Iranische Normalzeit", "IRST", "Iranische Sommerzeit", "IRDT", "Iranische Zeit", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String JST[] = new String[] {"Japanische Normalzeit", "JST", "Japanische Sommerzeit", "JDT", "Zeitzone f\u00FCr Japan", "JT"}; + String KRAT[] = new String[] {"Krasnojarsker Zeit", "KRAT", + "Krasnojarsker Sommerzeit", "KRAST", + "Krasnojarsker Zeit", "KRAT"}; String KST[] = new String[] {"Koreanische Normalzeit", "KST", "Koreanische Sommerzeit", "KDT", "Zeitzone f\u00FCr Korea", "KT"}; String LORD_HOWE[] = new String[] {"Lord Howe Normalzeit", "LHST", - "Lord Howe Sommerzeit", "LHST", + "Lord Howe Sommerzeit", "LHDT", "Lord-Howe Normalzeit", "LHT"}; String MHT[] = new String[] {"Marshallinseln Zeit", "MHT", "Marshallinseln Sommerzeit", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String SGT[] = new String[] {"Singapur Zeit", "SGT", "Singapur Sommerzeit", "SGST", "Singapur Zeit", "SGT"}; - String SLST[] = new String[] {"Greenwich Normalzeit", "GMT", - "Sierra Leone Sommerzeit", "SLST", - "Sierra Leone Zeit", "SLT"}; - String TASMANIA[] = new String[] {"\u00D6stliche Normalzeit (Tasmanien)", "EST", - "\u00D6stliche Sommerzeit (Tasmanien)", "EST", - "\u00D6stliche Zeitzone (Tasmanien)", "ET"}; + String TASMANIA[] = new String[] {"\u00D6stliche Normalzeit (Tasmanien)", "AEST", + "\u00D6stliche Sommerzeit (Tasmanien)", "AEDT", + "\u00D6stliche Zeitzone (Tasmanien)", "AET"}; String TMT[] = new String[] {"Turkmenische Zeit", "TMT", "Turkmenische Sommerzeit", "TMST", "Turkmenische Zeit", "TMT"}; String ULAT[]= new String[] {"Ulaanbaatar Zeit", "ULAT", "Ulaanbaatar Sommerzeit", "ULAST", "Ulaanbaatar Zeit", "ULAT"}; - String WART[] = new String[] {"Westargentinische Zeit", "WART", - "Westargentinische Sommerzeit", "WARST"}; String WAT[] = new String[] {"Westafrikanische Zeit", "WAT", "Westafrikanische Sommerzeit", "WAST", "Westafrikanische Zeit", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { String WIT[] = new String[] {"Westindonesische Zeit", "WIB", "Westindonesische Sommerzeit", "WIST", "Westindonesische Zeit", "WIB"}; - String WST_AUS[] = new String[] {"Westliche Normalzeit (Australien)", "WST", - "Westliche Sommerzeit (Australien)", "WST", - "Westliche Zeitzone (Australien)", "WT"}; + String WST_AUS[] = new String[] {"Westliche Normalzeit (Australien)", "AWST", + "Westliche Sommerzeit (Australien)", "AWDT", + "Westliche Zeitzone (Australien)", "AWT"}; String SAMOA[] = new String[] {"Samoa Normalzeit", "SST", "Samoa Sommerzeit", "SDT", "Zeitzone f\u00FCr Samoa", "ST"}; - String WST_SAMOA[] = new String[] {"West Samoa Zeit", "WST", + String WST_SAMOA[] = new String[] {"West Samoa Zeit", "WSST", "West Samoa Sommerzeit", "WSDT", "West Samoa Zeit", "WST"}; String ChST[] = new String[] {"Chamorro Normalzeit", "ChST", "Chamorro Sommerzeit", "ChDT", "Zeitzone f\u00FCr die Marianen", "ChT"}; - String VICTORIA[] = new String[] {"\u00D6stliche Normalzeit (Victoria)", "EST", - "\u00D6stliche Sommerzeit (Victoria)", "EST", - "\u00D6stliche Zeitzone (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"\u00D6stliche Normalzeit (Victoria)", "AEST", + "\u00D6stliche Sommerzeit (Victoria)", "AEDT", + "\u00D6stliche Zeitzone (Victoria)", "AET"}; String UTC[] = new String[] {"Koordinierte Universalzeit", "UTC", "Koordinierte Universalzeit", "UTC", "Koordinierte Universalzeit", "UTC"}; String UZT[] = new String[] {"Usbekistan Zeit", "UZT", "Usbekistan Sommerzeit", "UZST", "Usbekistan Zeit", "UZT"}; + String XJT[] = new String[] {"Chinesische Normalzeit", "XJT", + "Chinesische Sommerzeit", "XJDT", + "Zeitzone f\u00FCr China", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Westgr\u00f6nl\u00e4ndische Sommerzeit", "WGST", "Westgr\u00F6nl\u00E4ndische Zeit", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Metlakatla Normalzeit", "MeST", - "Metlakatla Sommerzeit", "MeDT", - "Metlakatla Normalzeit", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Pierre & Miquelon Normalzeit", "PMST", "Pierre & Miquelon Sommerzeit", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Brunei Sommerzeit", "BNST", "Brunei Zeit", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Choibalsan Zeit", "CHOT", "Choibalsan Sommerzeit", "CHOST", "Choibalsan Zeit", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Hovd Zeit", "HOVT", "Hovd Sommerzeit", "HOVST", "Hovd Zeit", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Irkutsk Zeit", "IRKT", - "Irkutsk Sommerzeit", "IRKST", - "Irkutsk Zeit", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"Ostindonesische Zeit", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Petropawlowsk-Kamtschatkische Sommerzeit", "PETST", "Petropawlowsk-Kamtschatkische Zeit", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Chandyga Zeit", "YAKT", "Chandyga Sommerzeit", "YAKST", "Chandyga Zeit", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Krasnojarsker Zeit", "KRAT", - "Krasnojarsker Sommerzeit", "KRAST", - "Krasnojarsker Zeit", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Philippinische Zeit", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Oral Zeit", "ORAT", "Oral Sommerzeit", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Ust-Nera Zeit", "VLAT", "Ust-Nera Sommerzeit", "VLAST", "Ust-Nera Zeit", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Zentral-Westliche Normalzeit (Australien)", "CWST", - "Zentral-Westliche Sommerzeit (Australien)", "CWST", - "Zentral-Westliche Normalzeit (Australien)", "CWT"}}, + {"Australia/Eucla", new String[] {"Zentral-Westliche Normalzeit (Australien)", "ACWST", + "Zentral-Westliche Sommerzeit (Australien)", "ACWDT", + "Zentral-Westliche Normalzeit (Australien)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Wolgograder Zeit", "VOLT", - "Wolgograder Sommerzeit", "VOLST", - "Wolgograder Zeit", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/es/TimeZoneNames_es.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/es/TimeZoneNames_es.java index c35c80963be..0235158296c 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/es/TimeZoneNames_es.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/es/TimeZoneNames_es.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String ACT[] = new String[] {"Hora de Acre", "ACT", "Hora de verano de Acre", "ACST", "Hora de Acre", "ACT"}; - String ADELAIDE[] = new String[] {"Hora est\u00E1ndar Central (Sur de Australia)", "CST", - "Hora de verano Central (Sur de Australia)", "CST", - "Hora Central (Australia del Sur)", "CT"}; + String ADELAIDE[] = new String[] {"Hora est\u00E1ndar Central (Sur de Australia)", "ACST", + "Hora de verano Central (Sur de Australia)", "ACDT", + "Hora Central (Australia del Sur)", "ACT"}; String AGT[] = new String[] {"Hora de Argentina", "ART", "Hora de verano de Argentina", "ARST", "Hora de Argentina", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String BDT[] = new String[] {"Hora de Bangladesh", "BDT", "Hora de verano de Bangladesh", "BDST", "Hora de Bangladesh", "BDT"}; - String BRISBANE[] = new String[] {"Hora est\u00E1ndar del Este (Queensland)", "EST", - "Hora est\u00E1ndar de verano del Este (Queensland)", "EST", - "Hora Oriental (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Hora est\u00E1ndar Central (Sur de Australia/Nueva Gales del Sur)", "CST", - "Hora de verano Central (Sur de Australia/Nueva Gales del Sur)", "CST", - "Hora Central (Australia del Sur/Nueva Gales del Sur)", "CT"}; + String BRISBANE[] = new String[] {"Hora est\u00E1ndar del Este (Queensland)", "AEST", + "Hora est\u00E1ndar de verano del Este (Queensland)", "AEDT", + "Hora Oriental (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Hora est\u00E1ndar Central (Sur de Australia/Nueva Gales del Sur)", "ACST", + "Hora de verano Central (Sur de Australia/Nueva Gales del Sur)", "ACDT", + "Hora Central (Australia del Sur/Nueva Gales del Sur)", "ACT"}; String BRT[] = new String[] {"Hora de Brasil", "BRT", "Hora de verano de Brasil", "BRST", "Hora de Brasil", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Hora est\u00e1ndar de Cuba", "CST", "Hora de verano de Cuba", "CDT", "Hora de Cuba", "CT"}; - String DARWIN[] = new String[] {"Hora est\u00E1ndar Central (territorio del Norte)", "CST", - "Hora de verano Central (territorio del Norte)", "CST", - "Hora Central (Territorio Septentrional)", "CT"}; + String DARWIN[] = new String[] {"Hora est\u00E1ndar Central (territorio del Norte)", "ACST", + "Hora de verano Central (territorio del Norte)", "ACDT", + "Hora Central (Territorio Septentrional)", "ACT"}; String DUBLIN[] = new String[] {"Hora del Meridiano de Greenwich", "GMT", "Hora de verano de Irlanda", "IST", "Hora de Irlanda", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String EST[] = new String[] {"Hora est\u00e1ndar Oriental", "EST", "Hora de verano Oriental", "EDT", "Hora Oriental", "ET"}; - String EST_NSW[] = new String[] {"Hora est\u00E1ndar Oriental (Nueva Gales del Sur)", "EST", - "Hora de verano Oriental (Nueva Gales del Sur)", "EST", - "Hora Oriental (Nueva Gales del Sur)", "ET"}; + String EST_NSW[] = new String[] {"Hora est\u00E1ndar Oriental (Nueva Gales del Sur)", "AEST", + "Hora de verano Oriental (Nueva Gales del Sur)", "AEDT", + "Hora Oriental (Nueva Gales del Sur)", "AET"}; String FET[] = new String[] {"Hora de Europa m\u00E1s Oriental", "FET", "Hora de verano de Europa m\u00E1s Oriental", "FEST", "Hora de Europa m\u00E1s Oriental", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String ICT[] = new String[] {"Hora de Indochina", "ICT", "Hora de verano de Indochina", "ICST", "Hora de Indochina", "ICT"}; + String IRKT[] = new String[] {"Hora de Irkutsk", "IRKT", + "Hora de verano de Irkutsk", "IRKST", + "Hora de Irkutsk", "IRKT"}; String IRT[] = new String[] {"Hora est\u00e1ndar de Ir\u00e1n", "IRST", "Hora de verano de Ir\u00e1n", "IRDT", "Hora de Ir\u00E1n", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String JST[] = new String[] {"Hora est\u00e1ndar de Jap\u00f3n", "JST", "Hora de verano de Jap\u00f3n", "JDT", "Hora de Jap\u00F3n", "JT"}; + String KRAT[] = new String[] {"Hora de Krasnoyarsk", "KRAT", + "Hora de verano de Krasnoyarsk", "KRAST", + "Hora de Krasnoyarsk", "KRAT"}; String KST[] = new String[] {"Hora est\u00e1ndar de Corea", "KST", "Hora de verano de Corea", "KDT", "Hora de Corea", "KT"}; String LORD_HOWE[] = new String[] {"Hora est\u00e1ndar de Lord Howe", "LHST", - "Hora de verano de Lord Howe", "LHST", + "Hora de verano de Lord Howe", "LHDT", "Hora de Lord Howe", "LHT"}; String MHT[] = new String[] {"Hora de las Islas Marshall", "MHT", "Hora de verano de las Islas Marshall", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String SGT[] = new String[] {"Hora de Singapur", "SGT", "Hora de verano de Singapur", "SGST", "Hora de Singapur", "SGT"}; - String SLST[] = new String[] {"Hora del Meridiano de Greenwich", "GMT", - "Hora de verano de Sierra Leona", "SLST", - "Horario de Sierra Leona", "SLT"}; - String TASMANIA[] = new String[] {"Hora est\u00E1ndar del Este (Tasmania)", "EST", - "Hora de verano del Este (Tasmania)", "EST", - "Hora Oriental (Tasmania)", "ET"}; + String TASMANIA[] = new String[] {"Hora est\u00E1ndar del Este (Tasmania)", "AEST", + "Hora de verano del Este (Tasmania)", "AEDT", + "Hora Oriental (Tasmania)", "AET"}; String TMT[] = new String[] {"Hora de Turkmenist\u00e1n", "TMT", "Hora de verano de Turkmenist\u00e1n", "TMST", "Hora de Turkmenist\u00E1n", "TMT"}; String ULAT[]= new String[] {"Hora de Ulan Bator", "ULAT", "Hora de verano de Ulan Bator", "ULAST", "Hora de Ulan Bator", "ULAT"}; - String WART[] = new String[] {"Hora de Argentina Occidental", "WART", - "Hora de verano de Argentina Occidental", "WARST"}; String WAT[] = new String[] {"Hora de \u00c1frica Occidental", "WAT", "Hora de verano de \u00c1frica Occidental", "WAST", "Hora de \u00C1frica Occidental", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { String WIT[] = new String[] {"Hora de Indonesia Occidental", "WIB", "Indonesia Hora de verano de Indonesia Occidental", "WIST", "Hora de Indonesia Occidental", "WIB"}; - String WST_AUS[] = new String[] {"Hora est\u00E1ndar Occidental (Australia)", "WST", - "Hora de verano Occidental (Australia)", "WST", - "Hora Occidental (Australia)", "WT"}; + String WST_AUS[] = new String[] {"Hora est\u00E1ndar Occidental (Australia)", "AWST", + "Hora de verano Occidental (Australia)", "AWDT", + "Hora Occidental (Australia)", "AWT"}; String SAMOA[] = new String[] {"Hora est\u00e1ndar de Samoa", "SST", "Hora de verano de Samoa", "SDT", "Hora de Samoa", "ST"}; - String WST_SAMOA[] = new String[] {"Hora de Samoa Occidental", "WST", + String WST_SAMOA[] = new String[] {"Hora de Samoa Occidental", "WSST", "Hora de verano de Samoa Occidental", "WSDT", "Hora de Samoa Occidental", "WST"}; String ChST[] = new String[] {"Hora est\u00e1ndar de Chamorro", "ChST", "Hora de verano de Chamorro", "ChDT", "Hora de Chamorro", "ChT"}; - String VICTORIA[] = new String[] {"Hora est\u00E1ndar del Este (Victoria)", "EST", - "Hora de verano del Este (Victoria)", "EST", - "Hora Oriental (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"Hora est\u00E1ndar del Este (Victoria)", "AEST", + "Hora de verano del Este (Victoria)", "AEDT", + "Hora Oriental (Victoria)", "AET"}; String UTC[] = new String[] {"Hora Universal Coordinada", "UTC", "Hora Universal Coordinada", "UTC", "Hora Universal Coordinada", "UTC"}; String UZT[] = new String[] {"Hora de Uzbekist\u00e1n", "UZT", "Hora de verano de Uzbekist\u00e1n", "UZST", "Hora de Uzbekist\u00E1n", "UZT"}; + String XJT[] = new String[] {"Hora est\u00e1ndar de China", "XJT", + "Hora de verano de China", "XJDT", + "Hora de China", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de verano de Groenlandia Occidental", "WGST", "Hora de Groenlandia Occidental", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Hora de Metlakatla", "MeST", - "Hora de verano de Metlakatla", "MeDT", - "Metlakatla Time", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Hora est\u00e1ndar de Pierre & Miquelon", "PMST", "Hora de verano de Pierre & Miquelon", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de verano de Brunei", "BNST", "Hora de Brunei", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Hora de Choibalsan", "CHOT", "Hora de verano de Choibalsan", "CHOST", "Hora de Choibalsan", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Hora de Hovd", "HOVT", "Hora de verano de Hovd", "HOVST", "Hora de Hovd", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Hora de Irkutsk", "IRKT", - "Hora de verano de Irkutsk", "IRKST", - "Hora de Irkutsk", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"Hora de Indonesia Oriental", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de verano de Petropavlovsk-Kamchatski", "PETST", "Hora de Petropavlovsk-Kamchatski", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Hora de Khandyga", "YAKT", "Hora de verano de Khandyga", "YAKST", "Hora de Khandyga", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Hora de Krasnoyarsk", "KRAT", - "Hora de verano de Krasnoyarsk", "KRAST", - "Hora de Krasnoyarsk", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de Filipinas", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Hora de Uralsk", "ORAT", "Hora de verano de Uralsk", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Hora de Ust-Nera", "VLAT", "Hora de verano de Ust-Nera", "VLAST", "Hora de Ust-Nera", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Hora est\u00E1ndar de Australia Central y Occidental", "CWST", - "Hora est\u00E1ndar de verano de Australia Central y Occidental", "CWST", - "Hora de Australia Central y Occidental", "CWT"}}, + {"Australia/Eucla", new String[] {"Hora est\u00E1ndar de Australia Central y Occidental", "ACWST", + "Hora est\u00E1ndar de verano de Australia Central y Occidental", "ACWDT", + "Hora de Australia Central y Occidental", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Hora de Volgogrado", "VOLT", - "Hora de verano de Volgogrado", "VOLST", - "Hora de Volgogrado", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java index 393e45d4549..1d8b8561299 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String ACT[] = new String[] {"Heure de l'Acre", "ACT", "Heure d'\u00e9t\u00e9 de l'Acre", "ACST", "Heure de l'Acre", "ACT"}; - String ADELAIDE[] = new String[] {"Heure standard d'Australie centrale (Australie du sud)", "CST", - "Heure d'\u00E9t\u00E9 d'Australie centrale (Australie du sud)", "CST", - "Centre (Australie-M\u00E9ridionale)", "CT"}; + String ADELAIDE[] = new String[] {"Heure standard d'Australie centrale (Australie du sud)", "ACST", + "Heure d'\u00E9t\u00E9 d'Australie centrale (Australie du sud)", "ACDT", + "Centre (Australie-M\u00E9ridionale)", "ACT"}; String AGT[] = new String[] {"Heure D'Argentine", "ART", "Heure d'\u00e9t\u00e9 D'Argentine", "ARST", "Heure d'Argentine", "ART"} ; @@ -72,12 +72,12 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String BDT[] = new String[] {"Heure du Bangladesh", "BDT", "Heure d'\u00e9t\u00e9 du Bangladesh", "BDST", "Heure du Bangladesh", "BDT"} ; - String BRISBANE[] = new String[] {"Heure standard d'Australie orientale (Queensland)", "EST", - "Heure d'\u00E9t\u00E9 d'Australie orientale (Queensland)", "EST", - "C\u00F4te Est (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Heure standard d'Australie centrale (Australie du sud/Nouvelle-Galles du sud)", "CST", - "Heure d'\u00E9t\u00E9 d'Australie centrale (Australie du sud/Nouvelle-Galles du sud)", "CST", - "Centre (Australie-M\u00E9ridionale/Nouvelle-Galles du Sud)", "CT"}; + String BRISBANE[] = new String[] {"Heure standard d'Australie orientale (Queensland)", "AEST", + "Heure d'\u00E9t\u00E9 d'Australie orientale (Queensland)", "AEDT", + "C\u00F4te Est (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Heure standard d'Australie centrale (Australie du sud/Nouvelle-Galles du sud)", "ACST", + "Heure d'\u00E9t\u00E9 d'Australie centrale (Australie du sud/Nouvelle-Galles du sud)", "ACDT", + "Centre (Australie-M\u00E9ridionale/Nouvelle-Galles du Sud)", "ACT"}; String BRT[] = new String[] {"Heure du Br\u00e9sil", "BRT", "Heure d'\u00e9t\u00e9 du Br\u00e9sil", "BRST", "Heure du Br\u00E9sil", "BRT"} ; @@ -111,9 +111,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Heure standard de Cuba", "CST", "Heure d'\u00e9t\u00e9 de Cuba", "CDT", "Heure de Cuba", "CT"}; - String DARWIN[] = new String[] {"Heure standard d'Australie centrale (Territoire du Nord)", "CST", - "Heure d'\u00E9t\u00E9 d'Australie centrale (Territoire du Nord)", "CST", - "Centre (Territoire du Nord)", "CT"}; + String DARWIN[] = new String[] {"Heure standard d'Australie centrale (Territoire du Nord)", "ACST", + "Heure d'\u00E9t\u00E9 d'Australie centrale (Territoire du Nord)", "ACDT", + "Centre (Territoire du Nord)", "ACT"}; String DUBLIN[] = new String[] {"Heure du m\u00e9ridien de Greenwich", "GMT", "Heure d'\u00e9t\u00e9 irlandaise", "IST", "Heure irlandaise", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String EST[] = new String[] {"Heure normale de l'Est", "EST", "Heure avanc\u00e9e de l'Est", "EDT", "C\u00F4te Est", "ET"} ; - String EST_NSW[] = new String[] {"Heure normale de l'Est (Nouvelle-Galles du Sud)", "EST", - "Heure d'\u00E9t\u00E9 de l'Est (Nouvelle-Galles du Sud)", "EST", - "C\u00F4te Est (Nouvelle-Galles du Sud)", "ET"} ; + String EST_NSW[] = new String[] {"Heure normale de l'Est (Nouvelle-Galles du Sud)", "AEST", + "Heure d'\u00E9t\u00E9 de l'Est (Nouvelle-Galles du Sud)", "AEDT", + "C\u00F4te Est (Nouvelle-Galles du Sud)", "AET"} ; String FET[] = new String[] {"Heure d'Europe de l'Est UTC+3", "FET", "Heure d'\u00E9t\u00E9 d'Europe de l'Est UTC+3", "FEST", "Heure d'Europe de l'Est UTC+3", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String ICT[] = new String[] {"Heure d'Indochine", "ICT", "Heure d'\u00e9t\u00e9 d'Indochine", "ICST", "Heure d'Indochine", "ICT"} ; + String IRKT[] = new String[] {"Heure d'Irkutsk", "IRKT", + "Heure d'\u00e9t\u00e9 d'Irkutsk", "IRKST", + "Heure d'Irkutsk", "IRKT"}; String IRT[] = new String[] {"Heure normale d'Iran", "IRST", "Heure avanc\u00e9e d'Iran", "IRDT", "Heure d'Iran", "IRT"} ; @@ -177,11 +180,14 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String JST[] = new String[] {"Heure normale du Japon", "JST", "Heure avanc\u00e9e du Japon", "JDT", "Japon", "JT"} ; + String KRAT[] = new String[] {"Heure de Krasno\u00efarsk", "KRAT", + "Heure d'\u00e9t\u00e9 de Krasno\u00efarsk", "KRAST", + "Heure de Krasno\u00EFarsk", "KRAT"}; String KST[] = new String[] {"Heure normale de Cor\u00e9e", "KST", "Heure avanc\u00e9e de Cor\u00e9e", "KDT", "Cor\u00E9e", "KT"} ; String LORD_HOWE[] = new String[] {"Heure standard de Lord Howe", "LHST", - "Heure d'\u00e9t\u00e9 de Lord Howe", "LHST", + "Heure d'\u00e9t\u00e9 de Lord Howe", "LHDT", "Heure de Lord Howe", "LHT"}; String MHT[] = new String[] {"Heure des Iles Marshall", "MHT", "Heure d'\u00e9t\u00e9 des Iles Marshall", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String SGT[] = new String[] {"Heure de Singapour", "SGT", "Heure d'\u00e9t\u00e9 de Singapour", "SGST", "Heure de Singapour", "SGT"}; - String SLST[] = new String[] {"Heure du m\u00e9ridien de Greenwich", "GMT", - "Heure d'\u00e9t\u00e9 de Sierra Leone", "SLST", - "Heure de Sierra Leone", "SLT"}; - String TASMANIA[] = new String[] {"Heure standard d'Australie orientale (Tasmanie)", "EST", - "Heure d'\u00E9t\u00E9 d'Australie orientale (Tasmanie)", "EST", - "C\u00F4te Est (Tasmanie)", "ET"}; + String TASMANIA[] = new String[] {"Heure standard d'Australie orientale (Tasmanie)", "AEST", + "Heure d'\u00E9t\u00E9 d'Australie orientale (Tasmanie)", "AEDT", + "C\u00F4te Est (Tasmanie)", "AET"}; String TMT[] = new String[] {"Heure du Turkm\u00e9nistan", "TMT", "Heure d'\u00e9t\u00e9 du Turkm\u00e9nistan", "TMST", "Heure du Turkm\u00E9nistan", "TMT"} ; String ULAT[]= new String[] {"Heure de l'Ulaanbaatar", "ULAT", "Heure d'\u00e9t\u00e9 de l'Ulaanbaatar", "ULAST", "Heure de l'Ulaanbaatar", "ULAT"} ; - String WART[] = new String[] {"Heure D'Argentine de l'Ouest", "WART", - "Heure d'\u00e9t\u00e9 D'Argentine de l'Ouest", "WARST"} ; String WAT[] = new String[] {"Heure d'Afrique de l'Ouest", "WAT", "Heure d'\u00e9t\u00e9 d'Afrique de l'Ouest", "WAST", "Heure d'Afrique de l'Ouest", "WAT"} ; @@ -254,27 +255,30 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { String WIT[] = new String[] {"Heure de l'Indon\u00e9sie occidentale", "WIB", "Heure d'\u00e9t\u00e9 de l'Indon\u00e9sie occidentale", "WIST", "Heure de l'Indon\u00E9sie occidentale", "WIB"}; - String WST_AUS[] = new String[] {"Heure normale de l'Ouest (Australie)", "WST", - "Heure d'\u00E9t\u00E9 de l'Ouest (Australie)", "WST", - "Ouest (Australie)", "WT"} ; + String WST_AUS[] = new String[] {"Heure normale de l'Ouest (Australie)", "AWST", + "Heure d'\u00E9t\u00E9 de l'Ouest (Australie)", "AWDT", + "Ouest (Australie)", "AWT"} ; String SAMOA[] = new String[] {"Heure standard de Samoa", "SST", "Heure avanc\u00e9e de Samoa", "SDT", "Samoa", "ST"}; - String WST_SAMOA[] = new String[] {"Heure des Samoas occidentales", "WST", + String WST_SAMOA[] = new String[] {"Heure des Samoas occidentales", "WSST", "Heure d'\u00e9t\u00e9 des Samoas occidentales", "WSDT", "Heure des Samoas occidentales", "WST"} ; String ChST[] = new String[] {"Heure normale des \u00eeles Mariannes", "ChST", "Heure d'\u00e9t\u00e9 des \u00eeles Mariannes", "ChDT", "Chamorro", "ChT"}; - String VICTORIA[] = new String[] {"Heure standard d'Australie orientale (Victoria)", "EST", - "Heure d'\u00E9t\u00E9 d'Australie orientale (Victoria)", "EST", - "C\u00F4te Est (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"Heure standard d'Australie orientale (Victoria)", "AEST", + "Heure d'\u00E9t\u00E9 d'Australie orientale (Victoria)", "AEDT", + "C\u00F4te Est (Victoria)", "AET"}; String UTC[] = new String[] {"Temps universel coordonn\u00e9", "UTC", "Temps universel coordonn\u00e9", "UTC", "Temps universel coordonn\u00E9", "UTC"}; String UZT[] = new String[] {"Heure de l'Ouzb\u00e9kistan", "UZT", "Heure d'\u00e9t\u00e9 de l'Ouzb\u00e9kistan", "UZST", "Heure de l'Ouzb\u00E9kistan", "UZT"}; + String XJT[] = new String[] {"Heure normale de Chine", "XJT", + "Heure avanc\u00e9e de Chine", "XJDT", + "Chine", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure d'\u00e9t\u00e9 du Groenland de l'Ouest", "WGST", "Heure du Groenland de l'Ouest", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Heure normale de Metlakatla", "MeST", - "Heure avanc\u00E9e de Metlakatla", "MeDT", - "Heure de Metlakatla", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Heure normale de Saint-Pierre et Miquelon", "PMST", "Heure avanc\u00e9e de Saint-Pierre et Miquelon", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure d'\u00e9t\u00e9 du Brunei", "BNST", "Heure du Brunei", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Heure de Choibalsan", "CHOT", "Heure d'\u00e9t\u00e9 de Choibalsan", "CHOST", "Heure de Choibalsan", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Heure de Hovd", "HOVT", "Heure d'\u00e9t\u00e9 de Hovd", "HOVST", "Heure de Hovd", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Heure d'Irkutsk", "IRKT", - "Heure d'\u00e9t\u00e9 d'Irkutsk", "IRKST", - "Heure d'Irkutsk", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"Heure d'Indon\u00e9sie orientale", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure d'\u00e9t\u00e9 de Petropavlovsk-Kamchatski", "PETST", "Heure de Petropavlovsk-Kamchatski", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Heure de Khandyga", "YAKT", "Heure d'\u00E9t\u00E9 de Khandyga", "YAKST", "Heure de Khandyga", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Heure de Krasno\u00efarsk", "KRAT", - "Heure d'\u00e9t\u00e9 de Krasno\u00efarsk", "KRAST", - "Heure de Krasno\u00EFarsk", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure des Philippines", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Heure d'Oral", "ORAT", "Heure d'\u00e9t\u00e9 d'Oral", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Heure d'Ust-Nera", "VLAT", "Heure d'\u00E9t\u00E9 d'Ust-Nera", "VLAST", "Heure d'Ust-Nera", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Heure standard de l'Australie occidentale (centre)", "CWST", - "Heure d'\u00E9t\u00E9 de l'Australie occidentale (centre)", "CWST", - "Heure de l'Australie occidentale (centre)", "CWT"}}, + {"Australia/Eucla", new String[] {"Heure standard de l'Australie occidentale (centre)", "ACWST", + "Heure d'\u00E9t\u00E9 de l'Australie occidentale (centre)", "ACWDT", + "Heure de l'Australie occidentale (centre)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Heure de Volgograd", "VOLT", - "Heure d'\u00e9t\u00e9 de Volgograd", "VOLST", - "Heure de Volgograd", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/it/TimeZoneNames_it.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/it/TimeZoneNames_it.java index 309a7715c7d..43035b66ea4 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/it/TimeZoneNames_it.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/it/TimeZoneNames_it.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String ACT[] = new String[] {"Ora di Acre", "ACT", "Ora estiva di Acre", "ACST", "Ora di Acre", "ACT"}; - String ADELAIDE[] = new String[] {"Ora standard centrale (Australia del Sud)", "CST", - "Ora estiva centrale (Australia del Sud)", "CST", - "Ora fuso centrale (Australia del Sud)", "CT"}; + String ADELAIDE[] = new String[] {"Ora standard centrale (Australia del Sud)", "ACST", + "Ora estiva centrale (Australia del Sud)", "ACDT", + "Ora fuso centrale (Australia del Sud)", "ACT"}; String AGT[] = new String[] {"Ora dell'Argentina", "ART", "Ora estiva dell'Argentina", "ARST", "Ora dell'Argentina", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String BDT[] = new String[] {"Ora del Bangladesh", "BDT", "Ora estiva del Bangladesh", "BDST", "Ora del Bangladesh", "BDT"}; - String BRISBANE[] = new String[] {"Ora standard orientale (Queensland)", "EST", - "Ora estiva orientale (Queensland)", "EST", - "Ora fuso orientale (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Ora standard centrale (Australia del Sud/Nuovo Galles del Sud)", "CST", - "Ora estiva centrale (Australia del Sud/Nuovo Galles del Sud)", "CST", - "Ora fuso centrale (Australia del Sud/Nuovo Galles del Sud)", "CT"}; + String BRISBANE[] = new String[] {"Ora standard orientale (Queensland)", "AEST", + "Ora estiva orientale (Queensland)", "AEDT", + "Ora fuso orientale (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Ora standard centrale (Australia del Sud/Nuovo Galles del Sud)", "ACST", + "Ora estiva centrale (Australia del Sud/Nuovo Galles del Sud)", "ACDT", + "Ora fuso centrale (Australia del Sud/Nuovo Galles del Sud)", "ACT"}; String BRT[] = new String[] {"Ora del Brasile", "BRT", "Ora estiva del Brasile", "BRST", "Ora di Brasilia", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Ora solare Cuba", "CST", "Ora legale Cuba", "CDT", "Ora di Cuba", "CT"}; - String DARWIN[] = new String[] {"Ora standard centrale (Territori del Nord)", "CST", - "Ora estiva centrale (Territori del Nord)", "CST", - "Ora fuso centrale (Territori del Nord)", "CT"}; + String DARWIN[] = new String[] {"Ora standard centrale (Territori del Nord)", "ACST", + "Ora estiva centrale (Territori del Nord)", "ACDT", + "Ora fuso centrale (Territori del Nord)", "ACT"}; String DUBLIN[] = new String[] {"Ora media di Greenwich", "GMT", "Ora estiva irlandese", "IST", "Ora irlandese", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String EST[] = new String[] {"Ora solare USA orientale", "EST", "Ora legale USA orientale", "EDT", "Fuso orientale", "ET"}; - String EST_NSW[] = new String[] {"Ora standard dell'Australia orientale (Nuovo Galles del Sud)", "EST", - "Ora estiva dell'Australia orientale (Nuovo Galles del Sud)", "EST", - "Ora fuso orientale (Nuovo Galles del Sud)", "ET"}; + String EST_NSW[] = new String[] {"Ora standard dell'Australia orientale (Nuovo Galles del Sud)", "AEST", + "Ora estiva dell'Australia orientale (Nuovo Galles del Sud)", "AEDT", + "Ora fuso orientale (Nuovo Galles del Sud)", "AET"}; String FET[] = new String[] {"Ora dei paesi europei pi\u00F9 orientali", "FET", "Ora estiva dei paesi europei pi\u00F9 orientali", "FEST", "Ora dei paesi europei pi\u00F9 orientali", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String ICT[] = new String[] {"Ora dell'Indocina", "ICT", "Ora estiva dell'Indocina", "ICST", "Ora dell'Indocina", "ICT"}; + String IRKT[] = new String[] {"Ora di Irkutsk", "IRKT", + "Ora estiva di Irkutsk", "IRKST", + "Ora di Irkutsk", "IRKT"}; String IRT[] = new String[] {"Ora solare Iran", "IRST", "Ora legale Iran", "IRDT", "Ora Iran", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String JST[] = new String[] {"Ora solare del Giappone", "JST", "Ora legale del Giappone", "JDT", "Ora Giappone", "JT"}; + String KRAT[] = new String[] {"Ora di Krasnojarsk", "KRAT", + "Ora estiva di Krasnojarsk", "KRAST", + "Ora di Krasnojarsk", "KRAT"}; String KST[] = new String[] {"Ora solare della Corea", "KST", "Ora legale della Corea", "KDT", "Ora Corea", "KT"}; String LORD_HOWE[] = new String[] {"Ora standard di Lord Howe", "LHST", - "Ora estiva di Lord Howe", "LHST", + "Ora estiva di Lord Howe", "LHDT", "Ora di Lord Howe", "LHT"}; String MHT[] = new String[] {"Ora delle Isole Marshall", "MHT", "Ora estiva delle Isole Marshall", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String SGT[] = new String[] {"Ora di Singapore", "SGT", "Ora estiva di Singapore", "SGST", "Ora di Singapore", "SGT"}; - String SLST[] = new String[] {"Ora media di Greenwich", "GMT", - "Ora legale della Sierra Leone", "SLST", - "Ora della Sierra Leone", "SLT"}; - String TASMANIA[] = new String[] {"Ora standard orientale (Tasmania)", "EST", - "Ora estiva orientale (Tasmania)", "EST", - "Ora fuso orientale (Tasmania)", "ET"}; + String TASMANIA[] = new String[] {"Ora standard orientale (Tasmania)", "AEST", + "Ora estiva orientale (Tasmania)", "AEDT", + "Ora fuso orientale (Tasmania)", "AET"}; String TMT[] = new String[] {"Ora del Turkmenistan", "TMT", "Ora estiva del Turkmenistan", "TMST", "Ora del Turkmenistan", "TMT"}; String ULAT[]= new String[] {"Ora di Ulaanbaatar", "ULAT", "Ora estiva di Ulaanbaatar", "ULAST", "Ora di Ulaanbaatar", "ULAT"}; - String WART[] = new String[] {"Ora dell'Argentina occidentale", "WART", - "Ora estiva dell'Argentina occidentale", "WARST"}; String WAT[] = new String[] {"Ora dell'Africa occidentale", "WAT", "Ora estiva dell'Africa occidentale", "WAST", "Ora dell'Africa occidentale", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { String WIT[] = new String[] {"Ora dell'Indonesia occidentale", "WIB", "Ora estiva dell'Indonesia occidentale", "WIST", "Ora dell'Indonesia occidentale", "WIB"}; - String WST_AUS[] = new String[] {"Ora standard dell'Australia occidentale", "WST", - "Ora estiva dell'Australia occidentale", "WST", - "Ora Australia occidentale", "WT"}; + String WST_AUS[] = new String[] {"Ora standard dell'Australia occidentale", "AWST", + "Ora estiva dell'Australia occidentale", "AWDT", + "Ora Australia occidentale", "AWT"}; String SAMOA[] = new String[] {"Ora standard di Samoa", "SST", "Ora legale di Samoa", "SDT", "Ora Samoa", "ST"}; - String WST_SAMOA[] = new String[] {"Ora di Samoa", "WST", + String WST_SAMOA[] = new String[] {"Ora di Samoa", "WSST", "Ora estiva di Samoa", "WSDT", "Ora di Samoa occidentale", "WST"}; String ChST[] = new String[] {"Ora standard di Chamorro", "ChST", "Ora legale di Chamorro", "ChDT", "Ora Chamorro", "ChT"}; - String VICTORIA[] = new String[] {"Ora standard orientale (Victoria)", "EST", - "Ora estiva orientale (Victoria)", "EST", - "Ora fuso orientale (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"Ora standard orientale (Victoria)", "AEST", + "Ora estiva orientale (Victoria)", "AEDT", + "Ora fuso orientale (Victoria)", "AET"}; String UTC[] = new String[] {"Tempo universale coordinato", "UTC", "Tempo universale coordinato", "UTC", "Tempo universale coordinato", "UTC"}; String UZT[] = new String[] {"Ora dell'Uzbekistan", "UZT", "Ora estiva dell'Uzbekistan", "UZST", "Ora dell'Uzbekistan", "UZT"}; + String XJT[] = new String[] {"Ora solare della Cina", "XJT", + "Ora legale della Cina", "XJDT", + "Ora Cina", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora estiva della Groenlandia occidentale", "WGST", "Ora della Groenlandia occidentale", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Ora standard di Metlakatla", "MeST", - "Ora legale di Metlakatla", "MeDT", - "Ora di Metlakatla", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Ora solare di Saint-Pierre e Miquelon", "PMST", "Ora legale di Saint-Pierre e Miquelon", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora estiva del Brunei", "BNST", "Ora del Brunei", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Ora di Choibalsan", "CHOT", "Ora estiva di Choibalsan", "CHOST", "Ora di Choibalsan", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Ora di Hovd", "HOVT", "Ora estiva di Hovd", "HOVST", "Ora di Hovd", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Ora di Irkutsk", "IRKT", - "Ora estiva di Irkutsk", "IRKST", - "Ora di Irkutsk", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"Ora dell'Indonesia orientale", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora estiva di Petropavlovsk-Kamchatski", "PETST", "Ora di Petropavlovsk-Kamchatski", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Kolkata", IST}, {"Asia/Khandyga", new String[] {"Ora di Khandyga", "YAKT", "Ora estiva di Khandyga", "YAKST", "Ora di Khandyga", "YAKT"}}, - {"Asia/Krasnoyarsk", new String[] {"Ora di Krasnojarsk", "KRAT", - "Ora estiva di Krasnojarsk", "KRAST", - "Ora di Krasnojarsk", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora delle Filippine", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Ora di Oral", "ORAT", "Ora estiva di Oral", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Ora di Ust-Nera", "VLAT", "Ora estiva di Ust-Nera", "VLAST", "Ora di Ust-Nera", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Ora standard Australia centro-occidentale", "CWST", - "Ora estiva Australia centro-occidentale", "CWST", - "Ora Australia centro-occidentale", "CWT"}}, + {"Australia/Eucla", new String[] {"Ora standard Australia centro-occidentale", "ACWST", + "Ora estiva Australia centro-occidentale", "ACWDT", + "Ora Australia centro-occidentale", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Ora di Volgograd", "VOLT", - "Ora estiva di Volgograd", "VOLST", - "Ora di Volgograd", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java index 23bbcd6c8e0..68bd6c30871 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String ACT[] = new String[] {"\u30a2\u30af\u30ec\u6642\u9593", "ACT", "\u30a2\u30af\u30ec\u590f\u6642\u9593", "ACST", "\u30a2\u30af\u30ec\u6642\u9593", "ACT"}; - String ADELAIDE[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CST", - "\u4E2D\u90E8\u590F\u6642\u9593(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CST", - "\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CT"}; + String ADELAIDE[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACST", + "\u4E2D\u90E8\u590F\u6642\u9593(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACDT", + "\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACT"}; String AGT[] = new String[] {"\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u6642\u9593", "ART", "\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u590f\u6642\u9593", "ARST", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6642\u9593", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String BDT[] = new String[] {"\u30d0\u30f3\u30b0\u30e9\u30c7\u30b7\u30e5\u6642\u9593", "BDT", "\u30d0\u30f3\u30b0\u30e9\u30c7\u30b7\u30e5\u590f\u6642\u9593", "BDST", "\u30D0\u30F3\u30B0\u30E9\u30C7\u30B7\u30E5\u6642\u9593", "BDT"}; - String BRISBANE[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "EST", - "\u6771\u90E8\u590F\u6642\u9593(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "EST", - "\u6771\u90E8\u6A19\u6E96\u6642(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "ET"}; - String BROKEN_HILL[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "CST", - "\u4E2D\u90E8\u590F\u6642\u9593(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "CST", - "\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "CT"}; + String BRISBANE[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "AEST", + "\u6771\u90E8\u590F\u6642\u9593(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "AEDT", + "\u6771\u90E8\u6A19\u6E96\u6642(\u30AF\u30A4\u30FC\u30F3\u30BA\u30E9\u30F3\u30C9)", "AET"}; + String BROKEN_HILL[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "ACST", + "\u4E2D\u90E8\u590F\u6642\u9593(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "ACDT", + "\u4E2D\u90E8\u6A19\u6E96\u6642(\u5357\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2/\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "ACT"}; String BRT[] = new String[] {"\u30d6\u30e9\u30b8\u30eb\u6642\u9593", "BRT", "\u30d6\u30e9\u30b8\u30eb\u590f\u6642\u9593", "BRST", "\u30D6\u30E9\u30B8\u30EA\u30A2\u6642\u9593", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String CUBA[] = new String[] {"\u30ad\u30e5\u30fc\u30d0\u6a19\u6e96\u6642", "CST", "\u30ad\u30e5\u30fc\u30d0\u590f\u6642\u9593", "CDT", "\u30AD\u30E5\u30FC\u30D0\u6642\u9593", "CT"}; - String DARWIN[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "CST", - "\u4E2D\u90E8\u590F\u6642\u9593(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "CST", - "\u4E2D\u90E8\u6A19\u6E96\u6642(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "CT"}; + String DARWIN[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "ACST", + "\u4E2D\u90E8\u590F\u6642\u9593(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "ACDT", + "\u4E2D\u90E8\u6A19\u6E96\u6642(\u30CE\u30FC\u30B6\u30F3\u30C6\u30EA\u30C8\u30EA\u30FC)", "ACT"}; String DUBLIN[] = new String[] {"\u30b0\u30ea\u30cb\u30c3\u30b8\u6a19\u6e96\u6642", "GMT", "\u30a2\u30a4\u30eb\u30e9\u30f3\u30c9\u590f\u6642\u9593", "IST", "\u30A2\u30A4\u30EB\u30E9\u30F3\u30C9\u6642\u9593", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String EST[] = new String[] {"\u6771\u90e8\u6a19\u6e96\u6642", "EST", "\u6771\u90e8\u590f\u6642\u9593", "EDT", "\u6771\u90E8\u6A19\u6E96\u6642", "ET"}; - String EST_NSW[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "EST", - "\u6771\u90E8\u590F\u6642\u9593(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "EST", - "\u6771\u90E8\u6A19\u6E96\u6642(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "ET"}; + String EST_NSW[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "AEST", + "\u6771\u90E8\u590F\u6642\u9593(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "AEDT", + "\u6771\u90E8\u6A19\u6E96\u6642(\u30CB\u30E5\u30FC\u30B5\u30A6\u30B9\u30A6\u30A7\u30FC\u30EB\u30BA)", "AET"}; String FET[] = new String[] {"\u6975\u6771\u30E8\u30FC\u30ED\u30C3\u30D1\u6642\u9593", "FET", "\u6975\u6771\u30E8\u30FC\u30ED\u30C3\u30D1\u590F\u6642\u9593", "FEST", "\u6975\u6771\u30E8\u30FC\u30ED\u30C3\u30D1\u6642\u9593", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String ICT[] = new String[] {"\u30a4\u30f3\u30c9\u30b7\u30ca\u6642\u9593", "ICT", "\u30a4\u30f3\u30c9\u30b7\u30ca\u590f\u6642\u9593", "ICST", "\u30A4\u30F3\u30C9\u30B7\u30CA\u6642\u9593", "ICT"}; + String IRKT[] = new String[] {"\u30a4\u30eb\u30af\u30fc\u30c4\u30af\u6642\u9593", "IRKT", + "\u30a4\u30eb\u30af\u30fc\u30c4\u30af\u590f\u6642\u9593", "IRKST", + "\u30A4\u30EB\u30AF\u30FC\u30C4\u30AF\u6642\u9593", "IRKT"}; String IRT[] = new String[] {"\u30a4\u30e9\u30f3\u6a19\u6e96\u6642", "IRST", "\u30a4\u30e9\u30f3\u590f\u6642\u9593", "IRDT", "\u30A4\u30E9\u30F3\u6642\u9593", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String JST[] = new String[] {"\u65e5\u672c\u6a19\u6e96\u6642", "JST", "\u65e5\u672c\u590f\u6642\u9593", "JDT", "\u65E5\u672C\u6642\u9593", "JT"}; + String KRAT[] = new String[] {"\u30af\u30e9\u30b9\u30ce\u30e4\u30eb\u30b9\u30af\u6642\u9593", "KRAT", + "\u30af\u30e9\u30b9\u30ce\u30e4\u30eb\u30b9\u30af\u590f\u6642\u9593", "KRAST", + "\u30AF\u30E9\u30B9\u30CE\u30E4\u30EB\u30B9\u30AF\u6642\u9593", "KRAT"}; String KST[] = new String[] {"\u97d3\u56fd\u6a19\u6e96\u6642", "KST", "\u97d3\u56fd\u590f\u6642\u9593", "KDT", "\u97D3\u56FD\u6642\u9593", "KT"}; String LORD_HOWE[] = new String[] {"\u30ed\u30fc\u30c9\u30cf\u30a6\u5cf6\u6a19\u6e96\u6642", "LHST", - "\u30ed\u30fc\u30c9\u30cf\u30a6\u5cf6\u590f\u6642\u9593", "LHST", + "\u30ed\u30fc\u30c9\u30cf\u30a6\u5cf6\u590f\u6642\u9593", "LHDT", "\u30ED\u30FC\u30C9\u30CF\u30A6\u6642\u9593", "LHT"}; String MHT[] = new String[] {"\u30de\u30fc\u30b7\u30e3\u30eb\u5cf6\u6642\u9593", "MHT", "\u30de\u30fc\u30b7\u30e3\u30eb\u5cf6\u590f\u6642\u9593", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String SGT[] = new String[] {"\u30b7\u30f3\u30ac\u30dd\u30fc\u30eb\u6642\u9593", "SGT", "\u30b7\u30f3\u30ac\u30dd\u30fc\u30eb\u590f\u6642\u9593", "SGST", "\u30B7\u30F3\u30AC\u30DD\u30FC\u30EB\u6642\u9593", "SGT"}; - String SLST[] = new String[] {"\u30b0\u30ea\u30cb\u30c3\u30b8\u6a19\u6e96\u6642", "GMT", - "\u30b7\u30a8\u30e9\u30ec\u30aa\u30cd\u590f\u6642\u9593", "SLST", - "\u30B7\u30A8\u30E9\u30EC\u30AA\u30CD\u6642\u9593", "SLT"}; - String TASMANIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30BF\u30B9\u30DE\u30CB\u30A2)", "EST", - "\u6771\u90E8\u590F\u6642\u9593(\u30BF\u30B9\u30DE\u30CB\u30A2)", "EST", - "\u6771\u90E8\u6A19\u6E96\u6642(\u30BF\u30B9\u30DE\u30CB\u30A2)", "ET"}; + String TASMANIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30BF\u30B9\u30DE\u30CB\u30A2)", "AEST", + "\u6771\u90E8\u590F\u6642\u9593(\u30BF\u30B9\u30DE\u30CB\u30A2)", "AEDT", + "\u6771\u90E8\u6A19\u6E96\u6642(\u30BF\u30B9\u30DE\u30CB\u30A2)", "AET"}; String TMT[] = new String[] {"\u30c8\u30eb\u30af\u30e1\u30cb\u30b9\u30bf\u30f3\u6642\u9593", "TMT", "\u30c8\u30eb\u30af\u30e1\u30cb\u30b9\u30bf\u30f3\u590f\u6642\u9593", "TMST", "\u30C8\u30EB\u30AF\u30E1\u30CB\u30B9\u30BF\u30F3\u6642\u9593", "TMT"}; String ULAT[]= new String[] {"\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u6642\u9593", "ULAT", "\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u590f\u6642\u9593", "ULAST", "\u30A6\u30E9\u30F3\u30D0\u30FC\u30C8\u30EB\u6642\u9593", "ULAT"}; - String WART[] = new String[] {"\u897f\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u6642\u9593", "WART", - "\u897f\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u590f\u6642\u9593", "WARST"}; String WAT[] = new String[] {"\u897f\u30a2\u30d5\u30ea\u30ab\u6642\u9593", "WAT", "\u897f\u30a2\u30d5\u30ea\u30ab\u590f\u6642\u9593", "WAST", "\u897F\u90E8\u30A2\u30D5\u30EA\u30AB\u6642\u9593", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { String WIT[] = new String[] {"\u897f\u30a4\u30f3\u30c9\u30cd\u30b7\u30a2\u6642\u9593", "WIB", "\u897f\u30a4\u30f3\u30c9\u30cd\u30b7\u30a2\u590f\u6642\u9593", "WIST", "\u897F\u90E8\u30A4\u30F3\u30C9\u30CD\u30B7\u30A2\u6642\u9593", "WIB"}; - String WST_AUS[] = new String[] {"\u897F\u90E8\u6A19\u6E96\u6642(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "WST", - "\u897F\u90E8\u590F\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "WST", - "\u897F\u90E8\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "WT"}; + String WST_AUS[] = new String[] {"\u897F\u90E8\u6A19\u6E96\u6642(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "AWST", + "\u897F\u90E8\u590F\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "AWDT", + "\u897F\u90E8\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "AWT"}; String SAMOA[] = new String[] {"\u30b5\u30e2\u30a2\u6a19\u6e96\u6642", "SST", "\u30b5\u30e2\u30a2\u590f\u6642\u9593", "SDT", "\u30B5\u30E2\u30A2\u6642\u9593", "ST"}; - String WST_SAMOA[] = new String[] {"\u897f\u30b5\u30e2\u30a2\u6642\u9593", "WST", + String WST_SAMOA[] = new String[] {"\u897f\u30b5\u30e2\u30a2\u6642\u9593", "WSST", "\u897f\u30b5\u30e2\u30a2\u590f\u6642\u9593", "WSDT", "\u897F\u30B5\u30E2\u30A2\u6642\u9593", "WST"}; String ChST[] = new String[] {"\u30b0\u30a2\u30e0\u6a19\u6e96\u6642", "ChST", "\u30b0\u30a2\u30e0\u590f\u6642\u9593", "ChDT", "\u30C1\u30E3\u30E2\u30ED\u6642\u9593", "ChT"}; - String VICTORIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30D3\u30AF\u30C8\u30EA\u30A2)", "EST", - "\u6771\u90E8\u590F\u6642\u9593(\u30D3\u30AF\u30C8\u30EA\u30A2)", "EST", - "\u6771\u90E8\u6A19\u6E96\u6642(\u30D3\u30AF\u30C8\u30EA\u30A2)", "ET"}; + String VICTORIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642(\u30D3\u30AF\u30C8\u30EA\u30A2)", "AEST", + "\u6771\u90E8\u590F\u6642\u9593(\u30D3\u30AF\u30C8\u30EA\u30A2)", "AEDT", + "\u6771\u90E8\u6A19\u6E96\u6642(\u30D3\u30AF\u30C8\u30EA\u30A2)", "AET"}; String UTC[] = new String[] {"\u5354\u5b9a\u4e16\u754c\u6642", "UTC", "\u5354\u5b9a\u4e16\u754c\u6642", "UTC", "\u5354\u5B9A\u4E16\u754C\u6642", "UTC"}; String UZT[] = new String[] {"\u30a6\u30ba\u30d9\u30ad\u30b9\u30bf\u30f3\u6642\u9593", "UZT", "\u30a6\u30ba\u30d9\u30ad\u30b9\u30bf\u30f3\u590f\u6642\u9593", "UZST", "\u30A6\u30BA\u30D9\u30AD\u30B9\u30BF\u30F3\u6642\u9593", "UZT"}; + String XJT[] = new String[] {"\u4e2d\u56fd\u6a19\u6e96\u6642", "XJT", + "\u4e2d\u56fd\u590f\u6642\u9593", "XJDT", + "\u4E2D\u56FD\u6642\u9593", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u897f\u30b0\u30ea\u30fc\u30f3\u30e9\u30f3\u30c9\u590f\u6642\u9593", "WGST", "\u897F\u90E8\u30B0\u30EA\u30FC\u30F3\u30E9\u30F3\u30C9\u6642\u9593", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"\u30E1\u30C8\u30E9\u30AB\u30C8\u30E9\u6A19\u6E96\u6642\u9593", "MeST", - "\u30E1\u30C8\u30E9\u30AB\u30C8\u30E9\u590F\u6642\u9593", "MeDT", - "\u30E1\u30C8\u30E9\u30AB\u30C8\u30E9\u6642\u9593", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"\u30b5\u30f3\u30d4\u30a8\u30fc\u30eb\u30fb\u30df\u30af\u30ed\u30f3\u8af8\u5cf6\u6a19\u6e96\u6642", "PMST", "\u30b5\u30f3\u30d4\u30a8\u30fc\u30eb\u30fb\u30df\u30af\u30ed\u30f3\u8af8\u5cf6\u590f\u6642\u9593", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u30d6\u30eb\u30cd\u30a4\u590f\u6642\u9593", "BNST", "\u30D6\u30EB\u30CD\u30A4\u6642\u9593", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"\u30c1\u30e7\u30a4\u30d0\u30eb\u30b5\u30f3\u6642\u9593", "CHOT", "\u30c1\u30e7\u30a4\u30d0\u30eb\u30b5\u30f3\u590f\u6642\u9593", "CHOST", "\u30C1\u30E7\u30A4\u30D0\u30EB\u30B5\u30F3\u6642\u9593", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"\u30db\u30d6\u30c9\u6642\u9593", "HOVT", "\u30db\u30d6\u30c9\u590f\u6642\u9593", "HOVST", "\u30DB\u30D6\u30C9\u6642\u9593", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"\u30a4\u30eb\u30af\u30fc\u30c4\u30af\u6642\u9593", "IRKT", - "\u30a4\u30eb\u30af\u30fc\u30c4\u30af\u590f\u6642\u9593", "IRKST", - "\u30A4\u30EB\u30AF\u30FC\u30C4\u30AF\u6642\u9593", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"\u6771\u30a4\u30f3\u30c9\u30cd\u30b7\u30a2\u6642\u9593", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u30da\u30c8\u30ed\u30d1\u30d6\u30ed\u30d5\u30b9\u30af\u30ab\u30e0\u30c1\u30e3\u30c4\u30ad\u30fc\u590f\u6642\u9593", "PETST", "\u30DA\u30C8\u30ED\u30D1\u30D6\u30ED\u30D5\u30B9\u30AF\u30FB\u30AB\u30E0\u30C1\u30E3\u30C4\u30AD\u30FC\u6642\u9593", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"\u30CF\u30F3\u30C9\u30A5\u30A4\u30AC\u6642\u9593", "YAKT", "\u30CF\u30F3\u30C9\u30A5\u30A4\u30AC\u590F\u6642\u9593", "YAKST", "\u30CF\u30F3\u30C9\u30A5\u30A4\u30AC\u6642\u9593", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"\u30af\u30e9\u30b9\u30ce\u30e4\u30eb\u30b9\u30af\u6642\u9593", "KRAT", - "\u30af\u30e9\u30b9\u30ce\u30e4\u30eb\u30b9\u30af\u590f\u6642\u9593", "KRAST", - "\u30AF\u30E9\u30B9\u30CE\u30E4\u30EB\u30B9\u30AF\u6642\u9593", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u30D5\u30A3\u30EA\u30D4\u30F3\u6642\u9593", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"\u30aa\u30e9\u30eb\u6642\u9593", "ORAT", "\u30aa\u30e9\u30eb\u590f\u6642\u9593", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"\u30A6\u30B9\u30C1\u30CD\u30E9\u6642\u9593", "VLAT", "\u30A6\u30B9\u30C1\u30CD\u30E9\u590F\u6642\u9593", "VLAST", "\u30A6\u30B9\u30C1\u30CD\u30E9\u6642\u9593", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6A19\u6E96\u6642(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CWST", - "\u4E2D\u897F\u90E8\u590F\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CWST", - "\u4E2D\u897F\u90E8\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "CWT"}}, + {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6A19\u6E96\u6642(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACWST", + "\u4E2D\u897F\u90E8\u590F\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACWDT", + "\u4E2D\u897F\u90E8\u6642\u9593(\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"\u30dc\u30eb\u30b4\u30b0\u30e9\u30fc\u30c9\u6642\u9593", "VOLT", - "\u30dc\u30eb\u30b4\u30b0\u30e9\u30fc\u30c9\u590f\u6642\u9593", "VOLST", - "\u30DC\u30EB\u30B4\u30B0\u30E9\u30FC\u30C9\u6642\u9593", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java index d1e106e2cd8..fcfd748153e 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String ACT[] = new String[] {"\uc5d0\uc774\ucee4 \uc2dc\uac04", "ACT", "\uc5d0\uc774\ucee4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ACST", "\uc5d0\uc774\ucee4 \uc2dc\uac04", "ACT"}; - String ADELAIDE[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CST", - "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CST", - "\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CT"}; + String ADELAIDE[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACST", + "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACDT", + "\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACT"}; String AGT[] = new String[] {"\uc544\ub974\ud5e8\ud2f0\ub098 \uc2dc\uac04", "ART", "\uc544\ub974\ud5e8\ud2f0\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ARST", "\uC544\uB974\uD5E8\uD2F0\uB098 \uD45C\uC900\uC2DC", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String BDT[] = new String[] {"\ubc29\uae00\ub77c\ub370\uc2dc \uc2dc\uac04", "BDT", "\ubc29\uae00\ub77c\ub370\uc2dc \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "BDST", "\uBC29\uAE00\uB77C\uB370\uC2DC \uD45C\uC900\uC2DC", "BDT"}; - String BRISBANE[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD038\uC990\uB79C\uB4DC)", "EST", - "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uD038\uC990\uB79C\uB4DC)", "EST", - "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD038\uC990\uB79C\uB4DC)", "ET"}; - String BROKEN_HILL[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "CST", - "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "CST", - "\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "CT"}; + String BRISBANE[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD038\uC990\uB79C\uB4DC)", "AEST", + "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uD038\uC990\uB79C\uB4DC)", "AEDT", + "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD038\uC990\uB79C\uB4DC)", "AET"}; + String BROKEN_HILL[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "ACST", + "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "ACDT", + "\uC911\uBD80 \uD45C\uC900\uC2DC(\uB0A8\uBD80 \uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544/\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "ACT"}; String BRT[] = new String[] {"\ube0c\ub77c\uc9c8\ub9ac\uc544 \uc2dc\uac04", "BRT", "\ube0c\ub77c\uc9c8\ub9ac\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "BRST", "\uBE0C\uB77C\uC9C8\uB9AC\uC544 \uD45C\uC900\uC2DC", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String CUBA[] = new String[] {"\ucfe0\ubc14 \ud45c\uc900\uc2dc", "CST", "\ucfe0\ubc14 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CDT", "\uCFE0\uBC14 \uD45C\uC900\uC2DC", "CT"}; - String DARWIN[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uBD81\uBD80 \uC9C0\uC5ED)", "CST", - "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uBD81\uBD80 \uC9C0\uC5ED)", "CST", - "\uC911\uBD80 \uD45C\uC900\uC2DC(\uBD81\uBD80 \uC9C0\uC5ED)", "CT"}; + String DARWIN[] = new String[] {"\uC911\uBD80 \uD45C\uC900\uC2DC(\uBD81\uBD80 \uC9C0\uC5ED)", "ACST", + "\uC911\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uBD81\uBD80 \uC9C0\uC5ED)", "ACDT", + "\uC911\uBD80 \uD45C\uC900\uC2DC(\uBD81\uBD80 \uC9C0\uC5ED)", "ACT"}; String DUBLIN[] = new String[] {"\uadf8\ub9ac\ub2c8\uce58 \ud45c\uc900\uc2dc", "GMT", "\uc544\uc77c\ub79c\ub4dc \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "IST", "\uC544\uC77C\uB79C\uB4DC \uD45C\uC900\uC2DC", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String EST[] = new String[] {"\ub3d9\ubd80 \ud45c\uc900\uc2dc", "EST", "\ub3d9\ubd80 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "EDT", "\uB3D9\uBD80 \uD45C\uC900\uC2DC", "ET"}; - String EST_NSW[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "EST", - "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "EST", - "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "ET"}; + String EST_NSW[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "AEST", + "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "AEDT", + "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uB274\uC0AC\uC6B0\uC2A4\uC6E8\uC77C\uC988)", "AET"}; String FET[] = new String[] {"\uADF9\uB3D9 \uC720\uB7FD \uD45C\uC900\uC2DC", "FET", "\uADF9\uB3D9 \uC720\uB7FD \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04", "FEST", "\uADF9\uB3D9 \uC720\uB7FD \uD45C\uC900\uC2DC", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String ICT[] = new String[] {"\uc778\ub3c4\ucc28\uc774\ub098 \ubc18\ub3c4 \uc2dc\uac04", "ICT", "\uc778\ub3c4\ucc28\uc774\ub098 \ubc18\ub3c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ICST", "\uC778\uB3C4\uCC28\uC774\uB098 \uBC18\uB3C4 \uD45C\uC900\uC2DC", "ICT"}; + String IRKT[] = new String[] {"\uc774\ub974\ucfe0\uce20\ud06c \uc2dc\uac04", "IRKT", + "\uc774\ub974\ucfe0\uce20\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "IRKST", + "\uC774\uB974\uCFE0\uCE20\uD06C \uD45C\uC900\uC2DC", "IRKT"}; String IRT[] = new String[] {"\uc774\ub780 \ud45c\uc900\uc2dc", "IRST", "\uc774\ub780 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "IRDT", "\uC774\uB780 \uD45C\uC900\uC2DC", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String JST[] = new String[] {"\uc77c\ubcf8 \ud45c\uc900\uc2dc", "JST", "\uc77c\ubcf8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "JDT", "\uC77C\uBCF8 \uD45C\uC900\uC2DC", "JT"}; + String KRAT[] = new String[] {"\ud06c\ub77c\uc2a4\ub178\uc57c\ub974\uc2a4\ud06c \uc2dc\uac04", "KRAT", + "\ud06c\ub77c\uc2a4\ub178\uc57c\ub974\uc2a4\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "KRAST", + "\uD06C\uB77C\uC2A4\uB178\uC57C\uB974\uC2A4\uD06C \uD45C\uC900\uC2DC", "KRAT"}; String KST[] = new String[] {"\ud55c\uad6d \ud45c\uc900\uc2dc", "KST", "\ud55c\uad6d \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "KDT", "\uB300\uD55C\uBBFC\uAD6D \uD45C\uC900\uC2DC", "KT"}; String LORD_HOWE[] = new String[] {"\ub85c\ub4dc \ud558\uc6b0 \ud45c\uc900\uc2dc", "LHST", - "\ub85c\ub4dc \ud558\uc6b0 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "LHST", + "\ub85c\ub4dc \ud558\uc6b0 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "LHDT", "\uB85C\uB4DC\uD558\uC6B0 \uD45C\uC900\uC2DC", "LHT"}; String MHT[] = new String[] {"\ub9c8\uc15c\uc81c\ub3c4 \uc2dc\uac04", "MHT", "\ub9c8\uc15c\uc81c\ub3c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String SGT[] = new String[] {"\uc2f1\uac00\ud3ec\ub974 \uc2dc\uac04", "SGT", "\uc2f1\uac00\ud3ec\ub974 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "SGST", "\uC2F1\uAC00\uD3EC\uB974 \uD45C\uC900\uC2DC", "SGT"}; - String SLST[] = new String[] {"\uadf8\ub9ac\ub2c8\uce58 \ud45c\uc900\uc2dc", "GMT", - "\uc2dc\uc5d0\ub77c\ub9ac\uc628 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "SLST", - "\uC2DC\uC5D0\uB77C\uB9AC\uC628 \uD45C\uC900\uC2DC", "SLT"}; - String TASMANIA[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "EST", - "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "EST", - "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "ET"}; + String TASMANIA[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "AEST", + "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "AEDT", + "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uD0DC\uC988\uBA54\uC774\uB2C8\uC544)", "AET"}; String TMT[] = new String[] {"\ud22c\ub974\ud06c\uba54\ub2c8\uc2a4\ud0c4 \uc2dc\uac04", "TMT", "\ud22c\ub974\ud06c\uba54\ub2c8\uc2a4\ud0c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "TMST", "\uD22C\uB974\uD06C\uBA54\uB2C8\uC2A4\uD0C4 \uD45C\uC900\uC2DC", "TMT"}; String ULAT[]= new String[] {"\uc6b8\ub780\ubc14\ud0c0\ub974 \uc2dc\uac04", "ULAT", "\uc6b8\ub780\ubc14\ud0c0\ub974 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ULAST", "\uC6B8\uB780\uBC14\uD1A0\uB974 \uD45C\uC900\uC2DC", "ULAT"}; - String WART[] = new String[] {"\uc11c\ubd80 \uc544\ub974\ud5e8\ud2f0\ub098 \uc2dc\uac04", "WART", - "\uc11c\ubd80 \uc544\ub974\ud5e8\ud2f0\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WARST"}; String WAT[] = new String[] {"\uc11c\ubd80 \uc544\ud504\ub9ac\uce74 \uc2dc\uac04", "WAT", "\uc11c\ubd80 \uc544\ud504\ub9ac\uce74 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WAST", "\uC11C\uBD80 \uC544\uD504\uB9AC\uCE74 \uD45C\uC900\uC2DC", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { String WIT[] = new String[] {"\uc11c\uc778\ub3c4\ub124\uc2dc\uc544 \uc2dc\uac04", "WIB", "\uc11c\uc778\ub3c4\ub124\uc2dc\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WIST", "\uC11C\uBD80 \uC778\uB3C4\uB124\uC2DC\uC544 \uD45C\uC900\uC2DC", "WIB"}; - String WST_AUS[] = new String[] {"\uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "WST", - "\uC11C\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "WST", - "\uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "WT"}; + String WST_AUS[] = new String[] {"\uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "AWST", + "\uC11C\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "AWDT", + "\uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "AWT"}; String SAMOA[] = new String[] {"\uc0ac\ubaa8\uc544 \ud45c\uc900\uc2dc", "SST", "\uc0ac\ubaa8\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "SDT", "\uC0AC\uBAA8\uC544 \uD45C\uC900\uC2DC", "ST"}; - String WST_SAMOA[] = new String[] {"\uc11c\uc0ac\ubaa8\uc544 \uc2dc\uac04", "WST", + String WST_SAMOA[] = new String[] {"\uc11c\uc0ac\ubaa8\uc544 \uc2dc\uac04", "WSST", "\uc11c\uc0ac\ubaa8\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WSDT", "\uC11C\uC0AC\uBAA8\uC544 \uD45C\uC900\uC2DC", "WST"}; String ChST[] = new String[] {"\ucc28\ubaa8\ub85c \ud45c\uc900\uc2dc", "ChST", "\ucc28\ubaa8\ub85c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ChDT", "\uCC28\uBAA8\uB974 \uD45C\uC900\uC2DC", "ChT"}; - String VICTORIA[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uBE45\uD1A0\uB9AC\uC544)", "EST", - "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uBE45\uD1A0\uB9AC\uC544)", "EST", - "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uBE45\uD1A0\uB9AC\uC544)", "ET"}; + String VICTORIA[] = new String[] {"\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uBE45\uD1A0\uB9AC\uC544)", "AEST", + "\uB3D9\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uBE45\uD1A0\uB9AC\uC544)", "AEDT", + "\uB3D9\uBD80 \uD45C\uC900\uC2DC(\uBE45\uD1A0\uB9AC\uC544)", "AET"}; String UTC[] = new String[] {"\uc138\uacc4 \ud45c\uc900\uc2dc", "UTC", "\uc138\uacc4 \ud45c\uc900\uc2dc", "UTC", "\uC9C0\uC5ED \uD45C\uC900\uC2DC", "UTC"}; String UZT[] = new String[] {"\uc6b0\uc988\ubca0\ud0a4\uc2a4\ud0c4 \uc2dc\uac04", "UZT", "\uc6b0\uc988\ubca0\ud0a4\uc2a4\ud0c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "UZST", "\uC6B0\uC988\uBCA0\uD0A4\uC2A4\uD0C4 \uD45C\uC900\uC2DC", "UZT"}; + String XJT[] = new String[] {"\uc911\uad6d \ud45c\uc900\uc2dc", "XJT", + "\uc911\uad6d \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "XJDT", + "\uC911\uAD6D \uD45C\uC900\uC2DC", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\uc11c\ubd80 \uadf8\ub9b0\ub79c\ub4dc \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WGST", "\uC11C\uBD80 \uADF8\uB9B0\uB780\uB4DC \uD45C\uC900\uC2DC", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"\uBA54\uD2B8\uB77C\uCE74\uD2B8\uB77C \uD45C\uC900\uC2DC", "MeST", - "\uBA54\uD2B8\uB77C\uCE74\uD2B8\uB77C \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04", "MeDT", - "\uBA54\uD2B8\uB77C\uCE74\uD2B8\uB77C \uD45C\uC900\uC2DC", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"\ud53c\uc5d0\ub974 \ubbf8\ud06c\ub860 \ud45c\uc900\uc2dc", "PMST", "\ud53c\uc5d0\ub974 \ubbf8\ud06c\ub860 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\ube0c\ub8e8\ub098\uc774 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "BNST", "\uBE0C\uB8E8\uB098\uC774 \uD45C\uC900\uC2DC", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Choibalsan \uc2dc\uac04", "CHOT", "Choibalsan \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CHOST", "\uCD08\uC774\uBC1C\uC0B0 \uD45C\uC900\uC2DC", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Hovd \uc2dc\uac04", "HOVT", "Hovd \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "HOVST", "\uD638\uBE0C\uB4DC \uD45C\uC900\uC2DC", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"\uc774\ub974\ucfe0\uce20\ud06c \uc2dc\uac04", "IRKT", - "\uc774\ub974\ucfe0\uce20\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "IRKST", - "\uC774\uB974\uCFE0\uCE20\uD06C \uD45C\uC900\uC2DC", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"\ub3d9\ubd80 \uc778\ub3c4\ub124\uc2dc\uc544 \uc2dc\uac04", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\ud398\ud2b8\ub85c\ud30c\ube14\ub85c\ud504\uc2a4\ud06c-\uce84\ucc28\uce20\ud0a4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PETST", "\uD398\uD2B8\uB85C\uD30C\uBE0C\uB85C\uD504\uC2A4\uD06C-\uCE84\uCC28\uCE20\uD0A4 \uD45C\uC900\uC2DC", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"\uD55C\uB514\uAC00 \uD45C\uC900\uC2DC", "YAKT", "\uD55C\uB514\uAC00 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04", "YAKST", "\uD55C\uB514\uAC00 \uD45C\uC900\uC2DC", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"\ud06c\ub77c\uc2a4\ub178\uc57c\ub974\uc2a4\ud06c \uc2dc\uac04", "KRAT", - "\ud06c\ub77c\uc2a4\ub178\uc57c\ub974\uc2a4\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "KRAST", - "\uD06C\uB77C\uC2A4\uB178\uC57C\uB974\uC2A4\uD06C \uD45C\uC900\uC2DC", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\uD544\uB9AC\uD540 \uD45C\uC900\uC2DC", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Oral \ud45c\uc900\uc2dc", "ORAT", "Oral \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"\uC6B0\uC2A4\uD2F0\uB124\uB77C \uD45C\uC900\uC2DC", "VLAT", "\uC6B0\uC2A4\uD2F0\uB124\uB77C \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04", "VLAST" , "\uC6B0\uC2A4\uD2F0\uB124\uB77C \uD45C\uC900\uC2DC", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"\uC911\uC559 \uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CWST", - "\uC911\uC559 \uC11C\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CWST", - "\uC911\uC559 \uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "CWT"}}, + {"Australia/Eucla", new String[] {"\uC911\uC559 \uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACWST", + "\uC911\uC559 \uC11C\uBD80 \uC77C\uAD11 \uC808\uC57D \uC2DC\uAC04(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACWDT", + "\uC911\uC559 \uC11C\uBD80 \uD45C\uC900\uC2DC(\uC624\uC2A4\uD2B8\uB808\uC77C\uB9AC\uC544)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"\ubcfc\uace0\uadf8\ub77c\ub4dc \uc2dc\uac04", "VOLT", - "\ubcfc\uace0\uadf8\ub77c\ub4dc \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "VOLST", - "\uBCFC\uACE0\uADF8\uB77C\uB4DC \uD45C\uC900\uC2DC", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java index 21852adbb67..60664c5b1f1 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String ACT[] = new String[] {"Fuso hor\u00e1rio do Acre", "ACT", "Fuso hor\u00e1rio de ver\u00e3o do Acre", "ACST", "Fuso hor\u00e1rio do Acre", "ACT"}; - String ADELAIDE[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Austr\u00E1lia do Sul)", "CST", - "Fuso Hor\u00E1rio de Ver\u00E3o Central (Austr\u00E1lia do Sul)", "CST", - "Hor\u00E1rio Central (Austr\u00E1lia do Sul)", "CT"}; + String ADELAIDE[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Austr\u00E1lia do Sul)", "ACST", + "Fuso Hor\u00E1rio de Ver\u00E3o Central (Austr\u00E1lia do Sul)", "ACDT", + "Hor\u00E1rio Central (Austr\u00E1lia do Sul)", "ACT"}; String AGT[] = new String[] {"Fuso hor\u00e1rio da Argentina", "ART", "Fuso hor\u00e1rio de ver\u00e3o da Argentina", "ARST", "Hor\u00E1rio da Argentina", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String BDT[] = new String[] {"Fuso hor\u00e1rio de Bangladesh", "BDT", "Fuso hor\u00e1rio de ver\u00e3o de Bangladesh", "BDST", "Hor\u00E1rio de Bangladesh", "BDT"}; - String BRISBANE[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Queensland)", "EST", - "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Queensland)", "EST", - "Hor\u00E1rio do Leste (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "CST", - "Fuso Hor\u00E1rio de Ver\u00E3o Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "CST", - "Hor\u00E1rio Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "CT"}; + String BRISBANE[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Queensland)", "AEST", + "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Queensland)", "AEDT", + "Hor\u00E1rio do Leste (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "ACST", + "Fuso Hor\u00E1rio de Ver\u00E3o Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "ACDT", + "Hor\u00E1rio Central (Austr\u00E1lia do Sul/Nova Gales do Sul)", "ACT"}; String BRT[] = new String[] {"Fuso hor\u00e1rio de Bras\u00edlia", "BRT", "Fuso hor\u00e1rio de ver\u00e3o de Bras\u00edlia", "BRST", "Hor\u00E1rio de Bras\u00EDlia", "BRT"}; @@ -108,9 +108,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o de Cuba", "CST", "Hor\u00e1rio de luz natural de Cuba", "CDT", "Hor\u00E1rio de Cuba", "CT"}; - String DARWIN[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Territ\u00F3rio do Norte)", "CST", - "Fuso Hor\u00E1rio de Ver\u00E3o Central (Territ\u00F3rio do Norte)", "CST", - "Hor\u00E1rio Central (Territ\u00F3rio do Norte)", "CT"}; + String DARWIN[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Central (Territ\u00F3rio do Norte)", "ACST", + "Fuso Hor\u00E1rio de Ver\u00E3o Central (Territ\u00F3rio do Norte)", "ACDT", + "Hor\u00E1rio Central (Territ\u00F3rio do Norte)", "ACT"}; String DUBLIN[] = new String[] {"Fuso hor\u00e1rio do meridiano de Greenwich", "GMT", "Fuso hor\u00e1rio de ver\u00e3o da Irlanda", "IST", "Hor\u00E1rio da Rep\u00FAblica da Irlanda", "IT"}; @@ -129,9 +129,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String EST[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o oriental", "EST", "Hor\u00e1rio de luz natural oriental", "EDT", "Hor\u00E1rio do Leste", "ET"}; - String EST_NSW[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Oriental (Nova Gales do Sul)", "EST", - "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Nova Gales do Sul)", "EST", - "Hor\u00E1rio Oriental (Nova Gales do Sul)", "ET"}; + String EST_NSW[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Oriental (Nova Gales do Sul)", "AEST", + "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Nova Gales do Sul)", "AEDT", + "Hor\u00E1rio Oriental (Nova Gales do Sul)", "AET"}; String FET[] = new String[] {"Hor\u00E1rio do Extremo Leste Europeu (FET)", "FET", "Fuso Hor\u00E1rio de Ver\u00E3o do Extremo Leste Europeu", "FEST", "Hor\u00E1rio do Extremo Leste Europeu (FET)", "FET"}; @@ -162,6 +162,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String ICT[] = new String[] {"Fuso hor\u00e1rio da Indochina", "ICT", "Fuso hor\u00e1rio de ver\u00e3o da Indochina", "ICST", "Hor\u00E1rio da Indochina", "ICT"}; + String IRKT[] = new String[] {"Fuso hor\u00e1rio de Irkutsk", "IRKT", + "Fuso hor\u00e1rio de ver\u00e3o de Irkutsk", "IRKST", + "Hor\u00E1rio de Irkutsk", "IRKT"}; String IRT[] = new String[] {"Fuso hor\u00e1rio do Ir\u00e3", "IRST", "Hor\u00e1rio de luz natural do Ir\u00e3", "IRDT", "Hor\u00E1rio do Ir\u00E3", "IRT"}; @@ -174,11 +177,14 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String JST[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o do Jap\u00e3o", "JST", "Hor\u00e1rio de luz natural do Jap\u00e3o", "JDT", "Hor\u00E1rio do Jap\u00E3o", "JT"}; + String KRAT[] = new String[] {"Fuso hor\u00e1rio de Krasnoyarsk", "KRAT", + "Fuso hor\u00e1rio de ver\u00e3o de Krasnoyarsk", "KRAST", + "Hor\u00E1rio de Krasnoyarsk", "KRAT"}; String KST[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o da Coreia", "KST", "Hor\u00e1rio de luz natural da Coreia", "KDT", "Hor\u00E1rio da Coreia", "KT"}; String LORD_HOWE[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o de Lord Howe", "LHST", - "Fuso hor\u00e1rio de ver\u00e3o de Lord Howe", "LHST", + "Fuso hor\u00e1rio de ver\u00e3o de Lord Howe", "LHDT", "Hor\u00E1rio de Lord Howe", "LHT"}; String MHT[] = new String[] {"Fuso hor\u00e1rio das Ilhas Marshall", "MHT", "Fuso hor\u00e1rio de ver\u00e3o das Ilhas Marshall", "MHST", @@ -228,12 +234,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String SGT[] = new String[] {"Fuso hor\u00e1rio de Cingapura", "SGT", "Fuso hor\u00e1rio de ver\u00e1 de Cingapura", "SGST", "Hor\u00E1rio de Cingapura", "SGT"}; - String SLST[] = new String[] {"Fuso hor\u00e1rio do meridiano de Greenwich", "GMT", - "Fuso hor\u00e1rio de ver\u00e3o de Serra Leoa", "SLST", - "Hor\u00E1rio de Serra Leoa", "SLT"}; - String TASMANIA[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Tasm\u00E2nia)", "EST", - "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Tasm\u00E2nia)", "EST", - "Hor\u00E1rio do Leste (Tasm\u00E2nia)", "ET"}; + String TASMANIA[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Tasm\u00E2nia)", "AEST", + "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Tasm\u00E2nia)", "AEDT", + "Hor\u00E1rio do Leste (Tasm\u00E2nia)", "AET"}; String TMT[] = new String[] {"Fuso hor\u00e1rio do Turcomenist\u00e3o", "TMT", "Fuso hor\u00e1rio de ver\u00e3o do Turcomenist\u00e3o", "TMST", "Hor\u00E1rio do Turcomenist\u00E3o", "TMT"}; @@ -252,29 +255,30 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { String WIT[] = new String[] {"Fuso hor\u00e1rio da Indon\u00e9sia Ocidental", "WIB", "Fuso hor\u00e1rio de ver\u00e3o da Indon\u00e9sia Ocidental", "WIST", "Hor\u00E1rio da Indon\u00E9sia Ocidental", "WIB"}; - String WST_AUS[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Ocidental (Austr\u00E1lia)", "WST", - "Fuso Hor\u00E1rio de Ver\u00E3o Ocidental (Austr\u00E1lia)", "WST", - "Hor\u00E1rio Ocidental (Austr\u00E1lia)", "WT"}; + String WST_AUS[] = new String[] {"Hor\u00E1rio-Padr\u00E3o Ocidental (Austr\u00E1lia)", "AWST", + "Fuso Hor\u00E1rio de Ver\u00E3o Ocidental (Austr\u00E1lia)", "AWDT", + "Hor\u00E1rio Ocidental (Austr\u00E1lia)", "AWT"}; String SAMOA[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o de Samoa", "SST", "Hor\u00e1rio de luz natural de Samoa", "SDT", "Hor\u00E1rio da Samoa", "ST"}; - String WST_SAMOA[] = new String[] {"Fuso hor\u00e1rio de Samoa Ocidental", "WST", + String WST_SAMOA[] = new String[] {"Fuso hor\u00e1rio de Samoa Ocidental", "WSST", "Fuso hor\u00e1rio de ver\u00e3o de Samoa Ocidental", "WSDT", "Fuso Hor\u00E1rio de Samoa Ocidental", "WST"}; String ChST[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o de Chamorro", "ChST", "Hor\u00e1rio de luz natural de Chamorro", "ChDT", "Hor\u00E1rio de Chamorro", "ChT"}; - String VICTORIA[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Victoria)", "EST", - "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Victoria)", "EST", - "Hor\u00E1rio do Leste (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"Hor\u00E1rio-Padr\u00E3o do Leste (Victoria)", "AEST", + "Fuso Hor\u00E1rio de Ver\u00E3o Oriental (Victoria)", "AEDT", + "Hor\u00E1rio do Leste (Victoria)", "AET"}; String UTC[] = new String[] {"Tempo universal coordenado", "UTC", "Tempo universal coordenado", "UTC", "Hor\u00E1rio Universal Coordenado", "UTC"}; String UZT[] = new String[] {"Fuso hor\u00e1rio do Uzbequist\u00e3o", "UZT", "Fuso hor\u00e1rio de ver\u00e3o do Uzbequist\u00e3o", "UZST", "Hor\u00E1rio do Uzbequist\u00E3o", "UZT"}; - String WART[] = new String[] {"Fuso hor\u00e1rio da Argentina Ocidental", "WART", - "Fuso hor\u00e1rio de ver\u00e3o da Argentina Ocidental", "WARST"}; + String XJT[] = new String[] {"Fuso hor\u00e1rio padr\u00e3o da China", "XJT", + "Hor\u00e1rio de luz natural da China", "XJDT", + "Hor\u00E1rio da China", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { "Fuso hor\u00e1rio de ver\u00e3o da Groenl\u00e2ndia Ocidental", "WGST", "Hor\u00E1rio da Groenl\u00E2ndia Ocidental", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Hor\u00E1rio Padr\u00E3o de Metlakatla", "MeST", - "Hor\u00E1rio de Luz Natural de Metlakatla", "MeDT", - "Hor\u00E1rio de Metlakatla", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Fuso hor\u00e1rio padr\u00e3o de S\u00e3o Pedro e Miquelon", "PMST", "Hor\u00e1rio de luz natural de S\u00e3o Pedro e Miquelon", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { "Fuso hor\u00e1rio de ver\u00e3o de Brunei", "BNST", "Hor\u00E1rio de Brunei", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Fuso hor\u00e1rio de Choibalsan", "CHOT", "Fuso hor\u00e1rio de ver\u00e3o de Choibalsan", "CHOST", "Hor\u00E1rio de Choibalsan", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Fuso hor\u00e1rio de Hovd", "HOVT", "Fuso hor\u00e1rio de ver\u00e3o de Hovd", "HOVST", "Hor\u00E1rio de Hovd", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Fuso hor\u00e1rio de Irkutsk", "IRKT", - "Fuso hor\u00e1rio de ver\u00e3o de Irkutsk", "IRKST", - "Hor\u00E1rio de Irkutsk", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"Fuso hor\u00e1rio da Indon\u00e9sia Oriental", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { "Fuso hor\u00e1rio de ver\u00e3o de Petropavlovsk-Kamchatski", "PETST", "Hor\u00E1rio de Petropavlovsk-Kamchatski", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Hor\u00E1rio de Khandyga", "YAKT", "Hor\u00E1rio de Ver\u00E3o de Khandyga", "YAKST", "Hor\u00E1rio de Khandyga", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Fuso hor\u00e1rio de Krasnoyarsk", "KRAT", - "Fuso hor\u00e1rio de ver\u00e3o de Krasnoyarsk", "KRAST", - "Hor\u00E1rio de Krasnoyarsk", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { "Hor\u00E1rio das Filipinas", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Fuso hor\u00e1rio de Uralsk", "ORAT", "Fuso hor\u00e1rio de ver\u00e3o de Uralsk", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Hor\u00E1rio de Ust-Nera", "VLAT", "Hor\u00E1rio de Ver\u00E3o de Ust-Nera", "VLAST", "Hor\u00E1rio de Ust-Nera", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Fuso Hor\u00E1rio Ocidental Central (Austr\u00E1lia)", "CWST", - "Fuso Hor\u00E1rio de Ver\u00E3o Ocidental Central (Austr\u00E1lia)", "CWST", - "Hor\u00E1rio Ocidental Central (Austr\u00E1lia)", "CWT"}}, + {"Australia/Eucla", new String[] {"Fuso Hor\u00E1rio Ocidental Central (Austr\u00E1lia)", "ACWST", + "Fuso Hor\u00E1rio de Ver\u00E3o Ocidental Central (Austr\u00E1lia)", "ACWDT", + "Hor\u00E1rio Ocidental Central (Austr\u00E1lia)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Fuso hor\u00e1rio de Volgogrado", "VOLT", - "Fuso hor\u00e1rio de ver\u00e3o de Volgogrado", "VOLST", - "Hor\u00E1rio de Volgogrado", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java index dd509e15142..ab28e0054a0 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String ACT[] = new String[] {"Acre, normaltid", "ACT", "Acre, sommartid", "ACST", "Acre, normaltid", "ACT"}; - String ADELAIDE[] = new String[] {"Central standardtid (Sydaustralien)", "CST", - "Central sommartid (South Australia)", "CST", - "Central tid (Sydaustralien)", "CT"}; + String ADELAIDE[] = new String[] {"Central standardtid (Sydaustralien)", "ACST", + "Central sommartid (South Australia)", "ACDT", + "Central tid (Sydaustralien)", "ACT"}; String AGT[] = new String[] {"Argentina, normaltid", "ART", "Argentina, sommartid", "ARST", "Argentinsk tid", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String BDT[] = new String[] {"Bangladesh, normaltid", "BDT", "Bangladesh, sommartid", "BDST", "Bangladeshisk tid", "BDT"}; - String BRISBANE[] = new String[] {"\u00D6stlig standardtid (Queensland)", "EST", - "\u00D6stlig sommartid (Queensland)", "EST", - "\u00D6stlig tid (Queensland)", "ET"}; - String BROKEN_HILL[] = new String[] {"Central standardtid (Sydaustralien/New South Wales)", "CST", - "Central sommartid (South Australia/New South Wales)", "CST", - "Central tid (Sydaustralien/New South Wales)", "CT"}; + String BRISBANE[] = new String[] {"\u00D6stlig standardtid (Queensland)", "AEST", + "\u00D6stlig sommartid (Queensland)", "AEDT", + "\u00D6stlig tid (Queensland)", "AET"}; + String BROKEN_HILL[] = new String[] {"Central standardtid (Sydaustralien/New South Wales)", "ACST", + "Central sommartid (South Australia/New South Wales)", "ACDT", + "Central tid (Sydaustralien/New South Wales)", "ACT"}; String BRT[] = new String[] {"Brasilien, normaltid", "BRT", "Brasilien, sommartid", "BRST", "Brasiliansk tid", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String CUBA[] = new String[] {"Kuba, normaltid", "CST", "Kuba, sommartid", "CDT", "Kubansk tid", "CT"}; - String DARWIN[] = new String[] {"Central standardtid (Nordterritoriet)", "CST", - "Central sommartid (Nordterritoriet)", "CST", - "Central tid (Nordterritoriet)", "CT"}; + String DARWIN[] = new String[] {"Central standardtid (Nordterritoriet)", "ACST", + "Central sommartid (Nordterritoriet)", "ACDT", + "Central tid (Nordterritoriet)", "ACT"}; String DUBLIN[] = new String[] {"Greenwichtid", "GMT", "Irland, sommartid", "IST", "Irl\u00E4ndsk tid", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String EST[] = new String[] {"Eastern, normaltid", "EST", "Eastern, sommartid", "EDT", "\u00D6stlig tid", "ET"}; - String EST_NSW[] = new String[] {"\u00D6stlig standardtid (New South Wales)", "EST", - "\u00D6stlig sommartid (New South Wales)", "EST", - "\u00D6stlig tid (New South Wales)", "ET"}; + String EST_NSW[] = new String[] {"\u00D6stlig standardtid (New South Wales)", "AEST", + "\u00D6stlig sommartid (New South Wales)", "AEDT", + "\u00D6stlig tid (New South Wales)", "AET"}; String FET[] = new String[] {"Kaliningradtid", "FET", "\u00D6steuropeisk sommartid", "FEST", "Kaliningradtid", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String ICT[] = new String[] {"Indokinesisk tid", "ICT", "Indokinesisk sommartid", "ICST", "Indokinesisk tid", "ICT"}; + String IRKT[] = new String[] {"Irkutsk, normaltid", "IRKT", + "Irkutsk, sommartid", "IRKST", + "Irkutsk-tid", "IRKT"}; String IRT[] = new String[] {"Iran, normaltid", "IRST", "Iran, sommartid", "IRDT", "Iransk tid", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String JST[] = new String[] {"Japan, normaltid", "JST", "Japan, sommartid", "JDT", "Japansk tid", "JT"}; + String KRAT[] = new String[] {"Krasnojarsk, normaltid", "KRAT", + "Krasnojarsk, sommartid", "KRAST", + "Krasnojarsk-tid", "KRAT"}; String KST[] = new String[] {"Korea, normaltid", "KST", "Korea, sommartid", "KDT", "Koreansk tid", "KT"}; String LORD_HOWE[] = new String[] {"Lord Howe, normaltid", "LHST", - "Lord Howe, sommartid", "LHST", + "Lord Howe, sommartid", "LHDT", "Lord Howe-tid", "LHT"}; String MHT[] = new String[] {"Marshall\u00f6arna, normaltid", "MHT", "Marshall\u00f6arna, sommartid", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String SGT[] = new String[] {"Singapore, normaltid", "SGT", "Singapore, sommartid", "SGST", "Singapore-tid", "SGT"}; - String SLST[] = new String[] {"Greenwichtid", "GMT", - "Sierra Leone, sommartid", "SLST", - "Sierra Leone-tid", "SLT"}; - String TASMANIA[] = new String[] {"\u00D6stlig standardtid (Tasmania)", "EST", - "\u00D6stlig sommartid (Tasmanien)", "EST", - "\u00D6stlig tid (Tasmania)", "ET"}; + String TASMANIA[] = new String[] {"\u00D6stlig standardtid (Tasmania)", "AEST", + "\u00D6stlig sommartid (Tasmanien)", "AEDT", + "\u00D6stlig tid (Tasmania)", "AET"}; String TMT[] = new String[] {"Turkmenistan, normaltid", "TMT", "Turkmenistan, sommartid", "TMST", "Turkmensk tid", "TMT"}; String ULAT[]= new String[] {"Ulaanbaatar, normaltid", "ULAT", "Ulaanbaatar, sommartid", "ULAST", "Ulaanbaatar-tid", "ULAT"}; - String WART[] = new String[] {"V\u00e4stargentina, normaltid", "WART", - "V\u00e4stargentina, sommartid", "WARST"}; String WAT[] = new String[] {"V\u00e4stafrikansk tid", "WAT", "V\u00e4stafrikansk sommartid", "WAST", "V\u00E4stafrikansk tid", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { String WIT[] = new String[] {"V\u00e4stindonesisk tid", "WIB", "V\u00e4stindonesisk sommartid", "WIST", "V\u00E4stindonesisk tid", "WIB"}; - String WST_AUS[] = new String[] {"Western Standard Time (Australien)", "WST", - "V\u00E4stlig sommartid (Australien)", "WST", - "V\u00E4stlig tid (Australien)", "WT"}; + String WST_AUS[] = new String[] {"Western Standard Time (Australien)", "AWST", + "V\u00E4stlig sommartid (Australien)", "AWDT", + "V\u00E4stlig tid (Australien)", "AWT"}; String SAMOA[] = new String[] {"Samoa, normaltid", "SST", "Samoa, sommartid", "SDT", "Samoansk tid", "ST"}; - String WST_SAMOA[] = new String[] {"V\u00e4stsamoansk tid", "WST", + String WST_SAMOA[] = new String[] {"V\u00e4stsamoansk tid", "WSST", "V\u00e4stsamoansk sommartid", "WSDT", "V\u00E4stsamoansk tid", "WST"}; String ChST[] = new String[] {"Chamorro, normaltid", "ChST", "Chamorro, sommartid", "ChDT", "Chamorros tid", "ChT"}; - String VICTORIA[] = new String[] {"\u00D6stlig standardtid (Victoria)", "EST", - "\u00D6stlig sommartid (Victoria)", "EST", - "\u00D6stlig tid (Victoria)", "ET"}; + String VICTORIA[] = new String[] {"\u00D6stlig standardtid (Victoria)", "AEST", + "\u00D6stlig sommartid (Victoria)", "AEDT", + "\u00D6stlig tid (Victoria)", "AET"}; String UTC[] = new String[] {"Koordinerad universell tid", "UTC", "Koordinerad universell tid", "UTC", "UTC (koordinerad v\u00E4rldstid)", "UTC"}; String UZT[] = new String[] {"Uzbekistan, normaltid", "UZT", "Uzbekistan, sommartid", "UZST", "Uzbekisk tid", "UZT"}; + String XJT[] = new String[] {"Kina, normaltid", "XJT", + "Kina, sommartid", "XJDT", + "Kinesisk tid", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "V\u00e4stra Gr\u00f6nland, sommartid", "WGST", "V\u00E4stgr\u00F6nl\u00E4ndsk tid", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"Metlakatla, normaltid", "MeST", - "Metlakatla, sommartid", "MeDT", - "Metlakatla-tid", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"Saint-Pierre-et-Miquelon, normaltid", "PMST", "Saint-Pierre-et-Miquelon, sommartid", "PMDT", @@ -612,6 +614,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Choibalsan-tid", "CHOT"}}, {"Asia/Chongqing", CTT}, {"Asia/Chungking", CTT}, + {"Asia/Chita", IRKT}, {"Asia/Colombo", IST}, {"Asia/Dacca", BDT}, {"Asia/Dhaka", BDT}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"Hovd, normaltid", "HOVT", "Hovd, sommartid", "HOVST", "Hovd-tid", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Irkutsk, normaltid", "IRKT", - "Irkutsk, sommartid", "IRKST", - "Irkutsk-tid", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"\u00d6stindonesisk tid", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Petropavlovsk-Kamtjatka, sommartid", "PETST", "Petropavlovsk-Kamtjatskij-tid", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"Khandyga, normaltid", "YAKT", "Khandyga, sommartid", "YAKST", "Khandyga, normaltid", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"Krasnojarsk, normaltid", "KRAT", - "Krasnojarsk, sommartid", "KRAST", - "Krasnojarsk-tid", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Filippinsk tid", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Oral, normaltid", "ORAT", "Oral, sommartid", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"Ust-Nera, normaltid", "VLAT", "Ust-Nera, sommartid", "VLAST", "Ust-Nera, normaltid", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central v\u00E4stlig normaltid (Australien)", "CWST", - "Central v\u00E4stlig sommartid (Australien)", "CWST", - "Central v\u00E4stlig tid (Australien)", "CWT"}}, + {"Australia/Eucla", new String[] {"Central v\u00E4stlig normaltid (Australien)", "ACWST", + "Central v\u00E4stlig sommartid (Australien)", "ACWDT", + "Central v\u00E4stlig tid (Australien)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"Volgograd-tid", "VOLT", - "Volgograd, sommartid", "VOLST", - "Volgograd, normaltid", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java index e4fca385baa..c8f109aec64 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String ACT[] = new String[] {"Acre \u65f6\u95f4", "ACT", "Acre \u590f\u4ee4\u65f6", "ACST", "Acre \u65f6\u95f4", "ACT"}; - String ADELAIDE[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A)", "CST", - "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5357\u6FB3\u5927\u5229\u4E9A)", "CST", - "\u4E2D\u90E8\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A)", "CT"}; + String ADELAIDE[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A)", "ACST", + "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5357\u6FB3\u5927\u5229\u4E9A)", "ACDT", + "\u4E2D\u90E8\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A)", "ACT"}; String AGT[] = new String[] {"\u963f\u6839\u5ef7\u65f6\u95f4", "ART", "\u963f\u6839\u5ef7\u590f\u4ee4\u65f6", "ARST", "\u963F\u6839\u5EF7\u65F6\u95F4", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String BDT[] = new String[] {"\u5b5f\u52a0\u62c9\u65f6\u95f4", "BDT", "\u5b5f\u52a0\u62c9\u590f\u4ee4\u65f6", "BDST", "\u5B5F\u52A0\u62C9\u65F6\u95F4", "BDT"}; - String BRISBANE[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u6606\u58EB\u5170)", "EST", - "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u6606\u58EB\u5170)", "EST", - "\u4E1C\u90E8\u65F6\u95F4 (\u6606\u58EB\u5170)", "ET"}; - String BROKEN_HILL[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "CST", - "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "CST", - "\u4E2D\u90E8\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "CT"}; + String BRISBANE[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u6606\u58EB\u5170)", "AEST", + "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u6606\u58EB\u5170)", "AEDT", + "\u4E1C\u90E8\u65F6\u95F4 (\u6606\u58EB\u5170)", "AET"}; + String BROKEN_HILL[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "ACST", + "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "ACDT", + "\u4E2D\u90E8\u65F6\u95F4 (\u5357\u6FB3\u5927\u5229\u4E9A/\u65B0\u5357\u5A01\u5C14\u65AF)", "ACT"}; String BRT[] = new String[] {"\u5df4\u897f\u5229\u4e9a\u65f6\u95f4", "BRT", "\u5df4\u897f\u5229\u4e9a\u590f\u4ee4\u65f6", "BRST", "\u5DF4\u897F\u5229\u4E9A\u65F6\u95F4", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String CUBA[] = new String[] {"\u53e4\u5df4\u6807\u51c6\u65f6\u95f4", "CST", "\u53e4\u5df4\u590f\u4ee4\u65f6", "CDT", "\u53E4\u5DF4\u65F6\u95F4", "CT"}; - String DARWIN[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5317\u9886\u5730)", "CST", - "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5317\u9886\u5730)", "CST", - "\u4E2D\u90E8\u65F6\u95F4 (\u5317\u90E8\u5730\u533A)", "CT"}; + String DARWIN[] = new String[] {"\u4E2D\u592E\u6807\u51C6\u65F6\u95F4 (\u5317\u9886\u5730)", "ACST", + "\u4E2D\u592E\u590F\u4EE4\u65F6 (\u5317\u9886\u5730)", "ACDT", + "\u4E2D\u90E8\u65F6\u95F4 (\u5317\u90E8\u5730\u533A)", "ACT"}; String DUBLIN[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u65f6\u95f4", "GMT", "\u7231\u5c14\u5170\u590f\u4ee4\u65f6", "IST", "\u7231\u5C14\u5170\u65F6\u95F4", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String EST[] = new String[] {"\u4e1c\u90e8\u6807\u51c6\u65f6\u95f4", "EST", "\u4e1c\u90e8\u590f\u4ee4\u65f6", "EDT", "\u4E1C\u90E8\u65F6\u95F4", "ET"}; - String EST_NSW[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u65B0\u5357\u5A01\u5C14\u65AF)", "EST", - "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u65B0\u5357\u5A01\u5C14\u65AF)", "EST", - "\u4E1C\u90E8\u65F6\u95F4 (\u65B0\u5357\u5A01\u5C14\u65AF)", "ET"}; + String EST_NSW[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u65B0\u5357\u5A01\u5C14\u65AF)", "AEST", + "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u65B0\u5357\u5A01\u5C14\u65AF)", "AEDT", + "\u4E1C\u90E8\u65F6\u95F4 (\u65B0\u5357\u5A01\u5C14\u65AF)", "AET"}; String FET[] = new String[] {"\u8FDC\u4E1C\u6B27\u65F6\u95F4", "FET", "\u8FDC\u4E1C\u6B27\u590F\u4EE4\u65F6", "FEST", "\u8FDC\u4E1C\u6B27\u65F6\u95F4", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String ICT[] = new String[] {"\u5370\u5ea6\u652f\u90a3\u65f6\u95f4", "ICT", "\u5370\u5ea6\u652f\u90a3\u590f\u4ee4\u65f6", "ICST", "\u5370\u5EA6\u652F\u90A3\u65F6\u95F4", "ICT"}; + String IRKT[] = new String[] {"\u4f0a\u5c14\u5e93\u6b21\u514b\u65f6\u95f4", "IRKT", + "\u4f0a\u5c14\u5e93\u6b21\u514b\u590f\u4ee4\u65f6", "IRKST", + "\u4F0A\u5C14\u5E93\u6B21\u514B\u65F6\u95F4", "IRKT"}; String IRT[] = new String[] {"\u4f0a\u6717\u6807\u51c6\u65f6\u95f4", "IRST", "\u4f0a\u6717\u590f\u4ee4\u65f6", "IRDT", "\u4F0A\u6717\u65F6\u95F4", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String JST[] = new String[] {"\u65e5\u672c\u6807\u51c6\u65f6\u95f4", "JST", "\u65e5\u672c\u590f\u4ee4\u65f6", "JDT", "\u65E5\u672C\u65F6\u95F4", "JT"}; + String KRAT[] = new String[] {"\u514b\u62c9\u65af\u8bfa\u4e9a\u5c14\u65af\u514b\u65f6\u95f4", "KRAT", + "\u514b\u62c9\u65af\u8bfa\u4e9a\u5c14\u65af\u514b\u590f\u4ee4\u65f6", "KRAST", + "\u514B\u62C9\u65AF\u8BFA\u4E9A\u5C14\u65AF\u514B\u65F6\u95F4", "KRAT"}; String KST[] = new String[] {"\u97e9\u56fd\u6807\u51c6\u65f6\u95f4", "KST", "\u97e9\u56fd\u590f\u4ee4\u65f6", "KDT", "\u97E9\u56FD\u65F6\u95F4", "KT"}; String LORD_HOWE[] = new String[] {"\u8c6a\u516c\u6807\u51c6\u65f6\u95f4", "LHST", - "\u8c6a\u516c\u590f\u4ee4\u65f6", "LHST", + "\u8c6a\u516c\u590f\u4ee4\u65f6", "LHDT", "\u8C6A\u516C\u65F6\u95F4", "LHT"}; String MHT[] = new String[] {"\u9a6c\u7ecd\u5c14\u7fa4\u5c9b\u65f6\u95f4", "MHT", "\u9a6c\u7ecd\u5c14\u7fa4\u5c9b\u590f\u4ee4\u65f6", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String SGT[] = new String[] {"\u65b0\u52a0\u5761\u65f6\u95f4", "SGT", "\u65b0\u52a0\u5761\u590f\u4ee4\u65f6", "SGST", "\u65B0\u52A0\u5761\u65F6\u95F4", "SGT"}; - String SLST[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u65f6\u95f4", "GMT", - "\u585e\u62c9\u5229\u6602\u590f\u4ee4\u65f6", "SLST", - "\u585E\u62C9\u91CC\u6602\u65F6\u95F4", "SLT"}; - String TASMANIA[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "EST", - "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "EST", - "\u4E1C\u90E8\u65F6\u95F4 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "ET"}; + String TASMANIA[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "AEST", + "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "AEDT", + "\u4E1C\u90E8\u65F6\u95F4 (\u5854\u65AF\u9A6C\u5C3C\u4E9A)", "AET"}; String TMT[] = new String[] {"\u571f\u5e93\u66fc\u65f6\u95f4", "TMT", "\u571f\u5e93\u66fc\u590f\u4ee4\u65f6", "TMST", "\u571F\u5E93\u66FC\u65F6\u95F4", "TMT"}; String ULAT[]= new String[] {"\u5e93\u4f26\u65f6\u95f4", "ULAT", "\u5e93\u4f26\u590f\u4ee4\u65f6", "ULAST", "\u5E93\u4F26\u65F6\u95F4", "ULAT"}; - String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u65f6\u95f4", "WART", - "\u897f\u963f\u6839\u5ef7\u590f\u4ee4\u65f6", "WARST"}; String WAT[] = new String[] {"\u897f\u975e\u65f6\u95f4", "WAT", "\u897f\u975e\u590f\u4ee4\u65f6", "WAST", "\u897F\u975E\u65F6\u95F4", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { String WIT[] = new String[] {"\u897f\u5370\u5ea6\u5c3c\u897f\u4e9a\u65f6\u95f4", "WIB", "\u897f\u5370\u5ea6\u5c3c\u897f\u4e9a\u590f\u4ee4\u65f6", "WIST", "\u897F\u5370\u5EA6\u5C3C\u897F\u4E9A\u65F6\u95F4", "WIB"}; - String WST_AUS[] = new String[] {"\u897F\u90E8\u6807\u51C6\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "WST", - "\u897F\u90E8\u590F\u4EE4\u65F6 (\u6FB3\u5927\u5229\u4E9A)", "WST", - "\u897F\u90E8\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "WT"}; + String WST_AUS[] = new String[] {"\u897F\u90E8\u6807\u51C6\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "AWST", + "\u897F\u90E8\u590F\u4EE4\u65F6 (\u6FB3\u5927\u5229\u4E9A)", "AWDT", + "\u897F\u90E8\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "AWT"}; String SAMOA[] = new String[] {"\u8428\u6469\u4e9a\u7fa4\u5c9b\u6807\u51c6\u65f6\u95f4", "SST", "\u8428\u6469\u4e9a\u7fa4\u5c9b\u590f\u4ee4\u65f6", "SDT", "\u8428\u6469\u4E9A\u65F6\u95F4", "ST"}; - String WST_SAMOA[] = new String[] {"\u897f\u8428\u6469\u4e9a\u65f6\u95f4", "WST", + String WST_SAMOA[] = new String[] {"\u897f\u8428\u6469\u4e9a\u65f6\u95f4", "WSST", "\u897f\u8428\u6469\u4e9a\u590f\u4ee4\u65f6", "WSDT", "\u897F\u8428\u6469\u4E9A\u65F6\u95F4", "WST"}; String ChST[] = new String[] {"Chamorro \u6807\u51c6\u65f6\u95f4", "ChST", "Chamorro \u590f\u4ee4\u65f6", "ChDT", "\u67E5\u6469\u6D1B\u65F6\u95F4", "ChT"}; - String VICTORIA[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u7EF4\u591A\u5229\u4E9A)", "EST", - "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u7EF4\u591A\u5229\u4E9A)", "EST", - "\u4E1C\u90E8\u65F6\u95F4 (\u7EF4\u591A\u5229\u4E9A)", "ET"}; + String VICTORIA[] = new String[] {"\u4E1C\u90E8\u6807\u51C6\u65F6\u95F4 (\u7EF4\u591A\u5229\u4E9A)", "AEST", + "\u4E1C\u90E8\u590F\u4EE4\u65F6 (\u7EF4\u591A\u5229\u4E9A)", "AEDT", + "\u4E1C\u90E8\u65F6\u95F4 (\u7EF4\u591A\u5229\u4E9A)", "AET"}; String UTC[] = new String[] {"\u534f\u8c03\u4e16\u754c\u65f6\u95f4", "UTC", "\u534f\u8c03\u4e16\u754c\u65f6\u95f4", "UTC", "\u534F\u8C03\u4E16\u754C\u65F6\u95F4", "UTC"}; String UZT[] = new String[] {"\u4e4c\u5179\u522b\u514b\u65af\u5766\u65f6\u95f4", "UZT", "\u4e4c\u5179\u522b\u514b\u65af\u5766\u590f\u4ee4\u65f6", "UZST", "\u4E4C\u5179\u522B\u514B\u65AF\u5766\u65F6\u95F4", "UZT"}; + String XJT[] = new String[] {"\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4", "XJT", + "\u4e2d\u56fd\u590f\u4ee4\u65f6", "XJDT", + "\u4E2D\u56FD\u65F6\u95F4", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u897f\u683c\u6797\u5170\u5c9b\u590f\u4ee4\u65f6", "WGST", "\u897F\u683C\u6797\u5170\u5C9B\u65F6\u95F4", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"\u6885\u7279\u62C9\u5361\u7279\u62C9\u6807\u51C6\u65F6\u95F4", "MeST", - "\u6885\u7279\u62C9\u5361\u7279\u62C9\u590F\u4EE4\u65F6", "MeDT", - "\u6885\u7279\u62C9\u5361\u7279\u62C9\u65F6\u95F4", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"\u76ae\u57c3\u5c14\u5c9b\u53ca\u5bc6\u514b\u9686\u5c9b\u6807\u51c6\u65f6\u95f4", "PMST", "\u76ae\u57c3\u5c14\u5c9b\u53ca\u5bc6\u514b\u9686\u5c9b\u590f\u4ee4\u65f6", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u6587\u83b1\u590f\u4ee4\u65f6", "BNST", "\u6587\u83B1\u65F6\u95F4", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"Choibalsan \u65f6\u95f4", "CHOT", "Choibalsan \u590f\u4ee4\u65f6", "CHOST", "Choibalsan \u65F6\u95F4", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"\u79d1\u5e03\u591a\u65f6\u95f4", "HOVT", "\u79d1\u5e03\u591a\u590f\u4ee4\u65f6", "HOVST", "\u79D1\u5E03\u591A\u65F6\u95F4", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"\u4f0a\u5c14\u5e93\u6b21\u514b\u65f6\u95f4", "IRKT", - "\u4f0a\u5c14\u5e93\u6b21\u514b\u590f\u4ee4\u65f6", "IRKST", - "\u4F0A\u5C14\u5E93\u6B21\u514B\u65F6\u95F4", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"\u4e1c\u5370\u5ea6\u5c3c\u897f\u4e9a\u65f6\u95f4", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u5f7c\u5f97\u7f57\u5df4\u752b\u6d1b\u592b\u65af\u514b\u590f\u4ee4\u65f6", "PETST", "\u5F7C\u5F97\u7F57\u5DF4\u752B\u6D1B\u592B\u65AF\u514B\u65F6\u95F4", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"\u6C49\u5FB7\u52A0\u65F6\u95F4", "YAKT", "\u6C49\u5FB7\u52A0\u590F\u4EE4\u65F6", "YAKST", "\u6C49\u5FB7\u52A0\u65F6\u95F4", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"\u514b\u62c9\u65af\u8bfa\u4e9a\u5c14\u65af\u514b\u65f6\u95f4", "KRAT", - "\u514b\u62c9\u65af\u8bfa\u4e9a\u5c14\u65af\u514b\u590f\u4ee4\u65f6", "KRAST", - "\u514B\u62C9\u65AF\u8BFA\u4E9A\u5C14\u65AF\u514B\u65F6\u95F4", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u83F2\u5F8B\u5BBE\u65F6\u95F4", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"Oral \u65f6\u95f4", "ORAT", "Oral \u590f\u4ee4\u65f6", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", CTT}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, @@ -708,7 +710,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"\u4E4C\u65AF\u5B63\u6D85\u62C9\u65F6\u95F4", "VLAT", "\u4E4C\u65AF\u5B63\u6D85\u62C9\u590F\u4EE4\u65F6", "VLAST", "\u4E4C\u65AF\u5B63\u6D85\u62C9\u65F6\u95F4", "VLAT"}}, @@ -750,9 +752,9 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6807\u51C6\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "CWST", - "\u4E2D\u897F\u90E8\u590F\u4EE4\u65F6 (\u6FB3\u5927\u5229\u4E9A)", "CWST", - "\u4E2D\u897F\u90E8\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "CWT"}}, + {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6807\u51C6\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "ACWST", + "\u4E2D\u897F\u90E8\u590F\u4EE4\u65F6 (\u6FB3\u5927\u5229\u4E9A)", "ACWDT", + "\u4E2D\u897F\u90E8\u65F6\u95F4 (\u6FB3\u5927\u5229\u4E9A)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -818,7 +820,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -853,9 +855,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"\u4f0f\u5c14\u52a0\u683c\u52d2\u65f6\u95f4", "VOLT", - "\u4f0f\u5c14\u52a0\u683c\u52d2\u590f\u4ee4\u65f6", "VOLST", - "\u4F0F\u5C14\u52A0\u683C\u52D2\u65F6\u95F4", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java b/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java index 20cfa231737..696b571ddc3 100644 --- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java +++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java @@ -48,9 +48,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String ACT[] = new String[] {"Acre \u6642\u9593", "ACT", "Acre \u590f\u4ee4\u6642\u9593", "ACST", "Acre \u6642\u9593", "ACT"}; - String ADELAIDE[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8)", "CST", - "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340)", "CST", - "\u4E2D\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8)", "CT"}; + String ADELAIDE[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8)", "ACST", + "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340)", "ACDT", + "\u4E2D\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8)", "ACT"}; String AGT[] = new String[] {"\u963f\u6839\u5ef7\u6642\u9593", "ART", "\u963f\u6839\u5ef7\u590f\u4ee4\u6642\u9593", "ARST", "\u963F\u6839\u5EF7\u6642\u9593", "ART"}; @@ -72,12 +72,12 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String BDT[] = new String[] {"\u5b5f\u52a0\u62c9\u6642\u9593", "BDT", "\u5b5f\u52a0\u62c9\u590f\u4ee4\u6642\u9593", "BDST", "\u5B5F\u52A0\u62C9\u6642\u9593", "BDT"}; - String BRISBANE[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u6606\u58EB\u862D)", "EST", - "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u6606\u58EB\u862D)", "EST", - "\u6771\u90E8\u6642\u9593 (\u6606\u58EB\u862D)", "ET"}; - String BROKEN_HILL[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340/\u65B0\u5357\u5A01\u723E\u65AF)", "CST", - "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340/\u65B0\u5357\u5A01\u723E\u65AF)", "CST", - "\u4E2D\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8/\u65B0\u5357\u5A01\u723E\u65AF)", "CT"}; + String BRISBANE[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u6606\u58EB\u862D)", "AEST", + "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u6606\u58EB\u862D)", "AEDT", + "\u6771\u90E8\u6642\u9593 (\u6606\u58EB\u862D)", "AET"}; + String BROKEN_HILL[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340/\u65B0\u5357\u5A01\u723E\u65AF)", "ACST", + "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u5340/\u65B0\u5357\u5A01\u723E\u65AF)", "ACDT", + "\u4E2D\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E\u5357\u90E8/\u65B0\u5357\u5A01\u723E\u65AF)", "ACT"}; String BRT[] = new String[] {"\u5df4\u897f\u5229\u4e9e\u6642\u9593", "BRT", "\u5df4\u897f\u5229\u4e9e\u590f\u4ee4\u6642\u9593", "BRST", "\u5DF4\u897F\u5229\u4E9E\u6642\u9593", "BRT"}; @@ -111,9 +111,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String CUBA[] = new String[] {"\u53e4\u5df4\u6a19\u6e96\u6642\u9593", "CST", "\u53e4\u5df4\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "CDT", "\u53E4\u5DF4\u6642\u9593", "CT"}; - String DARWIN[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u5317\u90E8\u5404\u5730\u5340)", "CST", - "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u5317\u90E8\u5404\u5730\u5340)", "CST", - "\u6FB3\u5927\u5229\u4E9E\u4E2D\u90E8\u6642\u9593 (\u5317\u65B9\u5340\u57DF)", "CT"}; + String DARWIN[] = new String[] {"\u4E2D\u90E8\u6A19\u6E96\u6642\u9593 (\u5317\u90E8\u5404\u5730\u5340)", "ACST", + "\u4E2D\u90E8\u590F\u4EE4\u6642\u9593 (\u5317\u90E8\u5404\u5730\u5340)", "ACDT", + "\u6FB3\u5927\u5229\u4E9E\u4E2D\u90E8\u6642\u9593 (\u5317\u65B9\u5340\u57DF)", "ACT"}; String DUBLIN[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u5e73\u5747\u6642\u9593", "GMT", "\u611b\u723e\u862d\u590f\u4ee4\u6642\u9593", "IST", "\u611B\u723E\u862D\u6587\u6642\u9593", "IT"}; @@ -132,9 +132,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String EST[] = new String[] {"\u6771\u65b9\u6a19\u6e96\u6642\u9593", "EST", "\u6771\u65b9\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "EDT", "\u7F8E\u570B\u6771\u90E8\u6642\u9593", "ET"}; - String EST_NSW[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "EST", - "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "EST", - "\u6771\u90E8\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "ET"}; + String EST_NSW[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "AEST", + "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "AEDT", + "\u6771\u90E8\u6642\u9593 (\u65B0\u5357\u5A01\u723E\u65AF)", "AET"}; String FET[] = new String[] {"\u6771\u6B50\u5167\u9678\u6642\u9593", "FET", "\u6771\u6B50\u5167\u9678\u590F\u4EE4\u6642\u9593", "FEST", "\u6771\u6B50\u5167\u9678\u6642\u9593", "FET"}; @@ -165,6 +165,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String ICT[] = new String[] {"\u5370\u5ea6\u652f\u90a3\u6642\u9593", "ICT", "\u5370\u5ea6\u652f\u90a3\u590f\u4ee4\u6642\u9593", "ICST", "\u5370\u5EA6\u652F\u90A3\u6642\u9593", "ICT"}; + String IRKT[] = new String[] {"Irkutsk \u6642\u9593", "IRKT", + "Irkutsk \u590f\u4ee4\u6642\u9593", "IRKST", + "\u4F0A\u723E\u5EAB\u6B21\u514B\u6642\u9593", "IRKT"}; String IRT[] = new String[] {"\u4f0a\u6717\u6a19\u6e96\u6642\u9593", "IRST", "\u4f0a\u6717\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "IRDT", "\u4F0A\u6717\u6642\u9593", "IRT"}; @@ -177,11 +180,14 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String JST[] = new String[] {"\u65e5\u672c\u6a19\u6e96\u6642\u9593", "JST", "\u65e5\u672c\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "JDT", "\u65E5\u672C\u6642\u9593", "JT"}; + String KRAT[] = new String[] {"\u514b\u62c9\u65af\u8afe\u4e9e\u723e\u65af\u514b\u6642\u9593", "KRAT", + "\u514b\u62c9\u65af\u8afe\u4e9e\u723e\u65af\u514b\u590f\u4ee4\u6642\u9593", "KRAST", + "\u514B\u62C9\u65AF\u8AFE\u4E9E\u723E\u65AF\u514B\u6642\u9593", "KRAT"}; String KST[] = new String[] {"\u97d3\u570b\u6a19\u6e96\u6642\u9593", "KST", "\u97d3\u570b\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "KDT", "\u97D3\u570B\u6642\u9593", "KT"}; String LORD_HOWE[] = new String[] {"\u8c6a\u52f3\u7235\u5cf6\u6a19\u6e96\u6642\u9593", "LHST", - "\u8c6a\u52f3\u7235\u5cf6\u590f\u4ee4\u6642\u9593", "LHST", + "\u8c6a\u52f3\u7235\u5cf6\u590f\u4ee4\u6642\u9593", "LHDT", "\u8C6A\u52F3\u7235\u5CF6\u6642\u9593", "LHT"}; String MHT[] = new String[] {"\u99ac\u7d39\u723e\u7fa4\u5cf6\u6642\u9593", "MHT", "\u99ac\u7d39\u723e\u7fa4\u5cf6\u590f\u4ee4\u6642\u9593", "MHST", @@ -231,20 +237,15 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String SGT[] = new String[] {"\u65b0\u52a0\u5761\u6642\u9593", "SGT", "\u65b0\u52a0\u5761\u590f\u4ee4\u6642\u9593", "SGST", "\u65B0\u52A0\u5761\u6642\u9593", "SGT"}; - String SLST[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u5e73\u5747\u6642\u9593", "GMT", - "\u7345\u5b50\u5c71\u590f\u4ee4\u6642\u9593", "SLST", - "\u7345\u5B50\u5C71\u6642\u9593", "SLT"}; - String TASMANIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u5854\u65AF\u6885\u5C3C\u4E9E\u5CF6)", "EST", - "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u5854\u65AF\u6885\u5C3C\u4E9E\u5CF6)", "EST", - "\u6FB3\u5927\u5229\u4E9E\u6771\u90E8\u6642\u9593 (\u5854\u65AF\u99AC\u5C3C\u4E9E\u5CF6)", "ET"}; + String TASMANIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u5854\u65AF\u6885\u5C3C\u4E9E\u5CF6)", "AEST", + "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u5854\u65AF\u6885\u5C3C\u4E9E\u5CF6)", "AEDT", + "\u6FB3\u5927\u5229\u4E9E\u6771\u90E8\u6642\u9593 (\u5854\u65AF\u99AC\u5C3C\u4E9E\u5CF6)", "AET"}; String TMT[] = new String[] {"\u571f\u5eab\u66fc\u6642\u9593", "TMT", "\u571f\u5eab\u66fc\u590f\u4ee4\u6642\u9593", "TMST", "\u571F\u5EAB\u66FC\u6642\u9593", "TMT"}; String ULAT[]= new String[] {"\u5eab\u502b\u6642\u9593", "ULAT", "\u5eab\u502b\u590f\u4ee4\u6642\u9593", "ULAST", "\u5EAB\u502B\u6642\u9593", "ULAT"}; - String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u6642\u9593", "WART", - "\u897f\u963f\u6839\u5ef7\u590f\u4ee4\u6642\u9593", "WARST"}; String WAT[] = new String[] {"\u897f\u975e\u6642\u9593", "WAT", "\u897f\u975e\u590f\u4ee4\u6642\u9593", "WAST", "\u897F\u975E\u6642\u9593", "WAT"}; @@ -254,27 +255,30 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { String WIT[] = new String[] {"\u897f\u5370\u5c3c\u6642\u9593", "WIB", "\u897f\u5370\u5c3c\u590f\u4ee4\u6642\u9593", "WIST", "\u897F\u5370\u5C3C\u6642\u9593", "WIB"}; - String WST_AUS[] = new String[] {"\u897F\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "WST", - "\u897F\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "WST", - "\u897F\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "WT"}; + String WST_AUS[] = new String[] {"\u897F\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "AWST", + "\u897F\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "AWDT", + "\u897F\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "AWT"}; String SAMOA[] = new String[] {"\u85a9\u6469\u4e9e\u6a19\u6e96\u6642\u9593", "SST", "\u85a9\u6469\u4e9e\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "SDT", "\u85A9\u6469\u4E9E\u6642\u9593", "ST"}; - String WST_SAMOA[] = new String[] {"\u897f\u85a9\u6469\u4e9e\u6642\u9593", "WST", + String WST_SAMOA[] = new String[] {"\u897f\u85a9\u6469\u4e9e\u6642\u9593", "WSST", "\u897f\u85a9\u6469\u4e9e\u590f\u4ee4\u6642\u9593", "WSDT", "\u897F\u85A9\u6469\u4E9E\u6642\u9593", "WST"}; String ChST[] = new String[] {"\u67e5\u83ab\u6d1b\u6a19\u6e96\u6642\u9593", "ChST", "\u67e5\u83ab\u6d1b\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "ChDT", "\u67E5\u83AB\u7F85\u6642\u9593", "ChT"}; - String VICTORIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E\u90A6)", "EST", - "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E\u90A6)", "EST", - "\u6771\u90E8\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E)", "ET"}; + String VICTORIA[] = new String[] {"\u6771\u90E8\u6A19\u6E96\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E\u90A6)", "AEST", + "\u6771\u90E8\u590F\u4EE4\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E\u90A6)", "AEDT", + "\u6771\u90E8\u6642\u9593 (\u7DAD\u591A\u5229\u4E9E)", "AET"}; String UTC[] = new String[] {"\u5354\u8abf\u4e16\u754c\u6642\u9593", "UTC", "\u5354\u8abf\u4e16\u754c\u6642\u9593", "UTC", "\u5354\u8ABF\u4E16\u754C\u6642\u9593", "UTC"}; String UZT[] = new String[] {"\u70cf\u8332\u5225\u514b\u65af\u5766\u6642\u9593", "UZT", "\u70cf\u8332\u5225\u514b\u65af\u5766\u590f\u4ee4\u6642\u9593", "UZST", "\u70CF\u8332\u5225\u514B\u65AF\u5766\u6642\u9593", "UZT"}; + String XJT[] = new String[] {"\u4e2d\u570b\u6a19\u6e96\u6642\u9593", "XJT", + "\u4e2d\u570b\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "XJDT", + "\u4E2D\u570B\u6642\u9593", "XJT"}; return new Object[][] { {"America/Los_Angeles", PST}, @@ -336,7 +340,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Africa/Djibouti", EAT}, {"Africa/Douala", WAT}, {"Africa/El_Aaiun", WET}, - {"Africa/Freetown", SLST}, + {"Africa/Freetown", GMT}, {"Africa/Gaborone", CAT}, {"Africa/Harare", CAT}, {"Africa/Johannesburg", SAST}, @@ -437,7 +441,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "\u897f\u683c\u6797\u862d\u5cf6\u590f\u4ee4\u6642\u9593", "WGST", "\u897F\u683C\u9675\u862D\u6642\u9593", "WGT"}}, {"America/Goose_Bay", AST}, - {"America/Grand_Turk", EST}, + {"America/Grand_Turk", AST}, {"America/Grenada", AST}, {"America/Guadeloupe", AST}, {"America/Guatemala", CST}, @@ -484,9 +488,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"America/Mendoza", AGT}, {"America/Menominee", CST}, {"America/Merida", CST}, - {"America/Metlakatla", new String[] {"\u6885\u7279\u62C9\u5361\u7279\u62C9\u6A19\u6E96\u6642\u9593", "MeST", - "\u6885\u7279\u62C9\u5361\u7279\u62C9\u65E5\u5149\u7BC0\u7D04\u6642\u9593", "MeDT", - "\u6885\u7279\u62C9\u5361\u7279\u62C9\u6642\u9593", "MeT"}}, + {"America/Metlakatla", PST}, {"America/Mexico_City", CST}, {"America/Miquelon", new String[] {"\u76ae\u57c3\u723e\u5cf6\u53ca\u5bc6\u514b\u9686\u5cf6\u6a19\u6e96\u6642\u9593", "PMST", "\u76ae\u57c3\u723e\u5cf6\u53ca\u5bc6\u514b\u9686\u5cf6\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "PMDT", @@ -607,6 +609,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "\u6c76\u840a\u590f\u4ee4\u6642\u9593", "BNST", "\u6C76\u840A\u6642\u9593", "BNT"}}, {"Asia/Calcutta", IST}, + {"Asia/Chita", IRKT}, {"Asia/Choibalsan", new String[] {"\u5de7\u5df4\u5c71 (Choibalsan) \u6642\u9593", "CHOT", "\u5de7\u5df4\u5c71 (Choibalsan) \u590f\u4ee4\u6642\u9593", "CHOST", "\u5DE7\u5DF4\u5C71 (Choibalsan) \u6642\u9593", "CHOT"}}, @@ -631,9 +634,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Asia/Hovd", new String[] {"\u4faf\u5fb7 (Hovd) \u6642\u9593", "HOVT", "\u4faf\u5fb7 (Hovd) \u590f\u4ee4\u6642\u9593", "HOVST", "\u4FAF\u5FB7 (Hovd) \u6642\u9593", "HOVT"}}, - {"Asia/Irkutsk", new String[] {"Irkutsk \u6642\u9593", "IRKT", - "Irkutsk \u590f\u4ee4\u6642\u9593", "IRKST", - "\u4F0A\u723E\u5EAB\u6B21\u514B\u6642\u9593", "IRKT"}}, + {"Asia/Irkutsk", IRKT}, {"Asia/Istanbul", EET}, {"Asia/Jakarta", WIT}, {"Asia/Jayapura", new String[] {"\u6771\u5370\u5ea6\u5c3c\u897f\u4e9e\u6642\u9593", "WIT", @@ -646,16 +647,14 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "Petropavlovsk-Kamchatski \u590f\u4ee4\u6642\u9593", "PETST", "Petropavlovsk-Kamchatski \u6642\u9593", "PETT"}}, {"Asia/Karachi", PKT}, - {"Asia/Kashgar", CTT}, + {"Asia/Kashgar", XJT}, {"Asia/Kathmandu", NPT}, {"Asia/Katmandu", NPT}, {"Asia/Khandyga", new String[] {"\u6F22\u5730\u52A0 (Khandyga) \u6642\u9593", "YAKT", "\u6F22\u5730\u52A0 (Khandyga) \u590F\u4EE4\u6642\u9593", "YAKST", "\u6F22\u5730\u52A0 (Khandyga) \u6642\u9593", "YAKT"}}, {"Asia/Kolkata", IST}, - {"Asia/Krasnoyarsk", new String[] {"\u514b\u62c9\u65af\u8afe\u4e9e\u723e\u65af\u514b\u6642\u9593", "KRAT", - "\u514b\u62c9\u65af\u8afe\u4e9e\u723e\u65af\u514b\u590f\u4ee4\u6642\u9593", "KRAST", - "\u514B\u62C9\u65AF\u8AFE\u4E9E\u723E\u65AF\u514B\u6642\u9593", "KRAT"}}, + {"Asia/Krasnoyarsk", KRAT}, {"Asia/Kuala_Lumpur", MYT}, {"Asia/Kuching", MYT}, {"Asia/Kuwait", ARAST}, @@ -670,7 +669,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "\u83F2\u5F8B\u8CD3\u6642\u9593", "PHT"}}, {"Asia/Muscat", GST}, {"Asia/Nicosia", EET}, - {"Asia/Novokuznetsk", NOVT}, + {"Asia/Novokuznetsk", KRAT}, {"Asia/Novosibirsk", NOVT}, {"Asia/Oral", new String[] {"\u6b50\u4f5b\u6642\u9593", "ORAT", "\u6b50\u4f5b\u590f\u4ee4\u6642\u9593", "ORAST", @@ -696,6 +695,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, + {"Asia/Srednekolymsk", new String[] {"Srednekolymsk Time", "SRET", + "Srednekolymsk Daylight Time", "SREDT", + "Srednekolymsk Time", "SRET"}}, {"Asia/Taipei", new String[] {"\u53f0\u7063\u6a19\u6e96\u6642\u9593", "TST", "\u53f0\u7063\u590f\u4ee4\u6642\u9593", "TDT", "\u53f0\u7063\u6642\u9593", "TT"}}, @@ -710,7 +712,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Asia/Ujung_Pandang", CIT}, {"Asia/Ulaanbaatar", ULAT}, {"Asia/Ulan_Bator", ULAT}, - {"Asia/Urumqi", CTT}, + {"Asia/Urumqi", XJT}, {"Asia/Ust-Nera", new String[] {"\u70CF\u65AF\u5167\u62C9 (Ust-Nera) \u6642\u9593", "VLAT", "\u70CF\u65AF\u5167\u62C9 (Ust-Nera) \u590F\u4EE4\u6642\u9593", "VLAST", "\u70CF\u65AF\u5167\u62C9 (Ust-Nera) \u6642\u9593", "VLAT"}}, @@ -752,9 +754,9 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "CWST", - "\u4E2D\u897F\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "CWST", - "\u4E2D\u897F\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "CWT"}}, + {"Australia/Eucla", new String[] {"\u4E2D\u897F\u90E8\u6A19\u6E96\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "ACWST", + "\u4E2D\u897F\u90E8\u590F\u4EE4\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "ACWDT", + "\u4E2D\u897F\u90E8\u6642\u9593 (\u6FB3\u5927\u5229\u4E9E)", "ACWT"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, @@ -820,7 +822,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Europe/Isle_of_Man", GMTBST}, {"Europe/Istanbul", EET}, {"Europe/Jersey", GMTBST}, - {"Europe/Kaliningrad", FET}, + {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, @@ -855,9 +857,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Europe/Vatican", CET}, {"Europe/Vienna", CET}, {"Europe/Vilnius", EET}, - {"Europe/Volgograd", new String[] {"\u4f0f\u723e\u52a0\u683c\u52d2\u6642\u9593", "VOLT", - "\u4f0f\u723e\u52a0\u683c\u52d2\u590f\u4ee4\u6642\u9593", "VOLST", - "\u4F0F\u723E\u52A0\u683C\u52D2\u6642\u9593", "VOLT"}}, + {"Europe/Volgograd", MSK}, {"Europe/Warsaw", CET}, {"Europe/Zagreb", CET}, {"Europe/Zaporozhye", EET}, diff --git a/jdk/src/jdk.runtime/share/native/common-unpack/unpack.cpp b/jdk/src/jdk.runtime/share/native/common-unpack/unpack.cpp index daf1b042428..5af0422661d 100644 --- a/jdk/src/jdk.runtime/share/native/common-unpack/unpack.cpp +++ b/jdk/src/jdk.runtime/share/native/common-unpack/unpack.cpp @@ -32,9 +32,12 @@ * the printf format %ld is correct and use of %lld will cause warning * errors from some compilers (gcc/g++). * _LP64 can be explicitly set (used on Linux). + * Should be checking for the Visual C++ since the _LP64 is set on the 64-bit + * systems but the correct format prefix for 64-bit integers is ll. * Solaris compilers will define __sparcv9 or __x86_64 on 64bit compilations. */ -#if defined(_LP64) || defined(__sparcv9) || defined(__x86_64) +#if !defined (_MSC_VER) && \ + (defined(_LP64) || defined(__sparcv9) || defined(__x86_64)) #define LONG_LONG_FORMAT "%ld" #define LONG_LONG_HEX_FORMAT "%lx" #else diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index fa11cfc642d..9b69db7c116 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -124,7 +124,7 @@ # jdk_management -# 8046351 +# 8044591 com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java generic-all com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationTest.java generic-all # 8056143 @@ -139,6 +139,9 @@ com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java aix-all com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java aix-all javax/management/MBeanServer/OldMBeanServerTest.java aix-all +# 8050115 +javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all + ############################################################################ # jdk_math @@ -272,6 +275,9 @@ com/sun/jdi/JdbReadTwiceTest.sh generic-all # jdk_util +# 8051641 +sun/util/calendar/zi/TestZoneInfo310.java generic-all + ############################################################################ # jdk_instrument @@ -283,15 +289,13 @@ com/sun/jdi/JdbReadTwiceTest.sh generic-all # 8031482 sun/tools/jcmd/TestJcmdSanity.java windows-all -# 8033104 -sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all - # 8027668 sun/tools/jstatd/TestJstatdDefaults.java generic-all sun/tools/jstatd/TestJstatdServer.java generic-all sun/tools/jstatd/TestJstatdPort.java generic-all +sun/tools/jstatd/TestJstatdPortAndServer.java generic-all -# 8046355 +# 8046285 8027668 sun/tools/jstatd/TestJstatdExternalRegistry.java generic-all # 6456333 diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index d361a3c5fcb..7c71d1e55cd 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -124,18 +124,29 @@ jdk_security2 = \ jdk_security3 = \ javax/security \ + -javax/security/auth/kerberos \ com/sun/security \ + -com/sun/security/jgss \ com/sun/org/apache/xml/internal/security \ sun/security \ + -sun/security/krb5 \ + -sun/security/jgss \ javax/net \ sun/net/www/protocol/https \ com/sun/net/ssl \ lib/security +jdk_security4 = \ + com/sun/security/jgss \ + javax/security/auth/kerberos \ + sun/security/krb5 \ + sun/security/jgss + jdk_security = \ :jdk_security1 \ :jdk_security2 \ - :jdk_security3 + :jdk_security3 \ + :jdk_security4 jdk_text = \ java/text \ diff --git a/jdk/test/java/lang/Integer/ParsingTest.java b/jdk/test/java/lang/Integer/ParsingTest.java index 920e81232a2..f5f64f70c84 100644 --- a/jdk/test/java/lang/Integer/ParsingTest.java +++ b/jdk/test/java/lang/Integer/ParsingTest.java @@ -23,24 +23,22 @@ /* * @test - * @bug 5017980 6576055 8041972 + * @bug 5017980 6576055 8041972 8055251 * @summary Test parsing methods * @author Joseph D. Darcy */ -import java.lang.IllegalArgumentException; import java.lang.IndexOutOfBoundsException; import java.lang.NullPointerException; import java.lang.RuntimeException; /** - * There are eight methods in java.lang.Integer which transform strings + * There are seven methods in java.lang.Integer which transform strings * into an int or Integer value: * * public Integer(String s) * public static Integer decode(String nm) - * public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex) - * public static int parseInt(CharSequence s, int radix, int beginIndex) + * public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix) * public static int parseInt(String s, int radix) * public static int parseInt(String s) * public static Integer valueOf(String s, int radix) @@ -55,20 +53,17 @@ import java.lang.RuntimeException; public class ParsingTest { public static void main(String... argv) { - check("+100", +100); - check("-100", -100); + check(+100, "+100"); + check(-100, "-100"); - check("+0", 0); - check("-0", 0); - check("+00000", 0); - check("-00000", 0); + check(0, "+0"); + check(0, "-0"); + check(0, "+00000"); + check(0, "-00000"); - check("+00000", 0, 0, 6); - check("-00000", 0, 0, 6); - - check("0", 0); - check("1", 1); - check("9", 9); + check(0, "0"); + check(1, "1"); + check(9, "9"); checkFailure(""); checkFailure("\u0000"); @@ -85,41 +80,37 @@ public class ParsingTest { checkFailure("-+6"); checkFailure("*100"); - check("test-00000", 0, 4, 10); - check("test-12345", -12345, 4, 10); - check("xx12345yy", 12345, 2, 7); + // check offset based methods + check(0, "+00000", 0, 6, 10); + check(0, "-00000", 0, 6, 10); + check(0, "test-00000", 4, 10, 10); + check(-12345, "test-12345", 4, 10, 10); + check(12345, "xx12345yy", 2, 7, 10); + check(15, "xxFyy", 2, 3, 16); - checkNumberFormatException("", 10, 0); - checkNumberFormatException("100", 10, 3); - checkNumberFormatException("+1000000", 10, 8); - checkNumberFormatException("-1000000", 10, 8); + checkNumberFormatException("", 0, 0, 10); + checkNumberFormatException("+-6", 0, 3, 10); + checkNumberFormatException("1000000", 7, 7, 10); + checkNumberFormatException("1000000", 0, 2, Character.MAX_RADIX + 1); + checkNumberFormatException("1000000", 0, 2, Character.MIN_RADIX - 1); - checkNumberFormatException("", 10, 0, 0); - checkNumberFormatException("+-6", 10, 0, 3); - checkNumberFormatException("1000000", 10, 7); - checkNumberFormatException("1000000", 10, 7, 7); - checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2); - checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2); + checkIndexOutOfBoundsException("1000000", 10, 4, 10); + checkIndexOutOfBoundsException("1000000", -1, 2, Character.MAX_RADIX + 1); + checkIndexOutOfBoundsException("1000000", -1, 2, Character.MIN_RADIX - 1); + checkIndexOutOfBoundsException("1000000", 10, 2, Character.MAX_RADIX + 1); + checkIndexOutOfBoundsException("1000000", 10, 2, Character.MIN_RADIX - 1); + checkIndexOutOfBoundsException("-1", 0, 3, 10); + checkIndexOutOfBoundsException("-1", 2, 3, 10); + checkIndexOutOfBoundsException("-1", -1, 2, 10); - checkIndexOutOfBoundsException("1000000", 10, 8); - checkIndexOutOfBoundsException("1000000", 10, -1); - checkIndexOutOfBoundsException("1000000", 10, 10, 4); - checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2); - checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2); - checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2); - checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2); - checkIndexOutOfBoundsException("-1", 10, 0, 3); - checkIndexOutOfBoundsException("-1", 10, 2, 3); - checkIndexOutOfBoundsException("-1", 10, -1, 2); - - checkNull(10, 0, 1); - checkNull(10, -1, 0); - checkNull(10, 0, 0); - checkNull(10, 0, -1); + checkNull(0, 1, 10); + checkNull(-1, 0, 10); + checkNull(0, 0, 10); + checkNull(0, -1, 10); checkNull(-1, -1, -1); } - private static void check(String val, int expected) { + private static void check(int expected, String val) { int n = Integer.parseInt(val); if (n != expected) throw new RuntimeException("Integer.parseInt failed. String:" + @@ -137,11 +128,11 @@ public class ParsingTest { } } - private static void checkNumberFormatException(String val, int radix, int start) { + private static void checkNumberFormatException(String val, int start, int end, int radix) { int n = 0; try { - n = Integer.parseInt(val, radix, start); - System.err.println("parseInt(" + val + ", " + radix + ", " + start + + n = Integer.parseInt(val, start, end, radix); + System.err.println("parseInt(" + val + ", " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (NumberFormatException nfe) { @@ -149,23 +140,11 @@ public class ParsingTest { } } - private static void checkNumberFormatException(String val, int radix, int start, int end) { + private static void checkIndexOutOfBoundsException(String val, int start, int end, int radix) { int n = 0; try { - n = Integer.parseInt(val, radix, start, end); - System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end + - ") incorrectly returned " + n); - throw new RuntimeException(); - } catch (NumberFormatException nfe) { - ; // Expected - } - } - - private static void checkIndexOutOfBoundsException(String val, int radix, int start) { - int n = 0; - try { - n = Integer.parseInt(val, radix, start); - System.err.println("parseInt(" + val + ", " + radix + ", " + start + + n = Integer.parseInt(val, start, end, radix); + System.err.println("parseInt(" + val + ", " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (IndexOutOfBoundsException ioob) { @@ -173,23 +152,11 @@ public class ParsingTest { } } - private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) { + private static void checkNull(int start, int end, int radix) { int n = 0; try { - n = Integer.parseInt(val, radix, start, end); - System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end + - ") incorrectly returned " + n); - throw new RuntimeException(); - } catch (IndexOutOfBoundsException ioob) { - ; // Expected - } - } - - private static void checkNull(int radix, int start, int end) { - int n = 0; - try { - n = Integer.parseInt(null, 10, start, end); - System.err.println("parseInt(null, " + radix + ", " + start + ", " + end + + n = Integer.parseInt(null, start, end, radix); + System.err.println("parseInt(null, " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (NullPointerException npe) { @@ -197,10 +164,10 @@ public class ParsingTest { } } - private static void check(String val, int expected, int start, int end) { - int n = Integer.parseInt(val, 10, start, end); + private static void check(int expected, String val, int start, int end, int radix) { + int n = Integer.parseInt(val, start, end, radix); if (n != expected) - throw new RuntimeException("Integer.parsedInt failed. String:" + - val + ", start: " + start + ", end: " + end + " Result:" + n); + throw new RuntimeException("Integer.parsedInt failed. Expected: " + expected + " String: \"" + + val + "\", start: " + start + ", end: " + end + ", radix: " + radix + " Result:" + n); } } diff --git a/jdk/test/java/lang/Integer/Unsigned.java b/jdk/test/java/lang/Integer/Unsigned.java index 09be7bfddb6..6c3aecc70c1 100644 --- a/jdk/test/java/lang/Integer/Unsigned.java +++ b/jdk/test/java/lang/Integer/Unsigned.java @@ -303,6 +303,17 @@ public class Unsigned { "\tconverting back ''%s'' resulted in %d%n", value, radix, longString, intResult); } + + // test offset based parse method + intResult = Integer.parseUnsignedInt("prefix" + longString + "suffix", + "prefix".length(), "prefix".length() + longString.length(), radix); + + if (Integer.toUnsignedLong(intResult) != value) { + errors++; + System.err.printf("Bad roundtrip conversion of %d in base %d" + + "\tconverting back ''%s'' resulted in %d%n", + value, radix, longString, intResult); + } } } diff --git a/jdk/test/java/lang/Long/ParsingTest.java b/jdk/test/java/lang/Long/ParsingTest.java index 42c49dddf3d..cbf83415d36 100644 --- a/jdk/test/java/lang/Long/ParsingTest.java +++ b/jdk/test/java/lang/Long/ParsingTest.java @@ -23,19 +23,18 @@ /* * @test - * @bug 5017980 6576055 8041972 + * @bug 5017980 6576055 8041972 8055251 * @summary Test parsing methods * @author Joseph D. Darcy */ /** - * There are eight methods in java.lang.Long which transform strings + * There are seven methods in java.lang.Long which transform strings * into a long or Long value: * * public Long(String s) * public static Long decode(String nm) * public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex) - * public static long parseLong(CharSequence s, int radix, int beginIndex) * public static long parseLong(String s, int radix) * public static long parseLong(String s) * public static Long valueOf(String s, int radix) @@ -49,17 +48,17 @@ public class ParsingTest { public static void main(String... argv) { - check("+100", +100L); - check("-100", -100L); + check(+100L, "+100"); + check(-100L, "-100"); - check("+0", 0L); - check("-0", 0L); - check("+00000", 0L); - check("-00000", 0L); + check(0L, "+0"); + check(0L, "-0"); + check(0L, "+00000"); + check(0L, "-00000"); - check("0", 0L); - check("1", 1L); - check("9", 9L); + check(0L, "0"); + check(1L, "1"); + check(9L, "9"); checkFailure(""); checkFailure("\u0000"); @@ -76,40 +75,36 @@ public class ParsingTest { checkFailure("-+6"); checkFailure("*100"); - check("test-00000", 0L, 4, 10); - check("test-12345", -12345L, 4, 10); - check("xx12345yy", 12345L, 2, 7); - check("xx123456789012345yy", 123456789012345L, 2, 17); + check(0L, "test-00000", 4, 10, 10); + check(-12345L, "test-12345", 4, 10, 10); + check(12345L, "xx12345yy", 2, 7, 10); + check(123456789012345L, "xx123456789012345yy", 2, 17, 10); + check(15L, "xxFyy", 2, 3, 16); - checkNumberFormatException("100", 10, 3); - checkNumberFormatException("", 10, 0); - checkNumberFormatException("+1000000", 10, 8); - checkNumberFormatException("-1000000", 10, 8); + checkNumberFormatException("", 0, 0, 10); + checkNumberFormatException("+-6", 0, 3, 10); + checkNumberFormatException("1000000", 7, 7, 10); + checkNumberFormatException("1000000", 0, 2, Character.MAX_RADIX + 1); + checkNumberFormatException("1000000", 0, 2, Character.MIN_RADIX - 1); - checkNumberFormatException("", 10, 0, 0); - checkNumberFormatException("+-6", 10, 0, 3); - checkNumberFormatException("1000000", 10, 7, 7); - checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2); - checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2); + checkIndexOutOfBoundsException("", 1, 1, 10); + checkIndexOutOfBoundsException("1000000", 10, 4, 10); + checkIndexOutOfBoundsException("1000000", 10, 2, Character.MAX_RADIX + 1); + checkIndexOutOfBoundsException("1000000", 10, 2, Character.MIN_RADIX - 1); + checkIndexOutOfBoundsException("1000000", -1, 2, Character.MAX_RADIX + 1); + checkIndexOutOfBoundsException("1000000", -1, 2, Character.MIN_RADIX - 1); + checkIndexOutOfBoundsException("-1", 0, 3, 10); + checkIndexOutOfBoundsException("-1", 2, 3, 10); + checkIndexOutOfBoundsException("-1", -1, 2, 10); - checkIndexOutOfBoundsException("", 10, 1, 1); - checkIndexOutOfBoundsException("1000000", 10, 10, 4); - checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2); - checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2); - checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2); - checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2); - checkIndexOutOfBoundsException("-1", 10, 0, 3); - checkIndexOutOfBoundsException("-1", 10, 2, 3); - checkIndexOutOfBoundsException("-1", 10, -1, 2); - - checkNull(10, 0, 1); - checkNull(10, -1, 0); - checkNull(10, 0, 0); - checkNull(10, 0, -1); + checkNull(0, 1, 10); + checkNull(-1, 0, 10); + checkNull(0, 0, 10); + checkNull(0, -1, 10); checkNull(-1, -1, -1); } - private static void check(String val, long expected) { + private static void check(long expected, String val) { long n = Long.parseLong(val); if (n != expected) throw new RuntimeException("Long.parseLong failed. String:" + @@ -127,11 +122,11 @@ public class ParsingTest { } } - private static void checkNumberFormatException(String val, int radix, int start) { + private static void checkNumberFormatException(String val, int start, int end, int radix) { long n = 0; try { - n = Long.parseLong(val, radix, start); - System.err.println("parseLong(" + val + ", " + radix + ", " + start + + n = Long.parseLong(val, start, end, radix); + System.err.println("parseLong(" + val + ", " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (NumberFormatException nfe) { @@ -139,23 +134,11 @@ public class ParsingTest { } } - private static void checkNumberFormatException(String val, int radix, int start, int end) { + private static void checkIndexOutOfBoundsException(String val, int start, int end, int radix) { long n = 0; try { - n = Long.parseLong(val, radix, start, end); - System.err.println("parseLong(" + val + ", " + radix + ", " + start + ", " + end + - ") incorrectly returned " + n); - throw new RuntimeException(); - } catch (NumberFormatException nfe) { - ; // Expected - } - } - - private static void checkIndexOutOfBoundsException(String val, int radix, int start) { - long n = 0; - try { - n = Long.parseLong(val, radix, start); - System.err.println("parseLong(" + val + ", " + radix + ", " + start + + n = Long.parseLong(val, start, end, radix); + System.err.println("parseLong(" + val + ", " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (IndexOutOfBoundsException ioob) { @@ -163,23 +146,11 @@ public class ParsingTest { } } - private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) { + private static void checkNull(int start, int end, int radix) { long n = 0; try { - n = Long.parseLong(val, radix, start, end); - System.err.println("parseLong(" + val + ", " + radix + ", " + start + ", " + end + - ") incorrectly returned " + n); - throw new RuntimeException(); - } catch (IndexOutOfBoundsException ioob) { - ; // Expected - } - } - - private static void checkNull(int radix, int start, int end) { - long n = 0; - try { - n = Long.parseLong(null, 10, start, end); - System.err.println("parseLong(null, " + radix + ", " + start + ", " + end + + n = Long.parseLong(null, start, end, radix); + System.err.println("parseLong(null, " + start + ", " + end + ", " + radix + ") incorrectly returned " + n); throw new RuntimeException(); } catch (NullPointerException npe) { @@ -187,10 +158,10 @@ public class ParsingTest { } } - private static void check(String val, long expected, int start, int end) { - long n = Long.parseLong(val, 10, start, end); + private static void check(long expected, String val, int start, int end, int radix) { + long n = Long.parseLong(val, start, end, radix); if (n != expected) - throw new RuntimeException("Long.parseLong failed. String:" + - val + ", start: " + start + ", end: " + end + " Result:" + n); + throw new RuntimeException("Long.parseLong failed. Expexted: " + expected + " String: \"" + + val + "\", start: " + start + ", end: " + end + " radix: " + radix + " Result: " + n); } } diff --git a/jdk/test/java/lang/Long/Unsigned.java b/jdk/test/java/lang/Long/Unsigned.java index 3686457ffe6..41f7692597c 100644 --- a/jdk/test/java/lang/Long/Unsigned.java +++ b/jdk/test/java/lang/Long/Unsigned.java @@ -289,6 +289,17 @@ public class Unsigned { "\tconverting back ''%s'' resulted in %d%n", value, radix, bigString, longResult); } + + // test offset based parse method + longResult = Long.parseUnsignedLong("prefix" + bigString + "suffix", "prefix".length(), + "prefix".length() + bigString.length(), radix); + + if (!toUnsignedBigInt(longResult).equals(value)) { + errors++; + System.err.printf("Bad roundtrip conversion of %d in base %d" + + "\tconverting back ''%s'' resulted in %d%n", + value, radix, bigString, longResult); + } } } diff --git a/jdk/test/java/lang/invoke/MethodHandlesTest.java b/jdk/test/java/lang/invoke/MethodHandlesTest.java index d607e06aad2..993eaefef0f 100644 --- a/jdk/test/java/lang/invoke/MethodHandlesTest.java +++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java @@ -2160,15 +2160,23 @@ public class MethodHandlesTest { else type = type.changeParameterType(j, argType); if (done.add(type)) - testInvokers(type); + testInvokersWithCatch(type); MethodType vtype = type.changeReturnType(void.class); if (done.add(vtype)) - testInvokers(vtype); + testInvokersWithCatch(vtype); } } } } + public void testInvokersWithCatch(MethodType type) throws Throwable { + try { + testInvokers(type); + } catch (Throwable ex) { + System.out.println("*** testInvokers on "+type+" => "); + ex.printStackTrace(System.out); + } + } public void testInvokers(MethodType type) throws Throwable { if (verbosity >= 3) System.out.println("test invokers for "+type); diff --git a/jdk/test/java/lang/invoke/VarargsArrayTest.java b/jdk/test/java/lang/invoke/VarargsArrayTest.java new file mode 100644 index 00000000000..91bf36485f2 --- /dev/null +++ b/jdk/test/java/lang/invoke/VarargsArrayTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2014, 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 java.lang.invoke; + +import sun.invoke.util.Wrapper; + +import java.util.Arrays; +import java.util.Collections; + +/* @test + * @summary unit tests for varargs array methods: MethodHandleInfo.varargsArray(int), + * MethodHandleInfo.varargsArray(Class,int) & MethodHandleInfo.varargsList(int) + * + * @run main/bootclasspath java.lang.invoke.VarargsArrayTest + * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250 + * java.lang.invoke.VarargsArrayTest + */ + +/* This might take a while and burn lots of metadata: + * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true java.lang.invoke.VarargsArrayTest + */ +public class VarargsArrayTest { + private static final Class CLASS = VarargsArrayTest.class; + private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); + private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0); + private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE"); + + public static void main(String[] args) throws Throwable { + testVarargsArray(); + testVarargsReferenceArray(); + testVarargsPrimitiveArray(); + } + + public static void testVarargsArray() throws Throwable { + final int MIN = START_ARITY; + final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added + for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) { + MethodHandle target = MethodHandleImpl.varargsArray(nargs); + Object[] args = new Object[nargs]; + for (int i = 0; i < nargs; i++) + args[i] = "#"+i; + Object res = target.invokeWithArguments(args); + assertArrayEquals(args, (Object[])res); + } + } + + public static void testVarargsReferenceArray() throws Throwable { + testTypedVarargsArray(Object[].class); + testTypedVarargsArray(String[].class); + testTypedVarargsArray(Number[].class); + } + + public static void testVarargsPrimitiveArray() throws Throwable { + testTypedVarargsArray(int[].class); + testTypedVarargsArray(long[].class); + testTypedVarargsArray(byte[].class); + testTypedVarargsArray(boolean[].class); + testTypedVarargsArray(short[].class); + testTypedVarargsArray(char[].class); + testTypedVarargsArray(float[].class); + testTypedVarargsArray(double[].class); + } + + private static int nextArgCount(int nargs, int density, int MAX) { + if (EXHAUSTIVE) return nargs + 1; + if (nargs >= MAX) return Integer.MAX_VALUE; + int BOT = 20, TOP = MAX-5; + if (density < 10) { BOT = 10; MAX = TOP-2; } + if (nargs <= BOT || nargs >= TOP) { + ++nargs; + } else { + int bump = Math.max(1, 100 / density); + nargs += bump; + if (nargs > TOP) nargs = TOP; + } + return nargs; + } + + private static void testTypedVarargsArray(Class arrayType) throws Throwable { + Class elemType = arrayType.getComponentType(); + int MIN = START_ARITY; + int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added + int density = 3; + if (elemType == int.class || elemType == long.class) density = 7; + if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; } + for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) { + Object[] args = makeTestArray(elemType, nargs); + MethodHandle varargsArray = MethodHandleImpl.varargsArray(arrayType, nargs); + MethodType vaType = varargsArray.type(); + assertEquals(arrayType, vaType.returnType()); + if (nargs != 0) { + assertEquals(elemType, vaType.parameterType(0)); + assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1)); + } + assertEquals(MethodType.methodType(arrayType, Collections.>nCopies(nargs, elemType)), + vaType); + Object res = varargsArray.invokeWithArguments(args); + assertEquals(res.getClass(), arrayType); + String resString = toArrayString(res); + assertEquals(Arrays.toString(args), resString); + + MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs); + MethodType stype = spreader.type(); + assert(stype == MethodType.methodType(arrayType, arrayType)); + if (nargs <= 5) { + // invoke target as a spreader also: + @SuppressWarnings("cast") + Object res2 = spreader.invokeWithArguments((Object)res); + String res2String = toArrayString(res2); + assertEquals(Arrays.toString(args), res2String); + // invoke the spreader on a generic Object[] array; check for error + try { + Object res3 = spreader.invokeWithArguments((Object)args); + String res3String = toArrayString(res3); + assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); + assertEquals(Arrays.toString(args), res3String); + } catch (ClassCastException ex) { + assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); + } + } + if (nargs == 0) { + // invoke spreader on null arglist + Object res3 = spreader.invokeWithArguments((Object)null); + String res3String = toArrayString(res3); + assertEquals(Arrays.toString(args), res3String); + } + } + } + + private static Object[] makeTestArray(Class elemType, int len) { + Wrapper elem = null; + if (elemType.isPrimitive()) + elem = Wrapper.forPrimitiveType(elemType); + else if (Wrapper.isWrapperType(elemType)) + elem = Wrapper.forWrapperType(elemType); + Object[] args = new Object[len]; + for (int i = 0; i < len; i++) { + Object arg = i * 100; + if (elem == null) { + if (elemType == String.class) + arg = "#"+arg; + arg = elemType.cast(arg); // just to make sure + } else { + switch (elem) { + case BOOLEAN: arg = (i % 3 == 0); break; + case CHAR: arg = 'a' + i; break; + case LONG: arg = (long)i * 1000_000_000; break; + case FLOAT: arg = (float)i / 100; break; + case DOUBLE: arg = (double)i / 1000_000; break; + } + arg = elem.cast(arg, elemType); + } + args[i] = arg; + } + return args; + } + + private static String toArrayString(Object a) { + if (a == null) return "null"; + Class elemType = a.getClass().getComponentType(); + if (elemType == null) return a.toString(); + if (elemType.isPrimitive()) { + switch (Wrapper.forPrimitiveType(elemType)) { + case INT: return Arrays.toString((int[])a); + case BYTE: return Arrays.toString((byte[])a); + case BOOLEAN: return Arrays.toString((boolean[])a); + case SHORT: return Arrays.toString((short[])a); + case CHAR: return Arrays.toString((char[])a); + case FLOAT: return Arrays.toString((float[])a); + case LONG: return Arrays.toString((long[])a); + case DOUBLE: return Arrays.toString((double[])a); + } + } + return Arrays.toString((Object[])a); + } + + public static void assertArrayEquals(Object[] arr1, Object[] arr2) { + if (arr1 == null && arr2 == null) return; + if (arr1 != null && arr2 != null && arr1.length == arr2.length) { + for (int i = 0; i < arr1.length; i++) { + assertEquals(arr1[i], arr2[i]); + } + return; + } + throw new AssertionError(Arrays.deepToString(arr1) + " != " + Arrays.deepToString(arr2)); + } + + public static void assertEquals(Object o1, Object o2) { + if (o1 == null && o2 == null) return; + if (o1 != null && o1.equals(o2)) return; + throw new AssertionError(o1 + " != " + o2); + } + + public static void assertTrue(String msg, boolean b) { + if (!b) { + throw new AssertionError(msg); + } + } + + public static void assertFalse(String msg, boolean b) { + assertTrue(msg, !b); + } +} diff --git a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java index 450cc870296..c269c398bc8 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java @@ -63,11 +63,16 @@ public class LowMemoryTest { // Use a low young gen size to ensure that the // allocated objects are put in the old gen. final String nmFlag = "-Xmn" + YOUNG_GEN_SIZE; - RunUtil.runTestKeepGcOpts(main, nmFlag); - RunUtil.runTestClearGcOpts(main, nmFlag, "-XX:+UseSerialGC"); - RunUtil.runTestClearGcOpts(main, nmFlag, "-XX:+UseParallelGC"); - RunUtil.runTestClearGcOpts(main, nmFlag, "-XX:+UseG1GC"); - RunUtil.runTestClearGcOpts(main, nmFlag, "-XX:+UseConcMarkSweepGC"); + // Using large pages will change the young gen size, + // make sure we don't use them for this test. + final String lpFlag = "-XX:-UseLargePages"; + // Prevent G1 from selecting a large heap region size, + // since that would change the young gen size. + final String g1Flag = "-XX:G1HeapRegionSize=1m"; + RunUtil.runTestClearGcOpts(main, nmFlag, lpFlag, "-XX:+UseSerialGC"); + RunUtil.runTestClearGcOpts(main, nmFlag, lpFlag, "-XX:+UseParallelGC"); + RunUtil.runTestClearGcOpts(main, nmFlag, lpFlag, "-XX:+UseG1GC", g1Flag); + RunUtil.runTestClearGcOpts(main, nmFlag, lpFlag, "-XX:+UseConcMarkSweepGC"); } private static volatile boolean listenerInvoked = false; @@ -155,19 +160,23 @@ public class LowMemoryTest { Thread allocator = new AllocatorThread(); Thread sweeper = new SweeperThread(); - // Now set threshold + // The chunk size needs to be larger than YOUNG_GEN_SIZE, + // otherwise we will get intermittent failures when objects + // end up in the young gen instead of the old gen. + final long epsilon = 1024; + chunkSize = YOUNG_GEN_SIZE + epsilon; + MemoryUsage mu = mpool.getUsage(); - chunkSize = (mu.getMax() - mu.getUsed()) / 20; newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); - // Sanity check. Make sure the chunkSize is large than the YOUNG_GEN_SIZE - // If the chunkSize are lower than the YOUNG_GEN_SIZE, we will get intermittent - // failures when objects end up in the young gen instead of the old gen. + // Sanity check. Make sure the new threshold isn't too large. // Tweak the test if this fails. - if (chunkSize < YOUNG_GEN_SIZE) { - throw new RuntimeException("TEST FAILED: " + - " chunkSize: " + chunkSize + " is less than YOUNG_GEN_SIZE: " + YOUNG_GEN_SIZE + - " max: " + mu.getMax() + " used: " + mu.getUsed() + " newThreshold: " + newThreshold); + final long headRoom = chunkSize * 2; + final long max = mu.getMax(); + if (max != -1 && newThreshold > max - headRoom) { + throw new RuntimeException("TEST FAILED: newThreshold: " + newThreshold + + " is too near the maximum old gen size: " + max + + " used: " + mu.getUsed() + " headRoom: " + headRoom); } System.out.println("Setting threshold for " + mpool.getName() + diff --git a/jdk/test/java/lang/management/MemoryMXBean/MemoryManagement.java b/jdk/test/java/lang/management/MemoryMXBean/MemoryManagement.java index b9db049946f..4cd913d7bcd 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/MemoryManagement.java +++ b/jdk/test/java/lang/management/MemoryMXBean/MemoryManagement.java @@ -31,7 +31,7 @@ * @author Mandy Chung * * @build MemoryManagement MemoryUtil - * @run main/othervm/timeout=600 -Xmn8m MemoryManagement + * @run main/othervm/timeout=600 -Xmn8m -XX:+IgnoreUnrecognizedVMOptions -XX:G1HeapRegionSize=1 -XX:-UseLargePages MemoryManagement */ import java.lang.management.*; @@ -103,25 +103,24 @@ public class MemoryManagement { Thread allocator = new AllocatorThread(); + // The chunk size needs to be larger than YOUNG_GEN_SIZE, + // otherwise we will get intermittent failures when objects + // end up in the young gen instead of the old gen. + final long epsilon = 1024; + chunkSize = YOUNG_GEN_SIZE + epsilon; + // Now set threshold MemoryUsage mu = mpool.getUsage(); - long max = mu.getMax(); - if (max != -1) { - chunkSize = (max - mu.getUsed()) / 20; - } else { // 6980984 - System.gc(); - chunkSize = Runtime.getRuntime().freeMemory()/20; - } newThreshold = mu.getUsed() + (chunkSize * NUM_CHUNKS); - // Sanity check. Make sure the chunkSize is large than the YOUNG_GEN_SIZE - // If the chunkSize are lower than the YOUNG_GEN_SIZE, we will get intermittent - // failures when objects end up in the young gen instead of the old gen. + // Sanity check. Make sure the new threshold isn't too large. // Tweak the test if this fails. - if (chunkSize < YOUNG_GEN_SIZE) { - throw new RuntimeException("TEST FAILED: " + - " chunkSize: " + chunkSize + " is less than YOUNG_GEN_SIZE: " + YOUNG_GEN_SIZE + - " max: " + mu.getMax() + " used: " + mu.getUsed() + " newThreshold: " + newThreshold); + final long headRoom = chunkSize * 2; + final long max = mu.getMax(); + if (max != -1 && newThreshold > max - headRoom) { + throw new RuntimeException("TEST FAILED: newThreshold: " + newThreshold + + " is too near the maximum old gen size: " + max + + " used: " + mu.getUsed() + " headRoom: " + headRoom); } System.out.println("Setting threshold for " + mpool.getName() + diff --git a/jdk/test/java/lang/reflect/Field/TestFieldReflectValueOf.java b/jdk/test/java/lang/reflect/Field/TestFieldReflectValueOf.java new file mode 100644 index 00000000000..bc80c49f03a --- /dev/null +++ b/jdk/test/java/lang/reflect/Field/TestFieldReflectValueOf.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2014, 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 5043030 + * @summary Verify that the method java.lang.reflect.Field.get(Object) makes + * use of the same caching mechanism as used for autoboxing + * when wrapping values of the primitive types. + * @author Andrej Golovnin + */ + +import java.lang.reflect.Field; + +public class TestFieldReflectValueOf { + + @SuppressWarnings("unused") + private static boolean booleanStaticField; + @SuppressWarnings("unused") + private static byte byteStaticField; + @SuppressWarnings("unused") + private static char charStaticField; + @SuppressWarnings("unused") + private static int intStaticField; + @SuppressWarnings("unused") + private static long longStaticField; + @SuppressWarnings("unused") + private static short shortStaticField; + + @SuppressWarnings("unused") + private static volatile boolean booleanStaticVolatileField; + @SuppressWarnings("unused") + private static volatile byte byteStaticVolatileField; + @SuppressWarnings("unused") + private static volatile char charStaticVolatileField; + @SuppressWarnings("unused") + private static volatile int intStaticVolatileField; + @SuppressWarnings("unused") + private static volatile long longStaticVolatileField; + @SuppressWarnings("unused") + private static volatile short shortStaticVolatileField; + + @SuppressWarnings("unused") + private boolean booleanField; + @SuppressWarnings("unused") + private byte byteField; + @SuppressWarnings("unused") + private char charField; + @SuppressWarnings("unused") + private int intField; + @SuppressWarnings("unused") + private long longField; + @SuppressWarnings("unused") + private short shortField; + + @SuppressWarnings("unused") + private volatile boolean booleanVolatileField; + @SuppressWarnings("unused") + private volatile byte byteVolatileField; + @SuppressWarnings("unused") + private volatile char charVolatileField; + @SuppressWarnings("unused") + private volatile int intVolatileField; + @SuppressWarnings("unused") + private volatile long longVolatileField; + @SuppressWarnings("unused") + private volatile short shortVolatileField; + + public static void main(String[] args) { + testUnsafeStaticFieldAccessors(); + testUnsafeQualifiedStaticFieldAccessors(); + testUnsafeFieldAccessors(); + testUnsafeQualifiedFieldAccessors(); + } + + private static void testUnsafeStaticFieldAccessors() { + testFieldAccessors(true, false); + } + + private static void testUnsafeQualifiedStaticFieldAccessors() { + testFieldAccessors(true, true); + } + + private static void testUnsafeFieldAccessors() { + testFieldAccessors(false, false); + } + + private static void testUnsafeQualifiedFieldAccessors() { + testFieldAccessors(false, true); + } + + private static void testFieldAccessors(boolean checkStatic, + boolean checkVolatile) + { + // Boolean#valueOf test + testField(Boolean.TYPE, Boolean.FALSE, checkStatic, checkVolatile); + testField(Boolean.TYPE, Boolean.TRUE, checkStatic, checkVolatile); + + // Byte#valueOf test + for (int b = Byte.MIN_VALUE; b < (Byte.MAX_VALUE + 1); b++) { + testField(Byte.TYPE, Byte.valueOf((byte) b), checkStatic, checkVolatile); + } + + // Character#valueOf test + for (char c = '\u0000'; c <= '\u007F'; c++) { + testField(Character.TYPE, Character.valueOf(c), checkStatic, checkVolatile); + } + + // Integer#valueOf test + for (int i = -128; i <= 127; i++) { + testField(Integer.TYPE, Integer.valueOf(i), checkStatic, checkVolatile); + } + + // Long#valueOf test + for (long l = -128L; l <= 127L; l++) { + testField(Long.TYPE, Long.valueOf(l), checkStatic, checkVolatile); + } + + // Short#valueOf test + for (short s = -128; s <= 127; s++) { + testField(Short.TYPE, Short.valueOf(s), checkStatic, checkVolatile); + } + } + + private static void testField(Class primType, Object wrappedValue, + boolean checkStatic, boolean checkVolatile) + { + String fieldName = primType.getName(); + if (checkStatic) { + fieldName += "Static"; + } + if (checkVolatile) { + fieldName += "Volatile"; + } + fieldName += "Field"; + try { + Field field = TestFieldReflectValueOf.class.getDeclaredField(fieldName); + field.setAccessible(true); + TestFieldReflectValueOf obj = new TestFieldReflectValueOf(); + field.set(obj, wrappedValue); + Object result = field.get(obj); + if (result != wrappedValue) { + throw new RuntimeException("The value " + wrappedValue + + " is not cached for the type " + primType); + } + } catch ( NoSuchFieldException | SecurityException + | IllegalAccessException | IllegalArgumentException e) + { + throw new RuntimeException(e); + } + } + +} diff --git a/jdk/test/java/lang/reflect/Method/invoke/TestMethodReflectValueOf.java b/jdk/test/java/lang/reflect/Method/invoke/TestMethodReflectValueOf.java new file mode 100644 index 00000000000..048eac55f45 --- /dev/null +++ b/jdk/test/java/lang/reflect/Method/invoke/TestMethodReflectValueOf.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014, 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 5043030 + * @summary Verify that the method java.lang.reflect.Method.invoke(Object, Object...) + * makes use of the same caching mechanism as used for autoboxing + * when wrapping returned values of the primitive types. + * @author Andrej Golovnin + * @run main/othervm -Dsun.reflect.noInflation=true TestMethodReflectValueOf + * @run main/othervm -Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=500 TestMethodReflectValueOf + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +public class TestMethodReflectValueOf { + + public static void main(String[] args) { + // When the inflation is disabled we compare values using "==" + // as the returned values of the primitive types should be cached + // by the same mechanism as used for autoboxing. When the inflation + // is enabled we use "equals()"-method to compare values as the native + // code still creates new instances to wrap values of the primitive + // types. + boolean checkIdentity = Boolean.getBoolean("sun.reflect.noInflation"); + + // Boolean#valueOf test + testMethod(Boolean.TYPE, Boolean.FALSE, checkIdentity); + testMethod(Boolean.TYPE, Boolean.TRUE, checkIdentity); + + // Byte#valueOf test + for (int b = Byte.MIN_VALUE; b < (Byte.MAX_VALUE + 1); b++) { + testMethod(Byte.TYPE, Byte.valueOf((byte) b), checkIdentity); + } + + // Character#valueOf test + for (char c = '\u0000'; c <= '\u007F'; c++) { + testMethod(Character.TYPE, Character.valueOf(c), checkIdentity); + } + + // Integer#valueOf test + for (int i = -128; i <= 127; i++) { + testMethod(Integer.TYPE, Integer.valueOf(i), checkIdentity); + } + + // Long#valueOf test + for (long l = -128L; l <= 127L; l++) { + testMethod(Long.TYPE, Long.valueOf(l), checkIdentity); + } + + // Short#valueOf test + for (short s = -128; s <= 127; s++) { + testMethod(Short.TYPE, Short.valueOf(s), checkIdentity); + } + } + + public static void testMethod(Class primType, Object wrappedValue, + boolean checkIdentity) + { + String methodName = primType.getName() + "Method"; + try { + Method method = TestMethodReflectValueOf.class.getMethod(methodName, primType); + Object result = method.invoke(new TestMethodReflectValueOf(), wrappedValue); + if (checkIdentity) { + if (result != wrappedValue) { + throw new RuntimeException("The value " + wrappedValue + + " is not cached for the type " + primType); + } + } else { + if (!result.equals(wrappedValue)) { + throw new RuntimeException("The result value " + result + + " is not equal to the expected value " + + wrappedValue + " for the type " + primType); + } + } + } catch ( NoSuchMethodException | SecurityException + | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) + { + throw new RuntimeException(e); + } + } + + public int intMethod(int value) { + return value; + } + + public long longMethod(long value) { + return value; + } + + public short shortMethod(short value) { + return value; + } + + public byte byteMethod(byte value) { + return value; + } + + public char charMethod(char value) { + return value; + } + + public boolean booleanMethod(boolean value) { + return value; + } + +} diff --git a/jdk/test/java/lang/reflect/annotationSharing/AnnotationSharing.java b/jdk/test/java/lang/reflect/annotationSharing/AnnotationSharing.java new file mode 100644 index 00000000000..98a13d6416c --- /dev/null +++ b/jdk/test/java/lang/reflect/annotationSharing/AnnotationSharing.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2014, 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 8054987 + * @summary Test sharing of annotations between Executable/Field instances. + * Sharing should not be noticeable when performing mutating + * operations. + * @run testng AnnotationSharing + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; + +import org.testng.annotations.Test; + +public class AnnotationSharing { + @Test + public void testMethodSharing() throws Exception { + Method[] m1 = AnnotationSharing.class.getMethods(); + Method[] m2 = AnnotationSharing.class.getMethods(); + validateSharingSafelyObservable(m1, m2); + } + + @Test + public void testDeclaredMethodSharing() throws Exception { + Method[] m3 = AnnotationSharing.class.getDeclaredMethods(); + Method[] m4 = AnnotationSharing.class.getDeclaredMethods(); + validateSharingSafelyObservable(m3, m4); + } + + @Test + public void testFieldSharing() throws Exception { + Field[] f1 = AnnotationSharing.class.getFields(); + Field[] f2 = AnnotationSharing.class.getFields(); + validateSharingSafelyObservable(f1, f2); + } + + @Test + public void testDeclaredFieldsSharing() throws Exception { + Field[] f3 = AnnotationSharing.class.getDeclaredFields(); + Field[] f4 = AnnotationSharing.class.getDeclaredFields(); + validateSharingSafelyObservable(f3, f4); + } + + @Test + public void testMethodSharingOccurs() throws Exception { + Method mm1 = AnnotationSharing.class.getDeclaredMethod("m", (Class[])null); + Method mm2 = AnnotationSharing.class.getDeclaredMethod("m", (Class[])null); + validateAnnotationSharing(mm1, mm2); + } + + @Test + public void testMethodSharingIsSafe() throws Exception { + Method mm1 = AnnotationSharing.class.getDeclaredMethod("m", (Class[])null); + Method mm2 = AnnotationSharing.class.getDeclaredMethod("m", (Class[])null); + validateAnnotationSharingIsSafe(mm1, mm2); + validateArrayValues(mm1.getAnnotation(Baz.class), mm2.getAnnotation(Baz.class)); + } + + @Test + public void testFieldSharingOccurs() throws Exception { + Field ff1 = AnnotationSharing.class.getDeclaredField("f"); + Field ff2 = AnnotationSharing.class.getDeclaredField("f"); + validateAnnotationSharing(ff1, ff2); + } + + @Test + public void testFieldSharingIsSafe() throws Exception { + Field ff1 = AnnotationSharing.class.getDeclaredField("f"); + Field ff2 = AnnotationSharing.class.getDeclaredField("f"); + validateAnnotationSharingIsSafe(ff1, ff2); + validateArrayValues(ff1.getAnnotation(Baz.class), ff2.getAnnotation(Baz.class)); + } + + // Validate that AccessibleObject instances are not shared + private static void validateSharingSafelyObservable(AccessibleObject[] m1, AccessibleObject[] m2) + throws Exception { + + // Validate that setAccessible works + for (AccessibleObject m : m1) + m.setAccessible(false); + + for (AccessibleObject m : m2) + m.setAccessible(true); + + for (AccessibleObject m : m1) + if (m.isAccessible()) + throw new RuntimeException(m + " should not be accessible"); + + for (AccessibleObject m : m2) + if (!m.isAccessible()) + throw new RuntimeException(m + " should be accessible"); + + // Validate that methods are still equal() + for (int i = 0; i < m1.length; i++) + if (!m1[i].equals(m2[i])) + throw new RuntimeException(m1[i] + " and " + m2[i] + " should be equal()"); + + // Validate that the arrays aren't shared + for (int i = 0; i < m1.length; i++) + m1[i] = null; + + for (int i = 0; i < m2.length; i++) + if (m2[i] == null) + throw new RuntimeException("Detected sharing of AccessibleObject arrays"); + } + + // Validate that annotations are shared + private static void validateAnnotationSharing(AccessibleObject m1, AccessibleObject m2) { + Bar b1 = m1.getAnnotation(Bar.class); + Bar b2 = m2.getAnnotation(Bar.class); + + if (b1 != b2) + throw new RuntimeException(b1 + " and " + b2 + " should be =="); + + } + + // Validate that Method instances representing the annotation elements + // behave as intended + private static void validateAnnotationSharingIsSafe(AccessibleObject m1, AccessibleObject m2) + throws Exception { + Bar b1 = m1.getAnnotation(Bar.class); + Bar b2 = m2.getAnnotation(Bar.class); + + Method mm1 = b1.annotationType().getMethod("value", (Class[]) null); + Method mm2 = b2.annotationType().getMethod("value", (Class[]) null); + inner(mm1, mm2); + + mm1 = b1.getClass().getMethod("value", (Class[]) null); + mm2 = b2.getClass().getMethod("value", (Class[]) null); + inner(mm1, mm2); + + } + private static void inner(Method mm1, Method mm2) + throws Exception { + if (!mm1.equals(mm2)) + throw new RuntimeException(mm1 + " and " + mm2 + " should be equal()"); + + mm1.setAccessible(false); + mm2.setAccessible(true); + + if (mm1.isAccessible()) + throw new RuntimeException(mm1 + " should not be accessible"); + + if (!mm2.isAccessible()) + throw new RuntimeException(mm2 + " should be accessible"); + } + + // Validate that array element values are not shared + private static void validateArrayValues(Baz a, Baz b) { + String[] s1 = a.value(); + String[] s2 = b.value(); + + s1[0] = "22"; + + if (!s2[0].equals("1")) + throw new RuntimeException("Mutation of array elements should not be detectable"); + } + + @Foo @Bar("val") @Baz({"1", "2"}) + public void m() { + return ; + } + + @Foo @Bar("someValue") @Baz({"1", "22", "33"}) + public Object f = new Object(); +} + +@Retention(RetentionPolicy.RUNTIME) +@interface Foo {} + +@Retention(RetentionPolicy.RUNTIME) +@interface Bar { + String value(); +} + +@Retention(RetentionPolicy.RUNTIME) +@interface Baz { + String [] value(); +} diff --git a/jdk/test/java/nio/file/WatchService/LotsOfCancels.java b/jdk/test/java/nio/file/WatchService/LotsOfCancels.java new file mode 100644 index 00000000000..cb7f9eff9af --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/LotsOfCancels.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 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 8029516 + * @summary Bash on WatchKey.cancel with a view to causing a crash when + * an outstanding I/O operation on directory completes after the + * directory has been closed + */ + +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import static java.nio.file.StandardWatchEventKinds.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class LotsOfCancels { + + // set to true for any exceptions + static volatile boolean failed; + + public static void main(String[] args) throws Exception { + + // create a bunch of directories. Create two tasks for each directory, + // one to bash on cancel, the other to poll the events + ExecutorService pool = Executors.newCachedThreadPool(); + try { + Path top = Files.createTempDirectory("work"); + top.toFile().deleteOnExit(); + for (int i=1; i<=16; i++) { + Path dir = Files.createDirectory(top.resolve("dir-" + i)); + WatchService watcher = FileSystems.getDefault().newWatchService(); + pool.submit(() -> handle(dir, watcher)); + pool.submit(() -> poll(watcher)); + } + } finally { + pool.shutdown(); + } + + // give thread pool lots of time to terminate + if (!pool.awaitTermination(5L, TimeUnit.MINUTES)) + throw new RuntimeException("Thread pool did not terminate"); + + if (failed) + throw new RuntimeException("Test failed, see log for details"); + } + + /** + * Stress the given WatchService, specifically the cancel method, in + * the given directory. Closes the WatchService when done. + */ + static void handle(Path dir, WatchService watcher) { + try { + try { + Path file = dir.resolve("anyfile"); + for (int i=0; i<2000; i++) { + WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE); + Files.createFile(file); + Files.delete(file); + key.cancel(); + } + } finally { + watcher.close(); + } + } catch (Exception e) { + e.printStackTrace(); + failed = true; + } + } + + /** + * Polls the given WatchService in a tight loop. This keeps the event + * queue drained, it also hogs a CPU core which seems necessary to + * tickle the original bug. + */ + static void poll(WatchService watcher) { + try { + for (;;) { + WatchKey key = watcher.take(); + if (key != null) { + key.pollEvents(); + key.reset(); + } + } + } catch (ClosedWatchServiceException expected) { + // nothing to do + } catch (Exception e) { + e.printStackTrace(); + failed = true; + } + } + +} + diff --git a/jdk/test/java/sql/test/sql/DateTests.java b/jdk/test/java/sql/test/sql/DateTests.java index 5a660507eee..ae6c276c4f6 100644 --- a/jdk/test/java/sql/test/sql/DateTests.java +++ b/jdk/test/java/sql/test/sql/DateTests.java @@ -26,261 +26,43 @@ import java.sql.Date; import java.time.Instant; import java.time.LocalDate; import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import util.BaseTest; -public class DateTests { +public class DateTests extends BaseTest { - public DateTests() { - } - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } - - /** + /* * Validate an IllegalArgumentException is thrown for an invalid Date string */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_year() throws Exception { - String expResult = "20009-11-01"; - Date.valueOf(expResult); + @Test(dataProvider = "invalidDateValues", + expectedExceptions = IllegalArgumentException.class) + public void test(String d) throws Exception { + Date.valueOf(d); } - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_year2() throws Exception { - String expResult = "09-11-01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_year3() throws Exception { - String expResult = "-11-01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_month() throws Exception { - String expResult = "2009-111-01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_month3() throws Exception { - String expResult = "2009--01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_month4() throws Exception { - String expResult = "2009-13-01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_day() throws Exception { - String expResult = "2009-11-011"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_day3() throws Exception { - String expResult = "2009-11-"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_day4() throws Exception { - String expResult = "2009-11-00"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_day5() throws Exception { - String expResult = "2009-11-33"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf() throws Exception { - String expResult = "--"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf2() throws Exception { - String expResult = ""; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf3() throws Exception { - String expResult = null; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf4() throws Exception { - String expResult = "-"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf5() throws Exception { - String expResult = "2009"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf6() throws Exception { - String expResult = "2009-01"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf7() throws Exception { - String expResult = "---"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf8() throws Exception { - String expResult = "2009-13--1"; - Date.valueOf(expResult); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Date string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_valueOf10() { - String expResult = "1900-1-0"; - Date.valueOf(expResult); - } - - /** + /* * Test that a date created from a date string is equal to the value * returned from toString() */ - @Test - public void test_valueOf() { - String expResult = "2009-08-30"; - Date d = Date.valueOf(expResult); - assertEquals(expResult, d.toString()); + @Test(dataProvider = "validDateValues") + public void test00(String d, String expectedD) { + Date d1 = Date.valueOf(d); + Date d2 = Date.valueOf(expectedD); + assertTrue(d1.equals(d2) && d2.equals(d1) + && d1.toString().equals(expectedD), "Error d1 != d2"); } - /** - * Test that two dates, one with lead 0s omitted for month are equal - */ - @Test - public void testValid_month_single_digit() { - String testDate = "2009-1-01"; - String expResult = "2009-01-01"; - Date d = Date.valueOf(testDate); - Date d2 = Date.valueOf(expResult); - assertEquals(d, d2); - } - - /** - * Test that two dates, one with lead 0s omitted for day are equal - */ - @Test - public void testValid_day_single_digit() { - String testDate = "2009-11-1"; - String expResult = "2009-11-01"; - Date d = Date.valueOf(testDate); - Date d2 = Date.valueOf(expResult); - assertEquals(d, d2); - } - - /** - * Test that two dates, one with lead 0s omitted for month and day are equal - */ - @Test - public void testValid_month_day_single_digit() { - String testDate = "2009-1-1"; - String expResult = "2009-01-01"; - Date d = Date.valueOf(testDate); - Date d2 = Date.valueOf(expResult); - assertEquals(d, d2); - } - - /** + /* * Validate that a Date.after() returns false when same date is compared */ @Test - public void test1() { + public void test01() { Date d = Date.valueOf("1961-08-30"); assertFalse(d.after(d), "Error d.after(d) = true"); } - /** + /* * Validate that a Date.after() returns true when later date is compared to * earlier date */ @@ -291,7 +73,7 @@ public class DateTests { assertTrue(d2.after(d), "Error d2.after(d) = false"); } - /** + /* * Validate that a Date.after() returns false when earlier date is compared * to later date */ @@ -302,7 +84,7 @@ public class DateTests { assertFalse(d.after(d2), "Error d.after(d2) = true"); } - /** + /* * Validate that a Date.after() returns false when date compared to another * date created from the original date */ @@ -314,7 +96,7 @@ public class DateTests { assertFalse(d2.after(d), "Error d2.after(d) = true"); } - /** + /* * Validate that a Date.before() returns false when same date is compared */ @Test @@ -323,7 +105,7 @@ public class DateTests { assertFalse(d.before(d), "Error d.before(d) = true"); } - /** + /* * Validate that a Date.before() returns true when earlier date is compared * to later date */ @@ -334,7 +116,7 @@ public class DateTests { assertTrue(d.before(d2), "Error d.before(d2) = false"); } - /** + /* * Validate that a Date.before() returns false when later date is compared * to earlier date */ @@ -345,7 +127,7 @@ public class DateTests { assertFalse(d2.before(d), "Error d2.before(d) = true"); } - /** + /* * Validate that a Date.before() returns false when date compared to another * date created from the original date */ @@ -357,7 +139,7 @@ public class DateTests { assertFalse(d2.before(d), "Error d2.before(d) = true"); } - /** + /* * Validate that a Date.compareTo returns 0 when both Date objects are the * same */ @@ -367,7 +149,7 @@ public class DateTests { assertTrue(d.compareTo(d) == 0, "Error d.compareTo(d) !=0"); } - /** + /* * Validate that a Date.compareTo returns 0 when both Date objects represent * the same date */ @@ -378,7 +160,7 @@ public class DateTests { assertTrue(d.compareTo(d2) == 0, "Error d.compareTo(d2) !=0"); } - /** + /* * Validate that a Date.compareTo returns -1 when comparing a date to a * later date */ @@ -389,7 +171,7 @@ public class DateTests { assertTrue(d.compareTo(d2) == -1, "Error d.compareTo(d2) != -1"); } - /** + /* * Validate that a Date.compareTo returns 1 when comparing a date to an * earlier date */ @@ -400,7 +182,7 @@ public class DateTests { assertTrue(d2.compareTo(d) == 1, "Error d.compareTo(d2) != 1"); } - /** + /* * Validate that a Date made from a LocalDate are equal */ @Test @@ -411,7 +193,7 @@ public class DateTests { assertTrue(d.equals(d2), "Error d != d2"); } - /** + /* * Validate that a Date LocalDate value, made from a LocalDate are equal */ @Test @@ -422,7 +204,7 @@ public class DateTests { "Error LocalDate values are not equal"); } - /** + /* * Validate an NPE occurs when a null LocalDate is passed to valueOf */ @Test(expectedExceptions = NullPointerException.class) @@ -431,7 +213,7 @@ public class DateTests { Date.valueOf(ld); } - /** + /* * Validate an UnsupportedOperationException occurs when toInstant() is * called */ @@ -441,7 +223,7 @@ public class DateTests { Instant instant = d.toInstant(); } - /** + /* * Validate that two Date objects are equal when one is created from the * toString() of the other */ @@ -452,7 +234,7 @@ public class DateTests { assertTrue(d.equals(d2) && d2.equals(d), "Error d != d2"); } - /** + /* * Validate that two Date values one created using valueOf and another via a * constructor are equal */ @@ -464,7 +246,7 @@ public class DateTests { assertTrue(d.equals(d2), "Error d != d2"); } - /** + /* * Validate that two Date values one created using getTime() of the other * are equal */ @@ -476,7 +258,7 @@ public class DateTests { assertTrue(d.equals(d2), "Error d != d2"); } - /** + /* * Validate that a Date value is equal to itself */ @Test @@ -486,7 +268,7 @@ public class DateTests { assertTrue(d.equals(d), "Error d != d"); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getHours */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -495,7 +277,7 @@ public class DateTests { d.getHours(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getMinutes */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -504,7 +286,7 @@ public class DateTests { d.getMinutes(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getSeconds */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -513,7 +295,7 @@ public class DateTests { d.getSeconds(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setHours */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -522,7 +304,7 @@ public class DateTests { d.setHours(8); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setMinutes */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -531,7 +313,7 @@ public class DateTests { d.setMinutes(0); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setSeconds */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -539,4 +321,53 @@ public class DateTests { Date d = Date.valueOf("1961-08-30"); d.setSeconds(0); } + + /* + * DataProvider used to provide Date which are not valid and are used + * to validate that an IllegalArgumentException will be thrown from the + * valueOf method + */ + @DataProvider(name = "invalidDateValues") + private Object[][] invalidDateValues() { + return new Object[][]{ + {"20009-11-01"}, + {"09-11-01"}, + {"-11-01"}, + {"2009-111-01"}, + {"2009--01"}, + {"2009-13-01"}, + {"2009-11-011"}, + {"2009-11-"}, + {"2009-11-00"}, + {"2009-11-33"}, + {"--"}, + {""}, + {null}, + {"-"}, + {"2009"}, + {"2009-01"}, + {"---"}, + {"2009-13--1"}, + {"1900-1-0"}, + {"2009-01-01 10:50:01"}, + {"1996-12-10 12:26:19.1"}, + {"10:50:01"} + }; + } + + /* + * DataProvider used to provide Dates which are valid and are used + * to validate that an IllegalArgumentException will not be thrown from the + * valueOf method and the corect value from toString() is returned + */ + @DataProvider(name = "validDateValues") + private Object[][] validDateValues() { + return new Object[][]{ + {"2009-08-30", "2009-08-30"}, + {"2009-01-8", "2009-01-08"}, + {"2009-1-01", "2009-01-01"}, + {"2009-1-1", "2009-01-01"} + + }; + } } diff --git a/jdk/test/java/sql/test/sql/TimeTests.java b/jdk/test/java/sql/test/sql/TimeTests.java index 4064c37d18e..7b99679754b 100644 --- a/jdk/test/java/sql/test/sql/TimeTests.java +++ b/jdk/test/java/sql/test/sql/TimeTests.java @@ -25,56 +25,35 @@ package test.sql; import java.sql.Time; import java.time.LocalTime; import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import util.BaseTest; -public class TimeTests { +public class TimeTests extends BaseTest { - public TimeTests() { - } - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } - - /** + /* * Validate an IllegalArgumentException is thrown for calling getYear */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test1() { + public void test01() { Time t = Time.valueOf("08:30:59"); t.getYear(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getMonth */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test2() { + public void test02() { Time t = Time.valueOf("08:30:59"); t.getMonth(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getDay */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test3() { + public void test03() { Time t = Time.valueOf("08:30:59"); t.getDay(); } @@ -83,62 +62,62 @@ public class TimeTests { * Validate an IllegalArgumentException is thrown for calling getDate */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test4() { + public void test04() { Time t = Time.valueOf("08:30:59"); t.getDate(); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setYear */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test5() { + public void test05() { Time t = Time.valueOf("08:30:59"); t.setYear(8); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setMonth */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test6() { + public void test06() { Time t = Time.valueOf("08:30:59"); t.setMonth(8); } - /** + /* * Validate an IllegalArgumentException is thrown for calling setDate */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test7() { + public void test07() { Time t = Time.valueOf("08:30:59"); t.setDate(30); } - /** + /* * Validate an IllegalArgumentException is thrown for calling getDate */ @Test(expectedExceptions = IllegalArgumentException.class) - public void test8() { + public void test08() { Time t = Time.valueOf("08:30:59"); t.getDate(); } - /** + /* * Validate that a Time made from a toLocalTime() LocalTime are equal */ @Test - public void test13() { + public void test09() { Time t = Time.valueOf("08:30:59"); Time t2 = Time.valueOf(t.toLocalTime()); assertTrue(t.equals(t2), "Error t != t2"); } - /** + /* * Validate that a Time LocalTime value, made from a LocalTime are equal */ @Test - public void test14() { + public void test10() { LocalTime lt = LocalTime.of(8, 30, 59); Time t = Time.valueOf(lt); System.out.println("lt=" + lt + ",t=" + t.toLocalTime()); @@ -146,231 +125,224 @@ public class TimeTests { "Error LocalTime values are not equal"); } - /** + /* * Validate an NPE occurs when a null LocalDate is passed to valueOf */ @Test(expectedExceptions = NullPointerException.class) - public void test15() throws Exception { + public void test11() throws Exception { LocalTime ld = null; Time.valueOf(ld); } - /** + /* * Validate an UnsupportedOperationException occurs when toInstant() is * called */ @Test(expectedExceptions = UnsupportedOperationException.class) - public void test16() throws Exception { + public void test12() throws Exception { Time t = new Time(System.currentTimeMillis()); t.toInstant(); } - /** - * Validate that a Time made from valueOf(String) returns the same String - * from Time.toString(); - */ - @Test - public void test17() { - String time = "08:30:59"; - Time t = Time.valueOf(time); - assertTrue(time.equals(t.toString()), "Error t != t2"); - } - - /** + /* * Validate that two Time objects are equal when one is created from the - * toString() of the other + * toString() of the other and that the correct value is returned from + * toString() */ - @Test - public void test18() { - Time t = Time.valueOf("08:30:59"); - Time t2 = Time.valueOf(t.toString()); - assertTrue(t.equals(t2) && t2.equals(t), "Error t != t2"); + @Test(dataProvider = "validTimeValues") + public void test13(String time, String expected) { + Time t1 = Time.valueOf(time); + Time t2 = Time.valueOf(t1.toString()); + assertTrue(t1.equals(t2) && t2.equals(t1) + && t1.toString().equals(expected), "Error t1 != t2"); } - /** + /* * Validate that two Time values one created using valueOf and another via a * constructor are equal */ @Test - public void test19() { + public void test14() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(8, 30, 59); assertTrue(t.equals(t2) && t2.equals(t), "Error t != t2"); } - /** + /* * Validate that two Time values one created using valueOf and another via a * constructor are equal */ @Test - public void test20() { + public void test15() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime()); assertTrue(t.equals(t2) && t2.equals(t), "Error t != t2"); } - /** - * Validate an IllegalArgumentException is thrown for calling valueOf with a - * null String - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test21() { - String time = null; - Time t = Time.valueOf(time); - - } - - /** + /* * Validate an IllegalArgumentException is thrown for an invalid Time string */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test22() throws Exception { - Time.valueOf("1961-08-30"); + @Test(dataProvider = "invalidTimeValues", + expectedExceptions = IllegalArgumentException.class) + public void test16(String time) throws Exception { + Time.valueOf(time); } - /** - * Validate an IllegalArgumentException is thrown for an invalid Time string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test23() throws Exception { - Time.valueOf("8:"); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Time string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test24() throws Exception { - Time.valueOf("a:b:c"); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Time string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test25() throws Exception { - Time.valueOf("08:10"); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Time string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test26() throws Exception { - Time.valueOf("08:10:10:10"); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Time string - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void test27() throws Exception { - Time.valueOf("08:10:Batman"); - } - - /** + /* * Validate that Time.after() returns false when same date is compared */ @Test - public void test28() { + public void test17() { Time t = Time.valueOf("08:30:59"); assertFalse(t.after(t), "Error t.after(t) = true"); } - /** + /* * Validate that Time.after() returns true when later date is compared to * earlier date */ @Test - public void test29() { + public void test18() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(System.currentTimeMillis()); assertTrue(t2.after(t), "Error t2.after(t) = false"); } - /** + /* * Validate that Time.after() returns false when earlier date is compared to * itself */ @Test - public void test30() { + public void test19() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime()); assertFalse(t.after(t2), "Error t.after(t2) = true"); assertFalse(t2.after(t), "Error t2.after(t) = true"); } - /** + /* * Validate that Time.before() returns false when same date is compared */ @Test - public void test31() { + public void test20() { Time t = Time.valueOf("08:30:59"); assertFalse(t.before(t), "Error t.before(t) = true"); } - /** + /* * Validate that Time.before() returns true when earlier date is compared to * later date */ @Test - public void test32() { + public void test21() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(System.currentTimeMillis()); assertTrue(t.before(t2), "Error t.before(t2) = false"); } - /** + /* * Validate that Time.before() returns false when earlier date is compared * to itself */ @Test - public void test33() { + public void test22() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime()); assertFalse(t.before(t2), "Error t.after(t2) = true"); assertFalse(t2.before(t), "Error t2.after(t) = true"); } - /** + /* * Validate that Time.compareTo returns 0 when both Date objects are the * same */ @Test - public void test34() { + public void test23() { Time t = Time.valueOf("08:30:59"); assertTrue(t.compareTo(t) == 0, "Error t.compareTo(t) !=0"); } - /** + /* * Validate thatTime.compareTo returns 0 when both Time objects are the same */ @Test - public void test35() { + public void test24() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime()); assertTrue(t.compareTo(t2) == 0, "Error t.compareTo(t2) !=0"); } - /** + /* * Validate that Time.compareTo returns 1 when comparing a later Time to an * earlier Time */ @Test - public void test36() { + public void test25() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime() + 1); assertTrue(t2.compareTo(t) == 1, "Error t2.compareTo(t) !=1"); } - /** + /* * Validate thatTime.compareTo returns 1 when comparing a later Time to an * earlier Time */ @Test - public void test37() { + public void test26() { Time t = Time.valueOf("08:30:59"); Time t2 = new Time(t.getTime() + 1); assertTrue(t.compareTo(t2) == -1, "Error t.compareTo(t2) != -1"); } + + /* + * DataProvider used to provide Time values which are not valid and are used + * to validate that an IllegalArgumentException will be thrown from the + * valueOf method + */ + @DataProvider(name = "invalidTimeValues") + private Object[][] invalidTimeValues() { + return new Object[][]{ + {"2009-11-01 10:50:01"}, + {"1961-08-30 10:50:01.1"}, + {"1961-08-30"}, + {"00:00:00."}, + {"10:50:0.1"}, + {":00:00"}, + {"00::00"}, + {"00:00:"}, + {"::"}, + {" : : "}, + {"0a:00:00"}, + {"00:bb:00"}, + {"00:01:cc"}, + {"08:10:Batman"}, + {"08:10:10:10"}, + {"08:10"}, + {"a:b:c"}, + {null}, + {"8:"} + }; + } + + /* + * DataProvider used to provide Time values which are valid and are used + * to validate that an IllegalArgumentException will not be thrown from the + * valueOf method. It also contains the expected return value from + * toString() + */ + @DataProvider(name = "validTimeValues") + private Object[][] validTimeValues() { + return new Object[][]{ + {"10:50:01", "10:50:01"}, + {"01:1:1", "01:01:01"}, + {"01:01:1", "01:01:01"}, + {"1:01:1", "01:01:01"}, + {"2:02:02", "02:02:02"}, + {"2:02:2", "02:02:02"}, + {"10:50:1", "10:50:01"}, + {"00:00:00", "00:00:00"}, + {"08:30:59", "08:30:59"}, + {"9:0:1", "09:00:01"} + }; + } } diff --git a/jdk/test/java/sql/test/sql/TimestampTests.java b/jdk/test/java/sql/test/sql/TimestampTests.java index ac87f16c013..a555b6ae0b5 100644 --- a/jdk/test/java/sql/test/sql/TimestampTests.java +++ b/jdk/test/java/sql/test/sql/TimestampTests.java @@ -29,66 +29,27 @@ import java.time.Instant; import java.time.LocalDateTime; import java.util.Calendar; import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import util.BaseTest; -public class TimestampTests { +public class TimestampTests extends BaseTest { - public TimestampTests() { - } - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } - - /** + /* * Validate an IllegalArgumentException is thrown for an invalid Timestamp */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_timestamp() throws Exception { - String testTS = "2009-11-01-01 10:50"; - Timestamp.valueOf(testTS); + @Test(dataProvider = "invalidTimestampValues", + expectedExceptions = IllegalArgumentException.class) + public void test(String ts) throws Exception { + Timestamp.valueOf(ts); } - /** - * Validate an IllegalArgumentException is thrown for an invalid Timestamp - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_year2() throws Exception { - String testTS = "aaaa-11-01-01 10:50"; - Timestamp.valueOf(testTS); - } - - /** - * Validate an IllegalArgumentException is thrown for an invalid Timestamp - */ - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalid_year3() throws Exception { - String testTS = "aaaa-11-01 10:50"; - Timestamp.valueOf(testTS); - } - - /** + /* * Validate that two Timestamp are equal when the leading 0 in seconds is * omitted */ @Test - public void test1() throws Exception { + public void test01() throws Exception { String testTS = "2009-01-01 10:50:00"; String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); @@ -96,23 +57,23 @@ public class TimestampTests { assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate two Timestamps created from the same string are equal */ @Test - public void test2() throws Exception { + public void test02() throws Exception { String testTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(testTS); assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one with leading 0s for month and day * equals same string without the leading 0s. */ @Test - public void test3() throws Exception { + public void test03() throws Exception { String testTS = "2009-1-1 10:50:0"; String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); @@ -120,12 +81,12 @@ public class TimestampTests { assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one with leading 0s for day omitted * are equal */ @Test - public void test4() throws Exception { + public void test04() throws Exception { String testTS = "2009-01-1 10:50:0"; String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); @@ -133,12 +94,12 @@ public class TimestampTests { assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one with leading 0s for month omitted * and both with leading 0s for seconds omitted are equal */ @Test - public void test5() throws Exception { + public void test05() throws Exception { String testTS = "2009-1-01 10:50:0"; String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); @@ -146,11 +107,11 @@ public class TimestampTests { assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one with leading 0s for month omitted */ @Test - public void test6() throws Exception { + public void test06() throws Exception { String testTS = "2005-1-01 10:20:50.00"; String ExpectedTS = "2005-01-01 10:20:50.00"; Timestamp ts = Timestamp.valueOf(testTS); @@ -158,52 +119,53 @@ public class TimestampTests { assertEquals(ts, ts2, "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one created using valueOf and another * via a constructor are equal */ @Test - public void test7() { + public void test07() { Timestamp ts1 = Timestamp.valueOf("1996-12-13 14:15:25.001"); Timestamp ts2 = new Timestamp(96, 11, 13, 14, 15, 25, 1000000); assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one created using valueOf and another * via a constructor are equal */ @Test - public void test8() { + public void test08() { Timestamp ts1 = Timestamp.valueOf("1996-12-13 14:15:25.001"); Timestamp ts2 = new Timestamp(ts1.getTime()); assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate that two Timestamp values one created using valueOf and another * via a constructor are equal */ @Test - public void test9() { + public void test09() { Timestamp ts1 = Timestamp.valueOf("1996-12-13 14:15:25.0"); Timestamp ts2 = new Timestamp(96, 11, 13, 14, 15, 25, 0); assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate that a Timestamp cannot be equal to null */ @Test public void test10() { Timestamp ts1 = Timestamp.valueOf("1961-08-30 14:15:25.745634"); - assertFalse(ts1.equals(null), "Error ts1 == null"); + Timestamp ts2 = null; + assertFalse(ts1.equals(ts2), "Error ts1 == null"); } - /** + /* * Validate that a Timestamp is equal to another timestamp created with the * using the same value but not equal to a Timestamp which is one day later */ @@ -218,7 +180,7 @@ public class TimestampTests { } - /** + /* * Validate that a Timestamp is equal to itself */ @Test @@ -227,19 +189,20 @@ public class TimestampTests { assertTrue(ts1.equals(ts1), "Error ts1 != ts1"); } - /** + /* * Validate that two Timestamps are equal when one is created from the * toString() of the other */ - @Test - public void test13() { - Timestamp ts1 = Timestamp.valueOf("1996-12-10 12:26:19.12"); + @Test(dataProvider = "validTimestampValues") + public void test13(String ts, String expectedTS) { + Timestamp ts1 = Timestamp.valueOf(ts); Timestamp ts2 = Timestamp.valueOf(ts1.toString()); - assertTrue(ts1.equals(ts2) && ts2.equals(ts1), "Error ts1 != ts2"); + assertTrue(ts1.equals(ts2) && ts2.equals(ts1) + && ts1.toString().equals(expectedTS), "Error ts1 != ts2"); } // Before Tests - /** + /* * Validate that Timestamp ts1 is before Timestamp ts2 */ @Test @@ -249,7 +212,7 @@ public class TimestampTests { assertTrue(ts1.before(ts2), "Error ts1 not before ts2"); } - /** + /* * Validate that Timestamp ts1 is before Timestamp ts2 */ @Test @@ -259,7 +222,7 @@ public class TimestampTests { assertTrue(ts1.before(ts2), "Error ts1 not before ts2"); } - /** + /* * Validate that Timestamp ts1 is before Timestamp ts2 */ @Test @@ -289,7 +252,7 @@ public class TimestampTests { assertFalse(ts1.before(ts1), "Error ts1 before ts1!"); } - /** + /* * Create 3 Timestamps and make sure the 1st is before the other two * Timestamps which are each greater than the one before it */ @@ -302,7 +265,7 @@ public class TimestampTests { assertTrue(ts1.before(ts2) && ts2.before(ts3) && ts1.before(ts3)); } - /** + /* * Validate that Timestamp ts1 is not after Timestamp ts2 */ @Test @@ -313,7 +276,7 @@ public class TimestampTests { } - /** + /* * Validate that Timestamp ts1 is after Timestamp ts2 */ @Test @@ -323,7 +286,7 @@ public class TimestampTests { assertTrue(ts1.after(ts2), "Error ts1 not after ts2"); } - /** + /* * Validate that a NullPointerException is thrown if a null is passed to the * after method */ @@ -333,7 +296,7 @@ public class TimestampTests { ts1.after(null); } - /** + /* * Validate that a Timestamp cannot be after itself */ @Test @@ -341,9 +304,10 @@ public class TimestampTests { Timestamp ts1 = Timestamp.valueOf("1999-11-10 12:26:19.3456543"); assertFalse(ts1.after(ts1), "Error ts1 is after itself"); } - /** - * Validate that a Timestamp after() works correctly with Timestamp - * created using milliseconds + + /* + * Validate that a Timestamp after() works correctly with Timestamp created + * using milliseconds */ @Test public void test24() { @@ -354,7 +318,7 @@ public class TimestampTests { assertTrue(ts1.after(ts2) && ts2.after(ts3) && ts1.after(ts3)); } - /** + /* * Validate compareTo returns 0 for Timestamps that are the same */ @Test @@ -364,7 +328,7 @@ public class TimestampTests { assertTrue(ts1.compareTo(ts2) == 0, "Error ts1 != ts2"); } - /** + /* * Validate compareTo returns -1 for when the 1st Timestamp is earlier than * the 2nd Timestamp */ @@ -376,7 +340,7 @@ public class TimestampTests { assertTrue(ts2.compareTo(ts1) == 1, "Error ts1 is not before ts2"); } - /** + /* * Validate compareTo returns 1 for when the 1st Timestamp is later than the * 2nd Timestamp */ @@ -388,7 +352,7 @@ public class TimestampTests { assertTrue(ts2.compareTo(ts1) == -1, "Error ts1 not after ts2"); } - /** + /* * Validate compareTo returns 0 for Timestamps that are the same */ @Test @@ -398,7 +362,7 @@ public class TimestampTests { assertTrue(ts1.compareTo(ts2) == 0, "Error ts1 != ts2"); } - /** + /* * Validate compareTo returns 0 for Timestamps that are the same */ @Test @@ -408,7 +372,7 @@ public class TimestampTests { assertFalse(ts1.equals(d), "Error ts1 == d"); } - /** + /* * Validate compareTo returns 0 for Timestamps that are the same */ @Test @@ -418,7 +382,7 @@ public class TimestampTests { assertTrue(ts1.equals(d), "Error ts1 != d"); } - /** + /* * Validate equals returns false when a Date object is passed to equals */ @Test @@ -428,7 +392,7 @@ public class TimestampTests { assertFalse(ts1.equals(d), "Error ts1 != d"); } - /** + /* * Validate equals returns false when a Date object is passed to equals */ @Test @@ -438,7 +402,7 @@ public class TimestampTests { assertFalse(ts1.equals(d), "Error ts1 != d"); } - /** + /* * Validate equals returns false when a Time object is passed to equals */ @Test @@ -448,7 +412,7 @@ public class TimestampTests { assertFalse(ts1.equals(t1), "Error ts1 == t1"); } - /** + /* * Validate equals returns false when a String object is passed to equals */ @Test @@ -457,7 +421,7 @@ public class TimestampTests { assertFalse(ts1.equals("1966-08-30 08:08:08"), "Error ts1 == a String"); } - /** + /* * Validate getTime() returns the same value from 2 timeStamps created by */ @Test @@ -469,7 +433,7 @@ public class TimestampTests { assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate getTime() returns the same value from 2 timeStamps when * setTime() is used to specify the same value for both Timestamps */ @@ -483,7 +447,7 @@ public class TimestampTests { assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate an IllegalArgumentException is thrown for an invalid nanos value */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -493,7 +457,7 @@ public class TimestampTests { } - /** + /* * Validate an IllegalArgumentException is thrown for an invalid nanos value */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -501,10 +465,9 @@ public class TimestampTests { int nanos = 999999999; Timestamp ts1 = Timestamp.valueOf("1961-08-30 00:00:00"); ts1.setNanos(nanos + 1); - } - /** + /* * Validate you can set nanos to 999999999 */ @Test @@ -513,10 +476,9 @@ public class TimestampTests { Timestamp ts1 = Timestamp.valueOf("1961-08-30 00:00:00"); ts1.setNanos(nanos); assertTrue(ts1.getNanos() == nanos, "Error Invalid Nanos value"); - } - /** + /* * Validate you can set nanos to 0 */ @Test @@ -525,10 +487,9 @@ public class TimestampTests { Timestamp ts1 = Timestamp.valueOf("1961-08-30 00:00:00"); ts1.setNanos(nanos); assertTrue(ts1.getNanos() == nanos, "Error Invalid Nanos value"); - } - /** + /* * Validate that a Timestamp made from a LocalDateTime are equal */ @Test @@ -539,7 +500,7 @@ public class TimestampTests { assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate that a Timestamp LocalDateTime value, made from a LocalDateTime * are equal */ @@ -551,7 +512,7 @@ public class TimestampTests { "Error LocalDateTime values are not equal"); } - /** + /* * Validate an NPE occurs when a null LocalDateTime is passed to valueOF */ @Test(expectedExceptions = NullPointerException.class) @@ -560,7 +521,7 @@ public class TimestampTests { Timestamp.valueOf(ldt); } - /** + /* * Validate that a Timestamp made from a Instant are equal */ @Test @@ -571,7 +532,7 @@ public class TimestampTests { assertTrue(ts1.equals(ts2), "Error ts1 != ts2"); } - /** + /* * Validate that a Timestamp made from a Instant are equal */ @Test @@ -582,7 +543,7 @@ public class TimestampTests { "Error Instant values do not match"); } - /** + /* * Validate an NPE occurs when a null instant is passed to from */ @Test(expectedExceptions = NullPointerException.class) @@ -592,7 +553,7 @@ public class TimestampTests { } // Added SQE tests - /** + /* * Create a Timestamp and a 2nd Timestamp that is 1 month earlier and * validate that it is not before or after the original Timestamp */ @@ -607,7 +568,7 @@ public class TimestampTests { assertFalse(ts1.before(ts2) || ts2.after(ts1)); } - /** + /* * Create two Timestamps and validate that compareTo returns 1 to indicate * the 1st Timestamp is greater than the 2nd Timestamp */ @@ -622,7 +583,7 @@ public class TimestampTests { assertTrue(ts1.compareTo(ts2) == 1); } - /** + /* * Create two Timestamps and validate that the 1st Timestamp is not equal to * the 2nd Timestamp but equal to itself */ @@ -637,4 +598,114 @@ public class TimestampTests { assertTrue(!ts1.equals(ts2) && ts1.equals(ts1)); } + /* + * Validate that two Timestamps are equal when one is created from the + * toString() of the other + */ + @Test(dataProvider = "validateNanos") + public void test51(String ts, int nanos) { + Timestamp ts1 = Timestamp.valueOf(ts); + Timestamp ts2 = Timestamp.valueOf(ts1.toString()); + assertTrue(ts1.getNanos() == nanos && ts1.equals(ts2), + "Error with Nanos"); + } + + /* + * DataProvider used to provide Timestamps which are not valid and are used + * to validate that an IllegalArgumentException will be thrown from the + * valueOf method + */ + @DataProvider(name = "invalidTimestampValues") + private Object[][] invalidTimestampValues() { + return new Object[][]{ + {"2009-11-01-01 10:50:01"}, + {"aaaa-11-01-01 10:50"}, + {"aaaa-11-01 10:50"}, + {"1961--30 00:00:00"}, + {"--30 00:00:00"}, + {"-- 00:00:00"}, + {"1961-1- 00:00:00"}, + {"2009-11-01"}, + {"10:50:01"}, + {"1961-a-30 00:00:00"}, + {"1961-01-bb 00:00:00"}, + {"1961-08-30 00:00:00."}, + {"1961-08-30 :00:00"}, + {"1961-08-30 00::00"}, + {"1961-08-30 00:00:"}, + {"1961-08-30 ::"}, + {"1961-08-30 0a:00:00"}, + {"1961-08-30 00:bb:00"}, + {"1961-08-30 00:01:cc"}, + {"1961-08-30 00:00:00.01a"}, + {"1961-08-30 00:00:00.a"}, + {"1996-12-10 12:26:19.1234567890"}, + {null} + }; + } + + /* + * DataProvider used to provide Timestamps which are valid and are used + * to validate that an IllegalArgumentException will not be thrown from the + * valueOf method and the corect value from toString() is returned + */ + @DataProvider(name = "validTimestampValues") + private Object[][] validTimestampValues() { + return new Object[][]{ + {"1961-08-30 00:00:00", "1961-08-30 00:00:00.0"}, + {"1961-08-30 11:22:33", "1961-08-30 11:22:33.0"}, + {"1961-8-30 00:00:00", "1961-08-30 00:00:00.0"}, + {"1966-08-1 00:00:00", "1966-08-01 00:00:00.0"}, + {"1996-12-10 12:26:19.1", "1996-12-10 12:26:19.1"}, + {"1996-12-10 12:26:19.12", "1996-12-10 12:26:19.12"}, + {"1996-12-10 12:26:19.123", "1996-12-10 12:26:19.123"}, + {"1996-12-10 12:26:19.1234", "1996-12-10 12:26:19.1234"}, + {"1996-12-10 12:26:19.12345", "1996-12-10 12:26:19.12345"}, + {"1996-12-10 12:26:19.123456", "1996-12-10 12:26:19.123456"}, + {"1996-12-10 12:26:19.1234567", "1996-12-10 12:26:19.1234567"}, + {"1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"}, + {"1996-12-10 12:26:19.123456789", "1996-12-10 12:26:19.123456789"}, + {"1996-12-10 12:26:19.000000001", "1996-12-10 12:26:19.000000001"}, + {"1996-12-10 12:26:19.000000012", "1996-12-10 12:26:19.000000012"}, + {"1996-12-10 12:26:19.000000123", "1996-12-10 12:26:19.000000123"}, + {"1996-12-10 12:26:19.000001234", "1996-12-10 12:26:19.000001234"}, + {"1996-12-10 12:26:19.000012345", "1996-12-10 12:26:19.000012345"}, + {"1996-12-10 12:26:19.000123456", "1996-12-10 12:26:19.000123456"}, + {"1996-12-10 12:26:19.001234567", "1996-12-10 12:26:19.001234567"}, + {"1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"}, + {"1996-12-10 12:26:19.0", "1996-12-10 12:26:19.0"}, + {"1996-12-10 12:26:19.01230", "1996-12-10 12:26:19.0123"} + }; + } + + /* + * DataProvider used to provide Timestamp and Nanos values in order to + * validate that the correct Nanos value is generated from the specified + * Timestamp + */ + @DataProvider(name = "validateNanos") + private Object[][] validateNanos() { + return new Object[][]{ + {"1961-08-30 00:00:00", 0}, + {"1996-12-10 12:26:19.1", 100000000}, + {"1996-12-10 12:26:19.12", 120000000}, + {"1996-12-10 12:26:19.123", 123000000}, + {"1996-12-10 12:26:19.1234", 123400000}, + {"1996-12-10 12:26:19.12345", 123450000}, + {"1996-12-10 12:26:19.123456", 123456000}, + {"1996-12-10 12:26:19.1234567", 123456700}, + {"1996-12-10 12:26:19.12345678", 123456780}, + {"1996-12-10 12:26:19.123456789", 123456789}, + {"1996-12-10 12:26:19.000000001", 1}, + {"1996-12-10 12:26:19.000000012", 12}, + {"1996-12-10 12:26:19.000000123", 123}, + {"1996-12-10 12:26:19.000001234", 1234}, + {"1996-12-10 12:26:19.000012345", 12345}, + {"1996-12-10 12:26:19.000123456", 123456}, + {"1996-12-10 12:26:19.001234567", 1234567}, + {"1996-12-10 12:26:19.012345678", 12345678}, + {"1996-12-10 12:26:19.0", 0}, + {"1996-12-10 12:26:19.01230", 12300000} + }; + } } diff --git a/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java index 4021a147c9c..28ccbfe0516 100644 --- a/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java +++ b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java @@ -138,7 +138,7 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { {"Asia/Taipei", "China Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, {"America/Chicago", "CST", none, Locale.ENGLISH, TextStyle.SHORT}, {"Asia/Taipei", "CST", preferred, Locale.ENGLISH, TextStyle.SHORT}, - {"Australia/South", "CST", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, + {"Australia/South", "ACST", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, {"America/Chicago", "CDT", none, Locale.ENGLISH, TextStyle.SHORT}, {"Asia/Shanghai", "CDT", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, }; diff --git a/jdk/test/javax/management/loading/MLetInternalsTest.java b/jdk/test/javax/management/loading/MLetInternalsTest.java new file mode 100644 index 00000000000..a359697b0b3 --- /dev/null +++ b/jdk/test/javax/management/loading/MLetInternalsTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, 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.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import javax.management.loading.MLet; +import org.testng.annotations.Test; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeTest; + +import static org.testng.Assert.*; + +/* + * @test + * @bug 8058089 + * @summary Tests various internal functions provided by MLet for correctness + * @author Jaroslav Bachorik + * @run testng MLetInternalsTest + */ +public class MLetInternalsTest { + private final static String CONSTRUCT_PARAMETER = "constructParameter"; + + private final static Map testedMethods = new HashMap<>(); + + @BeforeClass + public static void setupClass() { + testedMethods.clear(); + try { + Method m = MLet.class.getDeclaredMethod( + CONSTRUCT_PARAMETER, + String.class, String.class + ); + m.setAccessible(true); + + testedMethods.put(CONSTRUCT_PARAMETER, m); + } catch (Exception ex) { + throw new Error(ex); + } + } + + private MLet mlet; + + @BeforeTest + public void setupTest() { + mlet = new MLet(); + } + + @Test + public void testConstructParameter() throws Exception { + assertEquals(constructParameter("120", "int"), 120); + assertEquals(constructParameter("120", "java.lang.Integer"), Integer.valueOf(120)); + assertEquals(constructParameter("120", "long"), 120L); + assertEquals(constructParameter("120", "java.lang.Long"), Long.valueOf(120)); + assertEquals(constructParameter("120.0", "float"), 120.0f); + assertEquals(constructParameter("120.0", "java.lang.Float"), Float.valueOf(120.0f)); + assertEquals(constructParameter("120.0", "double"), 120.0d); + assertEquals(constructParameter("120", "java.lang.Double"), Double.valueOf(120d)); + assertEquals(constructParameter("120", "java.lang.String"), "120"); + assertEquals(constructParameter("120", "byte"), (byte)120); + assertEquals(constructParameter("120", "java.lang.Byte"), (byte)120); + assertEquals(constructParameter("120", "short"), (short)120); + assertEquals(constructParameter("120", "java.lang.Short"), (short)120); + assertEquals(constructParameter("true", "boolean"), true); + assertEquals(constructParameter("true", "java.lang.Boolean"), Boolean.valueOf(true)); + } + + private Object constructParameter(String param, String type) throws Exception { + return testedMethods.get(CONSTRUCT_PARAMETER).invoke(mlet, param, type); + } +} diff --git a/jdk/test/sun/invoke/util/ValueConversionsTest.java b/jdk/test/sun/invoke/util/ValueConversionsTest.java index 726e90d9dea..483afb7625c 100644 --- a/jdk/test/sun/invoke/util/ValueConversionsTest.java +++ b/jdk/test/sun/invoke/util/ValueConversionsTest.java @@ -25,11 +25,11 @@ package test.sun.invoke.util; import sun.invoke.util.ValueConversions; import sun.invoke.util.Wrapper; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.MethodHandle; import java.io.Serializable; import java.util.Arrays; -import java.util.Collections; import org.junit.Test; import static org.junit.Assert.*; @@ -37,24 +37,13 @@ import static org.junit.Assert.*; * @summary unit tests for value-type conversion utilities * @compile -XDignore.symbol.file ValueConversionsTest.java * @run junit/othervm test.sun.invoke.util.ValueConversionsTest - * @run junit/othervm - * -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.START_ARITY=250 - * test.sun.invoke.util.ValueConversionsTest */ -// This might take a while and burn lots of metadata: -// @run junit/othervm -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.EXHAUSTIVE=true test.sun.invoke.util.ValueConversionsTest - /** * * @author jrose */ public class ValueConversionsTest { - private static final Class CLASS = ValueConversionsTest.class; - private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); - private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0); - private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE"); - @Test public void testUnbox() throws Throwable { testUnbox(false); @@ -66,9 +55,7 @@ public class ValueConversionsTest { } private void testUnbox(boolean doCast) throws Throwable { - //System.out.println("unbox"); for (Wrapper dst : Wrapper.values()) { - //System.out.println(dst); for (Wrapper src : Wrapper.values()) { testUnbox(doCast, dst, src); } @@ -78,6 +65,7 @@ public class ValueConversionsTest { private void testUnbox(boolean doCast, Wrapper dst, Wrapper src) throws Throwable { boolean expectThrow = !doCast && !dst.isConvertibleFrom(src); if (dst == Wrapper.OBJECT || src == Wrapper.OBJECT) return; // must have prims + if (dst == Wrapper.VOID || src == Wrapper.VOID ) return; // must have values if (dst == Wrapper.OBJECT) expectThrow = false; // everything (even VOID==null here) converts to OBJECT try { @@ -91,9 +79,9 @@ public class ValueConversionsTest { } MethodHandle unboxer; if (doCast) - unboxer = ValueConversions.unboxCast(dst.primitiveType()); + unboxer = ValueConversions.unboxCast(dst); else - unboxer = ValueConversions.unbox(dst.primitiveType()); + unboxer = ValueConversions.unboxWiden(dst); Object expResult = (box == null) ? dst.zero() : dst.wrap(box); Object result = null; switch (dst) { @@ -104,9 +92,7 @@ public class ValueConversionsTest { case CHAR: result = (char) unboxer.invokeExact(box); break; case BYTE: result = (byte) unboxer.invokeExact(box); break; case SHORT: result = (short) unboxer.invokeExact(box); break; - case OBJECT: result = (Object) unboxer.invokeExact(box); break; case BOOLEAN: result = (boolean) unboxer.invokeExact(box); break; - case VOID: result = null; unboxer.invokeExact(box); break; } if (expectThrow) { expResult = "(need an exception)"; @@ -123,25 +109,23 @@ public class ValueConversionsTest { @Test public void testBox() throws Throwable { - //System.out.println("box"); for (Wrapper w : Wrapper.values()) { - if (w == Wrapper.VOID) continue; // skip this; no unboxed form - //System.out.println(w); + if (w == Wrapper.VOID) continue; // skip this; no unboxed form + if (w == Wrapper.OBJECT) continue; // skip this; already unboxed for (int n = -5; n < 10; n++) { Object box = w.wrap(n); - MethodHandle boxer = ValueConversions.box(w.primitiveType()); + MethodHandle boxer = ValueConversions.boxExact(w); Object expResult = box; Object result = null; switch (w) { - case INT: result = boxer.invokeExact(/*int*/n); break; - case LONG: result = boxer.invokeExact((long)n); break; - case FLOAT: result = boxer.invokeExact((float)n); break; - case DOUBLE: result = boxer.invokeExact((double)n); break; - case CHAR: result = boxer.invokeExact((char)n); break; - case BYTE: result = boxer.invokeExact((byte)n); break; - case SHORT: result = boxer.invokeExact((short)n); break; - case OBJECT: result = boxer.invokeExact((Object)n); break; - case BOOLEAN: result = boxer.invokeExact((n & 1) != 0); break; + case INT: result = (Integer) boxer.invokeExact(/*int*/n); break; + case LONG: result = (Long) boxer.invokeExact((long)n); break; + case FLOAT: result = (Float) boxer.invokeExact((float)n); break; + case DOUBLE: result = (Double) boxer.invokeExact((double)n); break; + case CHAR: result = (Character) boxer.invokeExact((char)n); break; + case BYTE: result = (Byte) boxer.invokeExact((byte)n); break; + case SHORT: result = (Short) boxer.invokeExact((short)n); break; + case BOOLEAN: result = (Boolean) boxer.invokeExact((n & 1) != 0); break; } assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box), expResult, result); @@ -151,16 +135,14 @@ public class ValueConversionsTest { @Test public void testCast() throws Throwable { - //System.out.println("cast"); Class[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class }; Object[] objects = { new Object(), Boolean.FALSE, "hello", (Long)12L, (Integer)6 }; for (Class dst : types) { - MethodHandle caster = ValueConversions.cast(dst); - assertEquals(caster.type(), ValueConversions.identity().type()); + MethodHandle caster = ValueConversions.cast().bindTo(dst); + assertEquals(caster.type(), MethodHandles.identity(Object.class).type()); for (Object obj : objects) { Class src = obj.getClass(); boolean canCast = dst.isAssignableFrom(src); - //System.out.println("obj="+obj+" <: dst="+dst+(canCast ? " (OK)" : " (will fail)")); try { Object result = caster.invokeExact(obj); if (canCast) @@ -175,26 +157,13 @@ public class ValueConversionsTest { } } - @Test - public void testIdentity() throws Throwable { - //System.out.println("identity"); - MethodHandle id = ValueConversions.identity(); - Object expResult = "foo"; - Object result = id.invokeExact(expResult); - // compiler bug: ValueConversions.identity().invokeExact("bar"); - assertEquals(expResult, result); - } - @Test public void testConvert() throws Throwable { - //System.out.println("convert"); for (long tval = 0, ctr = 0;;) { if (++ctr > 99999) throw new AssertionError("too many test values"); - // next test value: - //System.out.println(Long.toHexString(tval)); // prints 3776 test patterns + // prints 3776 test patterns (3776 = 8*59*8) tval = nextTestValue(tval); if (tval == 0) { - //System.out.println("test value count = "+ctr); // 3776 = 8*59*8 break; // repeat } } @@ -205,15 +174,12 @@ public class ValueConversionsTest { } } static void testConvert(Wrapper src, Wrapper dst, long tval) throws Throwable { - //System.out.println(src+" => "+dst); + if (dst == Wrapper.OBJECT || src == Wrapper.OBJECT) return; // must have prims + if (dst == Wrapper.VOID || src == Wrapper.VOID ) return; // must have values boolean testSingleCase = (tval != 0); final long tvalInit = tval; MethodHandle conv = ValueConversions.convertPrimitive(src, dst); - MethodType convType; - if (src == Wrapper.VOID) - convType = MethodType.methodType(dst.primitiveType() /* , void */); - else - convType = MethodType.methodType(dst.primitiveType(), src.primitiveType()); + MethodType convType = MethodType.methodType(dst.primitiveType(), src.primitiveType()); assertEquals(convType, conv.type()); MethodHandle converter = conv.asType(conv.type().changeReturnType(Object.class)); for (;;) { @@ -229,9 +195,7 @@ public class ValueConversionsTest { case CHAR: result = converter.invokeExact((char)n); break; case BYTE: result = converter.invokeExact((byte)n); break; case SHORT: result = converter.invokeExact((short)n); break; - case OBJECT: result = converter.invokeExact((Object)n); break; case BOOLEAN: result = converter.invokeExact((n & 1) != 0); break; - case VOID: result = converter.invokeExact(); break; default: throw new AssertionError(); } assertEquals("(src,dst,n,testValue)="+Arrays.asList(src,dst,"0x"+Long.toHexString(n),testValue), @@ -269,169 +233,4 @@ public class ValueConversionsTest { } return tweakSign(ux); } - - @Test - public void testVarargsArray() throws Throwable { - //System.out.println("varargsArray"); - final int MIN = START_ARITY; - final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added - for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) { - MethodHandle target = ValueConversions.varargsArray(nargs); - Object[] args = new Object[nargs]; - for (int i = 0; i < nargs; i++) - args[i] = "#"+i; - Object res = target.invokeWithArguments(args); - assertArrayEquals(args, (Object[])res); - } - } - - @Test - public void testVarargsReferenceArray() throws Throwable { - //System.out.println("varargsReferenceArray"); - testTypedVarargsArray(Object[].class); - testTypedVarargsArray(String[].class); - testTypedVarargsArray(Number[].class); - } - - @Test - public void testVarargsPrimitiveArray() throws Throwable { - //System.out.println("varargsPrimitiveArray"); - testTypedVarargsArray(int[].class); - testTypedVarargsArray(long[].class); - testTypedVarargsArray(byte[].class); - testTypedVarargsArray(boolean[].class); - testTypedVarargsArray(short[].class); - testTypedVarargsArray(char[].class); - testTypedVarargsArray(float[].class); - testTypedVarargsArray(double[].class); - } - - private static int nextArgCount(int nargs, int density, int MAX) { - if (EXHAUSTIVE) return nargs + 1; - if (nargs >= MAX) return Integer.MAX_VALUE; - int BOT = 20, TOP = MAX-5; - if (density < 10) { BOT = 10; MAX = TOP-2; } - if (nargs <= BOT || nargs >= TOP) { - ++nargs; - } else { - int bump = Math.max(1, 100 / density); - nargs += bump; - if (nargs > TOP) nargs = TOP; - } - return nargs; - } - - private void testTypedVarargsArray(Class arrayType) throws Throwable { - //System.out.println(arrayType.getSimpleName()); - Class elemType = arrayType.getComponentType(); - int MIN = START_ARITY; - int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added - int density = 3; - if (elemType == int.class || elemType == long.class) density = 7; - if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; } - for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) { - Object[] args = makeTestArray(elemType, nargs); - MethodHandle varargsArray = ValueConversions.varargsArray(arrayType, nargs); - MethodType vaType = varargsArray.type(); - assertEquals(arrayType, vaType.returnType()); - if (nargs != 0) { - assertEquals(elemType, vaType.parameterType(0)); - assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1)); - } - assertEquals(MethodType.methodType(arrayType, Collections.>nCopies(nargs, elemType)), - vaType); - Object res = varargsArray.invokeWithArguments(args); - String resString = toArrayString(res); - assertEquals(Arrays.toString(args), resString); - - MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs); - MethodType stype = spreader.type(); - assert(stype == MethodType.methodType(arrayType, arrayType)); - if (nargs <= 5) { - // invoke target as a spreader also: - @SuppressWarnings("cast") - Object res2 = spreader.invokeWithArguments((Object)res); - String res2String = toArrayString(res2); - assertEquals(Arrays.toString(args), res2String); - // invoke the spreader on a generic Object[] array; check for error - try { - Object res3 = spreader.invokeWithArguments((Object)args); - String res3String = toArrayString(res3); - assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); - assertEquals(Arrays.toString(args), res3String); - } catch (ClassCastException ex) { - assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); - } - } - if (nargs == 0) { - // invoke spreader on null arglist - Object res3 = spreader.invokeWithArguments((Object)null); - String res3String = toArrayString(res3); - assertEquals(Arrays.toString(args), res3String); - } - } - } - - private static Object[] makeTestArray(Class elemType, int len) { - Wrapper elem = null; - if (elemType.isPrimitive()) - elem = Wrapper.forPrimitiveType(elemType); - else if (Wrapper.isWrapperType(elemType)) - elem = Wrapper.forWrapperType(elemType); - Object[] args = new Object[len]; - for (int i = 0; i < len; i++) { - Object arg = i * 100; - if (elem == null) { - if (elemType == String.class) - arg = "#"+arg; - arg = elemType.cast(arg); // just to make sure - } else { - switch (elem) { - case BOOLEAN: arg = (i % 3 == 0); break; - case CHAR: arg = 'a' + i; break; - case LONG: arg = (long)i * 1000_000_000; break; - case FLOAT: arg = (float)i / 100; break; - case DOUBLE: arg = (double)i / 1000_000; break; - } - arg = elem.cast(arg, elemType); - } - args[i] = arg; - } - //System.out.println(elemType.getName()+Arrays.toString(args)); - return args; - } - - private static String toArrayString(Object a) { - if (a == null) return "null"; - Class elemType = a.getClass().getComponentType(); - if (elemType == null) return a.toString(); - if (elemType.isPrimitive()) { - switch (Wrapper.forPrimitiveType(elemType)) { - case INT: return Arrays.toString((int[])a); - case BYTE: return Arrays.toString((byte[])a); - case BOOLEAN: return Arrays.toString((boolean[])a); - case SHORT: return Arrays.toString((short[])a); - case CHAR: return Arrays.toString((char[])a); - case FLOAT: return Arrays.toString((float[])a); - case LONG: return Arrays.toString((long[])a); - case DOUBLE: return Arrays.toString((double[])a); - } - } - return Arrays.toString((Object[])a); - } - - @Test - public void testVarargsList() throws Throwable { - //System.out.println("varargsList"); - final int MIN = START_ARITY; - final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added - for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 7, MAX)) { - MethodHandle target = ValueConversions.varargsList(nargs); - Object[] args = new Object[nargs]; - for (int i = 0; i < nargs; i++) - args[i] = "#"+i; - Object res = target.invokeWithArguments(args); - assertEquals(Arrays.asList(args), res); - } - } } diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java index 98009708869..6d142174f6b 100644 --- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java @@ -115,8 +115,7 @@ public class JMXStartStopTest { throws Exception { Set names = server.queryNames(pattern,query); - for (Iterator i = names.iterator(); i.hasNext(); ) { - ObjectName name = (ObjectName)i.next(); + for (ObjectName name : names) { MBeanInfo info = server.getMBeanInfo(name); dbg_print("Got MBean: " + name); diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION index c735be51ca1..5e925ada8df 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION @@ -1,24 +1,24 @@ # # 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. # -tzdata2014c +tzdata2014g diff --git a/jdk/test/sun/util/calendar/zi/tzdata/africa b/jdk/test/sun/util/calendar/zi/tzdata/africa index 6f1a1471e0c..aa91f365ce1 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/africa +++ b/jdk/test/sun/util/calendar/zi/tzdata/africa @@ -21,13 +21,13 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -#

     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
     # From Paul Eggert (2013-02-21):
     #
    @@ -49,8 +49,8 @@
     # I found in the UCLA library.
     #
     # For data circa 1899, a common source is:
    -# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
    -# .
    +# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
    +# http://www.jstor.org/stable/1774359
     #
     # A reliable and entertaining source about time zones is
     # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    @@ -58,13 +58,13 @@
     # Previous editions of this database used WAT, CAT, SAT, and EAT
     # for +0:00 through +3:00, respectively,
     # but Mark R V Murray reports that
    -# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
    -# `CAT' is commonly used for +2:00 in countries north of South Africa, and
    -# `WAT' is probably the best name for +1:00, as the common phrase for
    -# the area that includes Nigeria is ``West Africa''.
    -# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
    +# 'SAST' is the official abbreviation for +2:00 in the country of South Africa,
    +# 'CAT' is commonly used for +2:00 in countries north of South Africa, and
    +# 'WAT' is probably the best name for +1:00, as the common phrase for
    +# the area that includes Nigeria is "West Africa".
    +# He has heard of "Western Sahara Time" for +0:00 but can find no reference.
     #
    -# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
    +# To make things confusing, 'WAT' seems to have been used for -1:00 long ago;
     # I'd guess that this was because people needed _some_ name for -1:00,
     # and at the time, far west Africa was the only major land area in -1:00.
     # This usage is now obsolete, as the last use of -1:00 on the African
    @@ -77,7 +77,7 @@
     #	 2:00	SAST	South Africa Standard Time
     # and Murray suggests the following abbreviation:
     #	 1:00	WAT	West Africa Time
    -# I realize that this leads to `WAT' being used for both -1:00 and 1:00
    +# I realize that this leads to 'WAT' being used for both -1:00 and 1:00
     # for times before 1976, but this is the best I can think of
     # until we get more information.
     #
    @@ -117,9 +117,9 @@ Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
     # Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
     # more precise 0:09:21.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
    -			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    -			0:00	Algeria	WE%sT	1940 Feb 25 2:00
    +Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15  0:01
    +			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
    +			0:00	Algeria	WE%sT	1940 Feb 25  2:00
     			1:00	Algeria	CE%sT	1946 Oct  7
     			0:00	-	WET	1956 Jan 29
     			1:00	-	CET	1963 Apr 14
    @@ -129,18 +129,8 @@ Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
     			1:00	-	CET
     
     # Angola
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Luanda	0:52:56	-	LMT	1892
    -			0:52:04	-	AOT	1911 May 26 # Angola Time
    -			1:00	-	WAT
    -
     # Benin
    -# Whitman says they switched to 1:00 in 1946, not 1934;
    -# go with Shanks & Pottenger.
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
    -			0:00	-	GMT	1934 Feb 26
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
     # Botswana
     # From Paul Eggert (2013-02-21):
    @@ -149,14 +139,12 @@ Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Gaborone	1:43:40 -	LMT	1885
     			1:30	-	SAST	1903 Mar
    -			2:00	-	CAT	1943 Sep 19 2:00
    -			2:00	1:00	CAST	1944 Mar 19 2:00
    +			2:00	-	CAT	1943 Sep 19  2:00
    +			2:00	1:00	CAST	1944 Mar 19  2:00
     			2:00	-	CAT
     
     # Burkina Faso
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Ouagadougou	-0:06:04 -	LMT	1912
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Burundi
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -164,52 +152,60 @@ Zone Africa/Bujumbura	1:57:28	-	LMT	1890
     			2:00	-	CAT
     
     # Cameroon
    -# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Douala	0:38:48	-	LMT	1912
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
     # Cape Verde
    +#
    +# Shanks gives 1907 for the transition to CVT.
    +# Perhaps the 1911-05-26 Portuguese decree
    +# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
    +# merely made it official?
    +#
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907			# Praia
    +Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907        # Praia
     			-2:00	-	CVT	1942 Sep
     			-2:00	1:00	CVST	1945 Oct 15
    -			-2:00	-	CVT	1975 Nov 25 2:00
    +			-2:00	-	CVT	1975 Nov 25  2:00
     			-1:00	-	CVT
     
     # Central African Republic
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Bangui	1:14:20	-	LMT	1912
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
     # Chad
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Ndjamena	1:00:12 -	LMT	1912
    +Zone	Africa/Ndjamena	1:00:12 -	LMT	1912        # N'Djamena
     			1:00	-	WAT	1979 Oct 14
     			1:00	1:00	WAST	1980 Mar  8
     			1:00	-	WAT
     
     # Comoros
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul   # Moroni, Gran Comoro
    +Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul # Moroni, Gran Comoro
     			3:00	-	EAT
     
    -# Democratic Republic of Congo
    +# Democratic Republic of the Congo
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Kinshasa	1:01:12 -	LMT	1897 Nov 9
    -			1:00	-	WAT
     Zone Africa/Lubumbashi	1:49:52 -	LMT	1897 Nov 9
     			2:00	-	CAT
    +# The above is for the eastern part; see Africa/Lagos for the western part.
     
     # Republic of the Congo
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Brazzaville	1:01:08 -	LMT	1912
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
    -# Cote D'Ivoire
    +# Côte d'Ivoire / Ivory Coast
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Abidjan	-0:16:08 -	LMT	1912
     			 0:00	-	GMT
    +Link Africa/Abidjan Africa/Bamako	# Mali
    +Link Africa/Abidjan Africa/Banjul	# Gambia
    +Link Africa/Abidjan Africa/Conakry	# Guinea
    +Link Africa/Abidjan Africa/Dakar	# Senegal
    +Link Africa/Abidjan Africa/Freetown	# Sierra Leone
    +Link Africa/Abidjan Africa/Lome		# Togo
    +Link Africa/Abidjan Africa/Nouakchott	# Mauritania
    +Link Africa/Abidjan Africa/Ouagadougou	# Burkina Faso
    +Link Africa/Abidjan Africa/Sao_Tome	# São Tomé and Príncipe
    +Link Africa/Abidjan Atlantic/St_Helena	# St Helena
     
     # Djibouti
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -254,30 +250,26 @@ Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
     # Egyptians would approve the cancellation."
     #
     # Egypt to cancel daylight saving time
    -# 
     # http://www.almasryalyoum.com/en/node/407168
    -# 
     # or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_egypt04.html
    -# 
     Rule	Egypt	1995	2010	-	Apr	lastFri	 0:00s	1:00	S
    -Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
    +Rule	Egypt	1995	2005	-	Sep	lastThu	24:00	0	-
     # From Steffen Thorsen (2006-09-19):
     # The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
     # Egypt will turn back clocks by one hour at the midnight of Thursday
     # after observing the daylight saving time since May.
     # http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
    -Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
    +Rule	Egypt	2006	only	-	Sep	21	24:00	0	-
     # From Dirk Losch (2007-08-14):
     # I received a mail from an airline which says that the daylight
     # saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
    -# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
    +# From Jesper Nørgaard Welen (2007-08-15): [The following agree:]
     # http://www.nentjes.info/Bill/bill5.htm
     # http://www.timeanddate.com/worldclock/city.html?n=53
     # From Steffen Thorsen (2007-09-04): The official information...:
     # http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
    -Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
    +Rule	Egypt	2007	only	-	Sep	Thu>=1	24:00	0	-
     # From Abdelrahman Hassan (2007-09-06):
     # Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
     # than the year of the Gregorian calendar, Ramadan shifts earlier each
    @@ -311,15 +303,9 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
     #
     # timeanddate[2] and another site I've found[3] also support that.
     #
    -# [1] 
    -# https://bugzilla.redhat.com/show_bug.cgi?id=492263
    -# 
    -# [2] 
    -# http://www.timeanddate.com/worldclock/clockchange.html?n=53
    -# 
    -# [3] 
    -# http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
    -# 
    +# [1] https://bugzilla.redhat.com/show_bug.cgi?id=492263
    +# [2] http://www.timeanddate.com/worldclock/clockchange.html?n=53
    +# [3] http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
     
     # From Arthur David Olson (2009-04-20):
     # In 2009 (and for the next several years), Ramadan ends before the fourth
    @@ -329,14 +315,10 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
     # From Steffen Thorsen (2009-08-11):
     # We have been able to confirm the August change with the Egyptian Cabinet
     # Information and Decision Support Center:
    -# 
     # http://www.timeanddate.com/news/time/egypt-dst-ends-2009.html
    -# 
     #
     # The Middle East News Agency
    -# 
     # http://www.mena.org.eg/index.aspx
    -# 
     # also reports "Egypt starts winter time on August 21"
     # today in article numbered "71, 11/08/2009 12:25 GMT."
     # Only the title above is available without a subscription to their service,
    @@ -344,19 +326,14 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
     # (at least today).
     
     # From Alexander Krivenyshev (2010-07-20):
    -# According to News from Egypt -  Al-Masry Al-Youm Egypt's cabinet has
    +# According to News from Egypt - Al-Masry Al-Youm Egypt's cabinet has
     # decided that Daylight Saving Time will not be used in Egypt during
     # Ramadan.
     #
     # Arabic translation:
    -# "Clocks to go back during Ramadan--and then forward again"
    -# 
    +# "Clocks to go back during Ramadan - and then forward again"
     # http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
    -# 
     
     # From Ahmad El-Dardiry (2014-05-07):
     # Egypt is to change back to Daylight system on May 15
    @@ -365,46 +342,77 @@ Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
     # From Gunther Vermier (2015-05-13):
     # our Egypt office confirms that the change will be at 15 May "midnight" (24:00)
     
    -# From Paul Eggert (2014-05-13):
    +# From Imed Chihi (2014-06-04):
    +# We have finally "located" a precise official reference about the DST changes
    +# in Egypt.  The Ministers Cabinet decision is explained at
    +# http://www.cabinet.gov.eg/Media/CabinetMeetingsDetails.aspx?id=347 ...
    +# [T]his (Arabic) site is not accessible outside Egypt, but the page ...
    +# translates into: "With regard to daylight saving time, it is scheduled to
    +# take effect at exactly twelve o'clock this evening, Thursday, 15 MAY 2014,
    +# to be suspended by twelve o'clock on the evening of Thursday, 26 JUN 2014,
    +# and re-established again at the end of the month of Ramadan, at twelve
    +# o'clock on the evening of Thursday, 31 JUL 2014."  This statement has been
    +# reproduced by other (more accessible) sites[, e.g.,]...
    +# http://elgornal.net/news/news.aspx?id=4699258
    +
    +# From Paul Eggert (2014-06-04):
     # Sarah El Deeb and Lee Keath of AP report that the Egyptian government says
     # the change is because of blackouts in Cairo, even though Ahram Online (cited
    -# above) says DST had no affect on electricity consumption.  The AP story says
    -# DST will not be observed during Ramadan.  There is no information about when
    -# DST will end.  See:
    +# above) says DST had no affect on electricity consumption.  There is
    +# no information about when DST will end this fall.  See:
     # http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833
     #
    -# For now, guess that later transitions will use 2010's rules, and that
    -# Egypt will agree with Morocco (see below) about the date Ramadan starts and
    -# ends, though (unlike Morocco) it will switch at 00:00 standard time.  In
    -# Egypt the spring-forward transitions are removed for 2020-2022, when the
    -# guessed spring-forward date falls during the estimated Ramadan, and all
    -# transitions removed for 2023-2038, where the estimated Ramadan falls entirely
    -# outside the guessed daylight-saving time.  Ramadan intrudes on the guessed
    -# DST starting in 2039, but that's beyond our somewhat-arbitrary cutoff.
    -
    -Rule	Egypt	2008	only	-	Aug	lastThu	23:00s	0	-
    -Rule	Egypt	2009	only	-	Aug	20	23:00s	0	-
    -Rule	Egypt	2010	only	-	Aug	11	0:00	0	-
    -Rule	Egypt	2010	only	-	Sep	10	0:00	1:00	S
    -Rule	Egypt	2010	only	-	Sep	lastThu	23:00s	0	-
    +# For now, guess that later spring and fall transitions will use
    +# 2010's rules, and guess that Egypt will switch to standard time at
    +# 24:00 the last Thursday before Ramadan, and back to DST at 00:00 the
    +# first Friday after Ramadan.  To implement this,
    +# transition dates for 2015 through 2037 were determined by running
    +# the following program under GNU Emacs 24.3, with the results integrated
    +# by hand into the table below.  Ramadan again intrudes on the guessed
    +# DST starting in 2038, but that's beyond our somewhat-arbitrary cutoff.
    +# (let ((islamic-year 1436))
    +#   (while (< islamic-year 1460)
    +#     (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year)))
    +#           (b (calendar-islamic-to-absolute (list 10 1 islamic-year)))
    +#           (friday 5))
    +#       (while (/= friday (mod a 7))
    +#         (setq a (1- a)))
    +#       (while (/= friday (mod b 7))
    +#         (setq b (1+ b)))
    +#       (setq a (1- a))
    +#       (setq b (1- b))
    +#       (setq a (calendar-gregorian-from-absolute a))
    +#       (setq b (calendar-gregorian-from-absolute b))
    +#       (insert
    +#        (format
    +#         (concat "Rule\tEgypt\t%d\tonly\t-\t%s\t%2d\t24:00\t0\t-\n"
    +#                 "Rule\tEgypt\t%d\tonly\t-\t%s\t%2d\t24:00\t1:00\tS\n")
    +#         (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
    +#         (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
    +#     (setq islamic-year (+ 1 islamic-year))))
    +Rule	Egypt	2008	only	-	Aug	lastThu	24:00	0	-
    +Rule	Egypt	2009	only	-	Aug	20	24:00	0	-
    +Rule	Egypt	2010	only	-	Aug	10	24:00	0	-
    +Rule	Egypt	2010	only	-	Sep	 9	24:00	1:00	S
    +Rule	Egypt	2010	only	-	Sep	lastThu	24:00	0	-
     Rule	Egypt	2014	only	-	May	15	24:00	1:00	S
    -Rule	Egypt	2014	only	-	Jun	29	 0:00s	0	-
    -Rule	Egypt	2014	only	-	Jul	29	 0:00s	1:00	S
    -Rule	Egypt	2014	max	-	Sep	lastThu	23:00s	0	-
    +Rule	Egypt	2014	only	-	Jun	26	24:00	0	-
    +Rule	Egypt	2014	only	-	Jul	31	24:00	1:00	S
    +Rule	Egypt	2014	max	-	Sep	lastThu	24:00	0	-
     Rule	Egypt	2015	2019	-	Apr	lastFri	 0:00s	1:00	S
    -Rule	Egypt	2015	only	-	Jun	18	 0:00s	0	-
    -Rule	Egypt	2015	only	-	Jul	18	 0:00s	1:00	S
    -Rule	Egypt	2016	only	-	Jun	 7	 0:00s	0	-
    -Rule	Egypt	2016	only	-	Jul	 7	 0:00s	1:00	S
    -Rule	Egypt	2017	only	-	May	27	 0:00s	0	-
    -Rule	Egypt	2017	only	-	Jun	26	 0:00s	1:00	S
    -Rule	Egypt	2018	only	-	May	16	 0:00s	0	-
    -Rule	Egypt	2018	only	-	Jun	15	 0:00s	1:00	S
    -Rule	Egypt	2019	only	-	May	 6	 0:00s	0	-
    -Rule	Egypt	2019	only	-	Jun	 5	 0:00s	1:00	S
    -Rule	Egypt	2020	only	-	May	24	 0:00s	1:00	S
    -Rule	Egypt	2021	only	-	May	13	 0:00s	1:00	S
    -Rule	Egypt	2022	only	-	May	 3	 0:00s	1:00	S
    +Rule	Egypt	2015	only	-	Jun	11	24:00	0	-
    +Rule	Egypt	2015	only	-	Jul	23	24:00	1:00	S
    +Rule	Egypt	2016	only	-	Jun	 2	24:00	0	-
    +Rule	Egypt	2016	only	-	Jul	 7	24:00	1:00	S
    +Rule	Egypt	2017	only	-	May	25	24:00	0	-
    +Rule	Egypt	2017	only	-	Jun	29	24:00	1:00	S
    +Rule	Egypt	2018	only	-	May	10	24:00	0	-
    +Rule	Egypt	2018	only	-	Jun	14	24:00	1:00	S
    +Rule	Egypt	2019	only	-	May	 2	24:00	0	-
    +Rule	Egypt	2019	only	-	Jun	 6	24:00	1:00	S
    +Rule	Egypt	2020	only	-	May	28	24:00	1:00	S
    +Rule	Egypt	2021	only	-	May	13	24:00	1:00	S
    +Rule	Egypt	2022	only	-	May	 5	24:00	1:00	S
     Rule	Egypt	2023	max	-	Apr	lastFri	 0:00s	1:00	S
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -412,60 +420,63 @@ Zone	Africa/Cairo	2:05:09 -	LMT	1900 Oct
     			2:00	Egypt	EE%sT
     
     # Equatorial Guinea
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Malabo	0:35:08 -	LMT	1912
    -			0:00	-	GMT	1963 Dec 15
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
     # Eritrea
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Asmara	2:35:32 -	LMT	1870
    -			2:35:32	-	AMT	1890	      # Asmara Mean Time
    -			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
    +			2:35:32	-	AMT	1890        # Asmara Mean Time
    +			2:35:20	-	ADMT	1936 May  5 # Adis Dera MT
     			3:00	-	EAT
     
     # Ethiopia
    -# From Paul Eggert (2006-03-22):
    -# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
    -# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
    -# We'll guess that 38E50 is for Adis Dera.
    +# From Paul Eggert (2014-07-31):
    +# Like the Swahili of Kenya and Tanzania, many Ethiopians keep a
    +# 12-hour clock starting at our 06:00, so their "8 o'clock" is our
    +# 02:00 or 14:00.  Keep this in mind when you ask the time in Amharic.
    +#
    +# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time
    +# zones between 1870 and 1890, that they merged to 38E50 (2:35:20) in
    +# 1890, and that they switched to 3:00 on 1936-05-05.  Perhaps 38E50
    +# was for Adis Dera.  Quite likely the Shanks data entries are wrong
    +# anyway.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
    -			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
    +			2:35:20	-	ADMT	1936 May  5 # Adis Dera MT
     			3:00	-	EAT
     
     # Gabon
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Libreville	0:37:48 -	LMT	1912
    -			1:00	-	WAT
    +# See Africa/Lagos.
     
     # Gambia
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Banjul	-1:06:36 -	LMT	1912
    -			-1:06:36 -	BMT	1935	# Banjul Mean Time
    -			-1:00	-	WAT	1964
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Ghana
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -# Whitman says DST was observed from 1931 to ``the present'';
    -# go with Shanks & Pottenger.
    -Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
    -Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
    +# Whitman says DST was observed from 1931 to "the present";
    +# Shanks & Pottenger say 1936 to 1942;
    +# and September 1 to January 1 is given by:
    +# Scott Keltie J, Epstein M (eds), The Statesman's Year-Book,
    +# 57th ed. Macmillan, London (1920), OCLC 609408015, pp xxviii.
    +# For lack of better info, assume DST was observed from 1920 to 1942.
    +Rule	Ghana	1920	1942	-	Sep	 1	0:00	0:20	GHST
    +Rule	Ghana	1920	1942	-	Dec	31	0:00	0	GMT
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Accra	-0:00:52 -	LMT	1918
     			 0:00	Ghana	%s
     
     # Guinea
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Conakry	-0:54:52 -	LMT	1912
    -			 0:00	-	GMT	1934 Feb 26
    -			-1:00	-	WAT	1960
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Guinea-Bissau
    +#
    +# Shanks gives 1911-05-26 for the transition to WAT,
    +# evidently confusing the date of the Portuguese decree
    +# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
    +# with the date that it took effect, namely 1912-01-01.
    +#
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Bissau	-1:02:20 -	LMT	1911 May 26
    +Zone	Africa/Bissau	-1:02:20 -	LMT	1912 Jan  1
     			-1:00	-	WAT	1975
     			 0:00	-	GMT
     
    @@ -480,8 +491,8 @@ Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
     # Lesotho
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Maseru	1:50:00 -	LMT	1903 Mar
    -			2:00	-	SAST	1943 Sep 19 2:00
    -			2:00	1:00	SAST	1944 Mar 19 2:00
    +			2:00	-	SAST	1943 Sep 19  2:00
    +			2:00	1:00	SAST	1944 Mar 19  2:00
     			2:00	-	SAST
     
     # Liberia
    @@ -549,11 +560,11 @@ Zone	Africa/Tripoli	0:52:44 -	LMT	1920
     			2:00	-	EET	1982
     			1:00	Libya	CE%sT	1990 May  4
     # The 1996 and 1997 entries are from Shanks & Pottenger;
    -# the IATA SSIM data contain some obvious errors.
    +# the IATA SSIM data entries contain some obvious errors.
     			2:00	-	EET	1996 Sep 30
     			1:00	Libya	CE%sT	1997 Oct  4
    -			2:00	-	EET	2012 Nov 10 2:00
    -			1:00	Libya	CE%sT	2013 Oct 25 2:00
    +			2:00	-	EET	2012 Nov 10  2:00
    +			1:00	Libya	CE%sT	2013 Oct 25  2:00
     			2:00	-	EET
     
     # Madagascar
    @@ -569,18 +580,8 @@ Zone	Africa/Blantyre	2:20:00 -	LMT	1903 Mar
     			2:00	-	CAT
     
     # Mali
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Bamako	-0:32:00 -	LMT	1912
    -			 0:00	-	GMT	1934 Feb 26
    -			-1:00	-	WAT	1960 Jun 20
    -			 0:00	-	GMT
    -
     # Mauritania
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
    -			 0:00	-	GMT	1934 Feb 26
    -			-1:00	-	WAT	1960 Nov 28
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Mauritius
     
    @@ -604,9 +605,7 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
     
     # From Steffen Thorsen (2008-07-10):
     # According to
    -# 
     # http://www.lexpress.mu/display_article.php?news_id=111216
    -# 
     # (in French), Mauritius will start and end their DST a few days earlier
     # than previously announced (2008-11-01 to 2009-03-31).  The new start
     # date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
    @@ -621,22 +620,17 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
     
     # From Alex Krivenyshev (2008-07-11):
     # Seems that English language article "The revival of daylight saving
    -# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
    +# time: Energy conservation?"-# No. 16578 (07/11/2008) was originally
     # published on Monday, June 30, 2008...
     #
     # I guess that article in French "Le gouvernement avance l'introduction
    -# de l'heure d'ete" stating that DST in Mauritius starting on October 26
    -# and ending on March 27, 2009 is the most recent one.
    -# ...
    -# 
    +# de l'heure d'été" stating that DST in Mauritius starting on October 26
    +# and ending on March 27, 2009 is the most recent one....
     # http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
    -# 
     
     # From Riad M. Hossen Ally (2008-08-03):
     # The Government of Mauritius weblink
    -# 
     # http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
    -# 
     # Cabinet Decision of July 18th, 2008 states as follows:
     #
     # 4. ...Cabinet has agreed to the introduction into the National Assembly
    @@ -646,33 +640,25 @@ Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
     # States of America. It will start at two o'clock in the morning on the
     # last Sunday of October and will end at two o'clock in the morning on
     # the last Sunday of March the following year. The summer time for the
    -# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
    +# year 2008-2009 will, therefore, be effective as from 26 October 2008
     # and end on 29 March 2009.
     
     # From Ed Maste (2008-10-07):
     # THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
     # beginning / ending of summer time is 2 o'clock standard time in the
     # morning of the last Sunday of October / last Sunday of March.
    -# 
     # http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
    -# 
     
     # From Steffen Thorsen (2009-06-05):
     # According to several sources, Mauritius will not continue to observe
     # DST the coming summer...
     #
     # Some sources, in French:
    -# 
     # http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB
    -# 
    -# 
     # http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints-
    -# 
     #
     # Our wrap-up:
    -# 
     # http://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html
    -# 
     
     # From Arthur David Olson (2009-07-11):
     # The "mauritius-dst-will-not-repeat" wrapup includes this:
    @@ -685,18 +671,18 @@ Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
     Rule Mauritius	2008	only	-	Oct	lastSun	2:00	1:00	S
     Rule Mauritius	2009	only	-	Mar	lastSun	2:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
    +Zone Indian/Mauritius	3:50:00 -	LMT	1907 # Port Louis
     			4:00 Mauritius	MU%sT	# Mauritius Time
     # Agalega Is, Rodriguez
     # no information; probably like Indian/Mauritius
     
     # Mayotte
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
    +Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul # Mamoutzou
     			3:00	-	EAT
     
     # Morocco
    -# See the `europe' file for Spanish Morocco (Africa/Ceuta).
    +# See the 'europe' file for Spanish Morocco (Africa/Ceuta).
     
     # From Alex Krivenyshev (2008-05-09):
     # Here is an article that Morocco plan to introduce Daylight Saving Time between
    @@ -704,60 +690,44 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     #
     # "... Morocco is to save energy by adjusting its clock during summer so it will
     # be one hour ahead of GMT between 1 June and 27 September, according to
    -# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
    +# Communication Minister and Government Spokesman, Khalid Naciri...."
     #
    -# 
     # http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
    -# 
    -# OR
    -# 
     # http://en.afrik.com/news11892.html
    -# 
     
     # From Alex Krivenyshev (2008-05-09):
    -# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
    -# 
    +# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe
    +# Presse:
     # http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
    -# 
     #
     # Morocco shifts to daylight time on June 1st through September 27, Govt.
     # spokesman.
     
     # From Patrice Scattolin (2008-05-09):
     # According to this article:
    -# 
     # http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
    -# 
    -# (and republished here:
    -# 
    -# http://www.actu.ma/heure-dete-comment_i127896_0.html
    -# 
    -# )
    -# the changes occurs at midnight:
    +# (and republished here: )
    +# the changes occur at midnight:
     #
    -# saturday night may 31st at midnight (which in french is to be
    -# intrepreted as the night between saturday and sunday)
    -# sunday night the 28th  at midnight
    +# Saturday night May 31st at midnight (which in French is to be
    +# interpreted as the night between Saturday and Sunday)
    +# Sunday night the 28th at midnight
     #
    -# Seeing that the 28th is monday, I am guessing that she intends to say
    -# the midnight of the 28th which is the midnight between sunday and
    -# monday, which jives with other sources that say that it's inclusive
    -# june1st to sept 27th.
    +# Seeing that the 28th is Monday, I am guessing that she intends to say
    +# the midnight of the 28th which is the midnight between Sunday and
    +# Monday, which jives with other sources that say that it's inclusive
    +# June 1st to Sept 27th.
     #
     # The decision was taken by decree *2-08-224 *but I can't find the decree
     # published on the web.
     #
     # It's also confirmed here:
    -# 
     # http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
    -# 
    -# on a government portal as being  between june 1st and sept 27th (not yet
    -# posted in english).
    +# on a government portal as being between June 1st and Sept 27th (not yet
    +# posted in English).
     #
    -# The following google query will generate many relevant hits:
    -# 
    +# The following Google query will generate many relevant hits:
     # http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
    -# 
     
     # From Steffen Thorsen (2008-08-27):
     # Morocco will change the clocks back on the midnight between August 31
    @@ -765,47 +735,32 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     # of September:
     #
     # One article about it (in French):
    -# 
     # http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
    -# 
     #
     # We have some further details posted here:
    -# 
     # http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
    -# 
     
     # From Steffen Thorsen (2009-03-17):
     # Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
     # to many sources, such as
    -# 
     # http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
    -# 
    -# 
     # http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
    -# 
     # (French)
     #
     # Our summary:
    -# 
     # http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
    -# 
     
     # From Alexander Krivenyshev (2009-03-17):
     # Here is a link to official document from Royaume du Maroc Premier Ministre,
    -# Ministere de la Modernisation des Secteurs Publics
    +# Ministère de la Modernisation des Secteurs Publics
     #
     # Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
     # concerning the amendment of the legal time, the Ministry of Modernization of
     # Public Sectors announced that the official time in the Kingdom will be
     # advanced 60 minutes from Sunday 31 May 2009 at midnight.
     #
    -# 
     # http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
    -# 
    -#
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
    -# 
     
     # From Steffen Thorsen (2010-04-13):
     # Several news media in Morocco report that the Ministry of Modernization
    @@ -813,51 +768,33 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     # 2010-05-02 to 2010-08-08.
     #
     # Example:
    -# 
     # http://www.lavieeco.com/actualites/4099-le-maroc-passera-a-l-heure-d-ete-gmt1-le-2-mai.html
    -# 
     # (French)
     # Our page:
    -# 
     # http://www.timeanddate.com/news/time/morocco-starts-dst-2010.html
    -# 
     
     # From Dan Abitol (2011-03-30):
     # ...Rules for Africa/Casablanca are the following (24h format)
    -# The 3rd april 2011 at 00:00:00, [it] will be 3rd april 1:00:00
    -# The 31th july 2011 at 00:59:59,  [it] will be 31th July 00:00:00
    +# The 3rd April 2011 at 00:00:00, [it] will be 3rd April 01:00:00
    +# The 31st July 2011 at 00:59:59, [it] will be 31st July 00:00:00
     # ...Official links of change in morocco
     # The change was broadcast on the FM Radio
     # I ve called ANRT (telecom regulations in Morocco) at
     # +212.537.71.84.00
    -# 
     # http://www.anrt.net.ma/fr/
    -# 
     # They said that
    -# 
     # http://www.map.ma/fr/sections/accueil/l_heure_legale_au_ma/view
    -# 
     # is the official publication to look at.
     # They said that the decision was already taken.
     #
     # More articles in the press
    -# 
    -# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-lev
    -# 
    -# e.html
    -# 
    +# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-leve.html
     # http://www.lematin.ma/Actualite/Express/Article.asp?id=148923
    -# 
    -# 
     # http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim
    -# anche-prochain-5538.html
    -# 
     
     # From Petr Machata (2011-03-30):
     # They have it written in English here:
    -# 
     # http://www.map.ma/eng/sections/home/morocco_to_spring_fo/view
    -# 
     #
     # It says there that "Morocco will resume its standard time on July 31,
     # 2011 at midnight." Now they don't say whether they mean midnight of
    @@ -865,20 +802,16 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     # also been like that in the past.
     
     # From Alexander Krivenyshev (2012-03-09):
    -# According to Infomédiaire web site from Morocco (infomediaire.ma),
    -# on March 9, 2012, (in French) Heure légale:
    -# Le Maroc adopte officiellement l'heure d'été
    -# 
    +# According to Infomédiaire web site from Morocco (infomediaire.ma),
    +# on March 9, 2012, (in French) Heure légale:
    +# Le Maroc adopte officiellement l'heure d'été
     # http://www.infomediaire.ma/news/maroc/heure-l%C3%A9gale-le-maroc-adopte-officiellement-lheure-d%C3%A9t%C3%A9
    -# 
     # Governing Council adopted draft decree, that Morocco DST starts on
     # the last Sunday of March (March 25, 2012) and ends on
     # last Sunday of September (September 30, 2012)
     # except the month of Ramadan.
     # or (brief)
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_morocco06.html
    -# 
     
     # From Arthur David Olson (2012-03-10):
     # The infomediaire.ma source indicates that the system is to be in
    @@ -889,17 +822,13 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     
     # From Christophe Tropamer (2012-03-16):
     # Seen Morocco change again:
    -# 
     # http://www.le2uminutes.com/actualite.php
    -# 
    -# "...à partir du dernier dimance d'avril et non fins mars,
    -# comme annoncé précédemment."
    +# "...à partir du dernier dimanche d'avril et non fins mars,
    +# comme annoncé précédemment."
     
     # From Milamber Space Network (2012-07-17):
     # The official return to GMT is announced by the Moroccan government:
    -# 
     # http://www.mmsp.gov.ma/fr/actualites.aspx?id=288 [in French]
    -# 
     #
     # Google translation, lightly edited:
     # Back to the standard time of the Kingdom (GMT)
    @@ -917,7 +846,7 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     # announced a bit in advance.  On 2012-07-11 the Moroccan government
     # announced that year's Ramadan daylight-saving transitions would be
     # 2012-07-20 and 2012-08-20; see
    -# .
    +# http://www.mmsp.gov.ma/fr/actualites.aspx?id=288
     
     # From Andrew Paprocki (2013-07-02):
     # Morocco announced that the year's Ramadan daylight-savings
    @@ -937,39 +866,36 @@ Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
     # From Sebastien Willemijns (2014-03-18):
     # http://www.afriquinfos.com/articles/2014/3/18/maroc-heure-dete-avancez-tous-horloges-247891.asp
     
    -# From Paul Eggert (2014-03-19):
    -# To estimate what the Moroccan government will do in future years,
    -# transition dates for 2014 through 2038 were determined by running
    -# the following program under GNU Emacs 24.3:
    -#
    -# (let ((islamic-year 1435))
    -#   (while (< islamic-year 1461)
    -#     (let ((a
    -#	     (calendar-gregorian-from-absolute
    -#	      (calendar-islamic-to-absolute (list 9 1 islamic-year))))
    -#	    (b
    -#	     (calendar-gregorian-from-absolute
    -#	      (calendar-islamic-to-absolute (list 10 1 islamic-year)))))
    -#	(insert
    -#	 (format
    -#	  (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 3:00\t0\t-\n"
    -#		  "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 2:00\t1:00\tS\n")
    -#	  (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
    -#	  (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
    +# From Milamber Space Network (2014-06-05):
    +# The Moroccan government has recently announced that the country will return
    +# to standard time at 03:00 on Saturday, June 28, 2014 local time....  DST
    +# will resume again at 02:00 on Saturday, August 2, 2014....
    +# http://www.mmsp.gov.ma/fr/actualites.aspx?id=586
    +
    +# From Paul Eggert (2014-06-05):
    +# For now, guess that later spring and fall transitions will use 2014's rules,
    +# and guess that Morocco will switch to standard time at 03:00 the last
    +# Saturday before Ramadan, and back to DST at 02:00 the first Saturday after
    +# Ramadan.  To implement this, transition dates for 2015 through 2037 were
    +# determined by running the following program under GNU Emacs 24.3, with the
    +# results integrated by hand into the table below.
    +# (let ((islamic-year 1436))
    +#   (while (< islamic-year 1460)
    +#     (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year)))
    +#           (b (calendar-islamic-to-absolute (list 10 1 islamic-year)))
    +#           (saturday 6))
    +#       (while (/= saturday (mod (setq a (1- a)) 7)))
    +#       (while (/= saturday (mod b 7))
    +#         (setq b (1+ b)))
    +#       (setq a (calendar-gregorian-from-absolute a))
    +#       (setq b (calendar-gregorian-from-absolute b))
    +#       (insert
    +#        (format
    +#         (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 3:00\t0\t-\n"
    +#                 "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 2:00\t1:00\tS\n")
    +#         (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
    +#         (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
     #     (setq islamic-year (+ 1 islamic-year))))
    -#
    -# with spring-forward transitions removed for 2023-2025, when the
    -# normal spring-forward date falls during the estimated Ramadan; with
    -# all transitions removed for 2026-2035, where the estimated Ramadan
    -# falls entirely outside daylight-saving time; and with fall-back
    -# transitions removed for 2036-2037, where the normal fall-back
    -# date falls during the estimated Ramadan.  Normally, the table would
    -# stop after 2037 because 32-bit time_t values roll around early in 2038,
    -# but that would imply a prediction of perpetual DST after March 2038
    -# due to the year-2037 glitches.  So, this table instead stops after
    -# 2038, the first non-glitchy year after the 32-bit rollover.
    -# An advantage of stopping after 2038 is that it lets zic guess
    -# TZ='WET0WEST,M3.5.0,M10.5.0/3' for time stamps far in the future.
     
     # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     
    @@ -991,46 +917,44 @@ Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
     Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
     Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
     Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
    -Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
    +Rule	Morocco	2009	only	-	Aug	21	 0:00	0	-
     Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
     Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
     Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
    -Rule	Morocco	2011	only	-	Jul	 31	 0	0	-
    -Rule	Morocco	2012	2013	-	Apr	 lastSun 2:00	1:00	S
    -Rule	Morocco	2012	only	-	Sep	 30	 3:00	0	-
    -Rule	Morocco	2012	only	-	Jul	 20	 3:00	0	-
    -Rule	Morocco	2012	only	-	Aug	 20	 2:00	1:00	S
    -Rule	Morocco	2013	only	-	Jul	  7	 3:00	0	-
    -Rule	Morocco	2013	only	-	Aug	 10	 2:00	1:00	S
    -Rule	Morocco	2013	2035	-	Oct	 lastSun 3:00	0	-
    -Rule	Morocco	2014	2022	-	Mar	 lastSun 2:00	1:00	S
    -Rule	Morocco	2014	only	-	Jun	 29	 3:00	0	-
    -Rule	Morocco	2014	only	-	Jul	 29	 2:00	1:00	S
    -Rule	Morocco	2015	only	-	Jun	 18	 3:00	0	-
    -Rule	Morocco	2015	only	-	Jul	 18	 2:00	1:00	S
    -Rule	Morocco	2016	only	-	Jun	  7	 3:00	0	-
    -Rule	Morocco	2016	only	-	Jul	  7	 2:00	1:00	S
    -Rule	Morocco	2017	only	-	May	 27	 3:00	0	-
    -Rule	Morocco	2017	only	-	Jun	 26	 2:00	1:00	S
    -Rule	Morocco	2018	only	-	May	 16	 3:00	0	-
    -Rule	Morocco	2018	only	-	Jun	 15	 2:00	1:00	S
    -Rule	Morocco	2019	only	-	May	  6	 3:00	0	-
    -Rule	Morocco	2019	only	-	Jun	  5	 2:00	1:00	S
    -Rule	Morocco	2020	only	-	Apr	 24	 3:00	0	-
    -Rule	Morocco	2020	only	-	May	 24	 2:00	1:00	S
    -Rule	Morocco	2021	only	-	Apr	 13	 3:00	0	-
    -Rule	Morocco	2021	only	-	May	 13	 2:00	1:00	S
    -Rule	Morocco	2022	only	-	Apr	  3	 3:00	0	-
    -Rule	Morocco	2022	only	-	May	  3	 2:00	1:00	S
    -Rule	Morocco	2023	only	-	Apr	 22	 2:00	1:00	S
    -Rule	Morocco	2024	only	-	Apr	 10	 2:00	1:00	S
    -Rule	Morocco	2025	only	-	Mar	 31	 2:00	1:00	S
    -Rule	Morocco	2026	max	-	Mar	 lastSun 2:00	1:00	S
    -Rule	Morocco	2036	only	-	Oct	 21	 3:00	0	-
    -Rule	Morocco	2037	only	-	Oct	 11	 3:00	0	-
    -Rule	Morocco	2038	only	-	Sep	 30	 3:00	0	-
    -Rule	Morocco	2038	only	-	Oct	 30	 2:00	1:00	S
    -Rule	Morocco	2038	max	-	Oct	 lastSun 3:00	0	-
    +Rule	Morocco	2011	only	-	Jul	31	 0	0	-
    +Rule	Morocco	2012	2013	-	Apr	lastSun	 2:00	1:00	S
    +Rule	Morocco	2012	only	-	Sep	30	 3:00	0	-
    +Rule	Morocco	2012	only	-	Jul	20	 3:00	0	-
    +Rule	Morocco	2012	only	-	Aug	20	 2:00	1:00	S
    +Rule	Morocco	2013	only	-	Jul	 7	 3:00	0	-
    +Rule	Morocco	2013	only	-	Aug	10	 2:00	1:00	S
    +Rule	Morocco	2013	max	-	Oct	lastSun	 3:00	0	-
    +Rule	Morocco	2014	2022	-	Mar	lastSun	 2:00	1:00	S
    +Rule	Morocco	2014	only	-	Jun	28	 3:00	0	-
    +Rule	Morocco	2014	only	-	Aug	 2	 2:00	1:00	S
    +Rule	Morocco	2015	only	-	Jun	13	 3:00	0	-
    +Rule	Morocco	2015	only	-	Jul	18	 2:00	1:00	S
    +Rule	Morocco	2016	only	-	Jun	 4	 3:00	0	-
    +Rule	Morocco	2016	only	-	Jul	 9	 2:00	1:00	S
    +Rule	Morocco	2017	only	-	May	20	 3:00	0	-
    +Rule	Morocco	2017	only	-	Jul	 1	 2:00	1:00	S
    +Rule	Morocco	2018	only	-	May	12	 3:00	0	-
    +Rule	Morocco	2018	only	-	Jun	16	 2:00	1:00	S
    +Rule	Morocco	2019	only	-	May	 4	 3:00	0	-
    +Rule	Morocco	2019	only	-	Jun	 8	 2:00	1:00	S
    +Rule	Morocco	2020	only	-	Apr	18	 3:00	0	-
    +Rule	Morocco	2020	only	-	May	30	 2:00	1:00	S
    +Rule	Morocco	2021	only	-	Apr	10	 3:00	0	-
    +Rule	Morocco	2021	only	-	May	15	 2:00	1:00	S
    +Rule	Morocco	2022	only	-	Apr	 2	 3:00	0	-
    +Rule	Morocco	2022	only	-	May	 7	 2:00	1:00	S
    +Rule	Morocco	2023	only	-	Apr	22	 2:00	1:00	S
    +Rule	Morocco	2024	only	-	Apr	13	 2:00	1:00	S
    +Rule	Morocco	2025	only	-	Apr	 5	 2:00	1:00	S
    +Rule	Morocco	2026	max	-	Mar	lastSun	 2:00	1:00	S
    +Rule	Morocco	2035	only	-	Oct	27	 3:00	0	-
    +Rule	Morocco	2036	only	-	Oct	18	 3:00	0	-
    +Rule	Morocco	2037	only	-	Oct	10	 3:00	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
    @@ -1049,11 +973,17 @@ Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
     # Assume that this has been true since Western Sahara switched to GMT,
     # since most of it was then controlled by Morocco.
     
    -Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
    +Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan # El Aaiún
     			-1:00	-	WAT	1976 Apr 14
     			 0:00	Morocco	WE%sT
     
     # Mozambique
    +#
    +# Shanks gives 1903-03-01 for the transition to CAT.
    +# Perhaps the 1911-05-26 Portuguese decree
    +# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
    +# merely made it official?
    +#
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
     			2:00	-	CAT
    @@ -1062,8 +992,8 @@ Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
     # The 1994-04-03 transition is from Shanks & Pottenger.
     # Shanks & Pottenger report no DST after 1998-04; go with IATA.
     
    -# From Petronella Sibeene (2007-03-30) in
    -# :
    +# From Petronella Sibeene (2007-03-30):
    +# http://allafrica.com/stories/200703300178.html
     # While the entire country changes its time, Katima Mulilo and other
     # settlements in Caprivi unofficially will not because the sun there
     # rises and sets earlier compared to other regions.  Chief of
    @@ -1080,34 +1010,41 @@ Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
     Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Windhoek	1:08:24 -	LMT	1892 Feb 8
    -			1:30	-	SWAT	1903 Mar	# SW Africa Time
    -			2:00	-	SAST	1942 Sep 20 2:00
    -			2:00	1:00	SAST	1943 Mar 21 2:00
    +			1:30	-	SWAT	1903 Mar    # SW Africa Time
    +			2:00	-	SAST	1942 Sep 20  2:00
    +			2:00	1:00	SAST	1943 Mar 21  2:00
     			2:00	-	SAST	1990 Mar 21 # independence
     			2:00	-	CAT	1994 Apr  3
     			1:00	Namibia	WA%sT
     
     # Niger
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Niamey	 0:08:28 -	LMT	1912
    -			-1:00	-	WAT	1934 Feb 26
    -			 0:00	-	GMT	1960
    -			 1:00	-	WAT
    +# See Africa/Lagos.
     
     # Nigeria
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Lagos	0:13:36 -	LMT	1919 Sep
     			1:00	-	WAT
    +Link Africa/Lagos Africa/Bangui	     # Central African Republic
    +Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo
    +Link Africa/Lagos Africa/Douala	     # Cameroon
    +Link Africa/Lagos Africa/Kinshasa    # Dem. Rep. of the Congo (west)
    +Link Africa/Lagos Africa/Libreville  # Gabon
    +Link Africa/Lagos Africa/Luanda	     # Angola
    +Link Africa/Lagos Africa/Malabo	     # Equatorial Guinea
    +Link Africa/Lagos Africa/Niamey	     # Niger
    +Link Africa/Lagos Africa/Porto-Novo  # Benin
     
    -# Reunion
    +# Réunion
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun	# Saint-Denis
    -			4:00	-	RET	# Reunion Time
    +Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun # Saint-Denis
    +			4:00	-	RET	# Réunion Time
     #
    -# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
    +# Crozet Islands also observes Réunion time; see the 'antarctica' file.
    +#
    +# Scattered Islands (Îles Éparses) administered from Réunion are as follows.
     # The following information about them is taken from
    -# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
    -# no longer available as of 1999-08-17).
    +# Îles Éparses (, 1997-07-22,
    +# in French; no longer available as of 1999-08-17).
     # We have no info about their time zone histories.
     #
     # Bassas da India - uninhabited
    @@ -1122,32 +1059,21 @@ Zone	Africa/Kigali	2:00:16 -	LMT	1935 Jun
     			2:00	-	CAT
     
     # St Helena
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Atlantic/St_Helena	-0:22:48 -	LMT	1890		# Jamestown
    -			-0:22:48 -	JMT	1951	# Jamestown Mean Time
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     # The other parts of the St Helena territory are similar:
     #	Tristan da Cunha: on GMT, say Whitman and the CIA
    -#	Ascension: on GMT, says usno1995 and the CIA
    +#	Ascension: on GMT, say the USNO (1995-12-21) and the CIA
     #	Gough (scientific station since 1955; sealers wintered previously):
     #		on GMT, says the CIA
    -#	Inaccessible, Nightingale: no information, but probably GMT
    -
    -# Sao Tome and Principe
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Sao_Tome	 0:26:56 -	LMT	1884
    -			-0:36:32 -	LMT	1912	# Lisbon Mean Time
    -			 0:00	-	GMT
    +#	Inaccessible, Nightingale: uninhabited
     
    +# São Tomé and Príncipe
     # Senegal
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Dakar	-1:09:44 -	LMT	1912
    -			-1:00	-	WAT	1941 Jun
    -			 0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Seychelles
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
    +Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun # Victoria
     			4:00	-	SCT	# Seychelles Time
     # From Paul Eggert (2001-05-30):
     # Aldabra, Farquhar, and Desroches, originally dependencies of the
    @@ -1157,17 +1083,7 @@ Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
     # Possibly the islands were uninhabited.
     
     # Sierra Leone
    -# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
    -Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
    -Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
    -Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
    -Rule	SL	1957	1962	-	Sep	 1	0:00	0	GMT
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Freetown	-0:53:00 -	LMT	1882
    -			-0:53:00 -	FMT	1913 Jun # Freetown Mean Time
    -			-1:00	SL	%s	1957
    -			 0:00	SL	%s
    +# See Africa/Abidjan.
     
     # Somalia
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -1190,9 +1106,9 @@ Zone Africa/Johannesburg 1:52:00 -	LMT	1892 Feb 8
     
     # Sudan
     #
    -# From 
    -# Sudan News Agency (2000-01-13)
    -# , also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
    +# From 
    +# Sudan News Agency (2000-01-13),
    +# also reported by Michaël De Beukelaer-Dossche via Steffen Thorsen:
     # Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
     # Saturday....  This was announced Thursday by Caretaker State Minister for
     # Manpower Abdul-Rahman Nur-Eddin.
    @@ -1223,14 +1139,12 @@ Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
     			3:00	-	EAT
     
     # Togo
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Africa/Lome	0:04:52 -	LMT	1893
    -			0:00	-	GMT
    +# See Africa/Abidjan.
     
     # Tunisia
     
     # From Gwillim Law (2005-04-30):
    -# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
    +# My correspondent, Risto Nykänen, has alerted me to another adoption of DST,
     # this time in Tunisia.  According to Yahoo France News
     # , in a story attributed to AP
     # and dated 2005-04-26, "Tunisia has decided to advance its official time by
    @@ -1239,8 +1153,8 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
     # Saturday."  (My translation)
     #
     # From Oscar van Vlijmen (2005-05-02):
    -# LaPresse, the first national daily newspaper ...
    -# 
    +# La Presse, the first national daily newspaper ...
    +# http://www.lapresse.tn/archives/archives280405/actualites/lheure.html
     # ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
     # 1h standard time.
     #
    @@ -1253,18 +1167,12 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
     # From Steffen Thorsen (2009-03-16):
     # According to several news sources, Tunisia will not observe DST this year.
     # (Arabic)
    -# 
     # http://www.elbashayer.com/?page=viewn&nid=42546
    -# 
    -# 
     # http://www.babnet.net/kiwidetail-15295.asp
    -# 
     #
     # We have also confirmed this with the US embassy in Tunisia.
     # We have a wrap-up about this on the following page:
    -# 
     # http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
    -# 
     
     # From Alexander Krivenyshev (2009-03-17):
     # Here is a link to Tunis Afrique Presse News Agency
    @@ -1272,20 +1180,17 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
     # Standard time to be kept the whole year long (tap.info.tn):
     #
     # (in English)
    -# 
     # http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
    -# 
     #
     # (in Arabic)
    -# 
     # http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
    -# 
     
    -# From Arthur David Olson (2009--3-18):
    -# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
    -# that the fasting month of ramadan coincides with the period concerned by summer time.
    -# Therefore, the standard time will be kept unchanged the whole year long."
    -# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
    +# From Arthur David Olson (2009-03-18):
    +# The Tunis Afrique Presse News Agency notice contains this: "This measure is
    +# due to the fact that the fasting month of Ramadan coincides with the period
    +# concerned by summer time.  Therefore, the standard time will be kept
    +# unchanged the whole year long."  So foregoing DST seems to be an exception
    +# (albeit one that may be repeated in the future).
     
     # From Alexander Krivenyshev (2010-03-27):
     # According to some news reports Tunis confirmed not to use DST in 2010
    @@ -1297,12 +1202,8 @@ Zone	Africa/Lome	0:04:52 -	LMT	1893
     # coincided with the month of Ramadan..."
     #
     # (in Arabic)
    -# 
     # http://www.moheet.com/show_news.aspx?nid=358861&pg=1
    -# 
     # http://www.almadenahnews.com/newss/news.php?c=118&id=38036
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_tunis02.html
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    @@ -1337,7 +1238,7 @@ Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
     # Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
    -			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    +			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
     			1:00	Tunisia	CE%sT
     
     # Uganda
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/antarctica b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
    index e31bada94fb..0cdac270861 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/antarctica
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
    @@ -21,19 +21,16 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
     # From Paul Eggert (1999-11-15):
     # To keep things manageable, we list only locations occupied year-round; see
    -# 
     # COMNAP - Stations and Bases
    -# 
    +# http://www.comnap.aq/comnap/comnap.nsf/P/Stations/
     # and
    -# 
     # Summary of the Peri-Antarctic Islands (1998-07-23)
    -# 
    +# http://www.spri.cam.ac.uk/bob/periant.htm
     # for information.
     # Unless otherwise specified, we have no time zone information.
     #
    @@ -78,19 +75,19 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
     
     # Argentina - year-round bases
     # Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
    -# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
    -# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
    -# Marambio, Seymour I, -6414-05637, since 1969-10-29
    +# Carlini, Potter Cove, King George Island, -6414-0602320, since 1982-01
    +# Esperanza, Hope Bay, -6323-05659, since 1952-12-17
    +# Marambio, -6414-05637, since 1969-10-29
     # Orcadas, Laurie I, -6016-04444, since 1904-02-22
    -# San Martin, Debenham I, -6807-06708, since 1951-03-21
    +# San Martín, Barry I, -6808-06706, since 1951-03-21
     #	(except 1960-03 / 1976-03-21)
     
     # Australia - territories
     # Heard Island, McDonald Islands (uninhabited)
     #	previously sealers and scientific personnel wintered
    -#	
     #	Margaret Turner reports
    -#	 (1999-09-30) that they're UTC+5, with no DST;
    +#	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;
     #	presumably this is when they have visitors.
     #
     # year-round bases
    @@ -107,14 +104,10 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
     # The changes occurred on 2009-10-18 at 02:00 (local times).
     #
     # Government source: (Australian Antarctic Division)
    -# 
     # http://www.aad.gov.au/default.asp?casid=37079
    -# 
     #
     # We have more background information here:
    -# 
     # http://www.timeanddate.com/news/time/antarctica-new-times.html
    -# 
     
     # From Steffen Thorsen (2010-03-10):
     # We got these changes from the Australian Antarctic Division: ...
    @@ -129,50 +122,49 @@ Rule	ChileAQ	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
     # - Mawson station stays on UTC+5.
     #
     # Background:
    -# 
     # http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
    -# 
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Antarctica/Casey	0	-	zzz	1969
    -			8:00	-	WST	2009 Oct 18 2:00
    -						# Western (Aus) Standard Time
    -			11:00	-	CAST	2010 Mar 5 2:00
    -						# Casey Time
    -			8:00	-	WST	2011 Oct 28 2:00
    +			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	-	WST
    +			8:00	-	AWST
     Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
    -			7:00	-	DAVT	1964 Nov # Davis Time
    +			7:00	-	DAVT	1964 Nov    # Davis Time
     			0	-	zzz	1969 Feb
    -			7:00	-	DAVT	2009 Oct 18 2:00
    +			7:00	-	DAVT	2009 Oct 18  2:00
     			5:00	-	DAVT	2010 Mar 10 20:00u
    -			7:00	-	DAVT	2011 Oct 28 2:00
    +			7:00	-	DAVT	2011 Oct 28  2:00
     			5:00	-	DAVT	2012 Feb 21 20:00u
     			7:00	-	DAVT
     Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
    -			6:00	-	MAWT	2009 Oct 18 2:00
    -						# Mawson Time
    +			6:00	-	MAWT	2009 Oct 18  2:00 # Mawson Time
     			5:00	-	MAWT
     # References:
    -# 
     # Casey Weather (1998-02-26)
    -# 
    -# 
    +# http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html
     # Davis Station, Antarctica (1998-02-26)
    -# 
    -# 
    +# http://www.antdiv.gov.au/aad/exop/sfo/davis/video.html
     # Mawson Station, Antarctica (1998-02-25)
    -# 
    +# http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html
    +
    +# Belgium - year-round base
    +# Princess Elisabeth, Queen Maud Land, -713412+0231200, since 2007
     
     # Brazil - year-round base
    -# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
    +# Ferraz, King George Island, -6205+05824, since 1983/4
    +
    +# Bulgaria - year-round base
    +# St. Kliment Ohridski, Livingston Island, -623829-0602153, since 1988
     
     # Chile - year-round bases and towns
     # Escudero, South Shetland Is, -621157-0585735, since 1994
    -# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
    -# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
    -# Capitan Arturo Prat, -6230-05941
    +# Frei Montalva, King George Island, -6214-05848, since 1969-03-07
    +# O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
    +# Prat, -6230-05941
     # Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
     # These locations have always used Santiago time; use TZ='America/Santiago'.
     
    @@ -180,31 +172,35 @@ Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
     # Great Wall, King George Island, -6213-05858, since 1985-02-20
     # Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
     
    -# France - year-round bases
    +# France - year-round bases (also see "France & Italy")
     #
     # From Antoine Leca (1997-01-20):
    -# Time data are from Nicole Pailleau at the IFRTP
    +# Time data entries are from Nicole Pailleau at the IFRTP
     # (French Institute for Polar Research and Technology).
    -# She confirms that French Southern Territories and Terre Adelie bases
    -# don't observe daylight saving time, even if Terre Adelie supplies came
    +# She confirms that French Southern Territories and Terre Adélie bases
    +# don't observe daylight saving time, even if Terre Adélie supplies came
     # from Tasmania.
     #
     # French Southern Territories with year-round inhabitants
     #
    -# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
    -# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
    -# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
    +# Alfred Faure, Possession Island, Crozet Islands, -462551+0515152, since 1964;
    +#	sealing & whaling stations operated variously 1802/1911+;
    +#	see Indian/Reunion.
    +#
    +# Martin-de-Viviès, Amsterdam Island, -374105+0773155, since 1950
    +# Port-aux-Français, Kerguelen Islands, -492110+0701303, since 1951;
     #	whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
     #
     # St Paul Island - near Amsterdam, uninhabited
     #	fishing stations operated variously 1819/1931
     #
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Indian/Kerguelen	0	-	zzz	1950	# Port-aux-Francais
    +Zone Indian/Kerguelen	0	-	zzz	1950 # Port-aux-Français
     			5:00	-	TFT	# ISO code TF Time
     #
     # year-round base in the main continent
    -# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
    +# Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11
    +#  (2005-12-05)
     #
     # Another base at Port-Martin, 50km east, began operation in 1947.
     # It was destroyed by fire on 1952-01-14.
    @@ -214,20 +210,22 @@ Zone Antarctica/DumontDUrville 0 -	zzz	1947
     			10:00	-	PMT	1952 Jan 14 # Port-Martin Time
     			0	-	zzz	1956 Nov
     			10:00	-	DDUT	# Dumont-d'Urville Time
    -# Reference:
    -# 
    -# Dumont d'Urville Station (2005-12-05)
    -# 
    +
    +# France & Italy - year-round base
    +# Concordia, -750600+1232000, since 2005
     
     # Germany - year-round base
    -# Georg von Neumayer, -7039-00815
    +# Neumayer III, -704080-0081602, since 2009
     
    -# India - year-round base
    -# Dakshin Gangotri, -7005+01200
    +# India - year-round bases
    +# Bharati, -692428+0761114, since 2012
    +# Maitri, -704558+0114356, since 1989
    +
    +# Italy - year-round base (also see "France & Italy")
    +# Zuchelli, Terra Nova Bay, -744140+1640647, since 1986
     
     # Japan - year-round bases
    -# Dome Fuji, -7719+03942
    -# Syowa, -690022+0393524
    +# Syowa (also known as Showa), -690022+0393524, since 1957
     #
     # From Hideyuki Suzuki (1999-02-06):
     # In all Japanese stations, +0300 is used as the standard time.
    @@ -239,11 +237,11 @@ Zone Antarctica/DumontDUrville 0 -	zzz	1947
     Zone Antarctica/Syowa	0	-	zzz	1957 Jan 29
     			3:00	-	SYOT	# Syowa Time
     # See:
    -# 
     # NIPR Antarctic Research Activities (1999-08-17)
    -# 
    +# http://www.nipr.ac.jp/english/ara01.html
     
     # S Korea - year-round base
    +# Jang Bogo, Terra Nova Bay, -743700+1641205 since 2014
     # King Sejong, King George Island, -6213-05847, since 1988
     
     # New Zealand - claims
    @@ -287,11 +285,14 @@ Rule	Troll	2005	max	-	Mar	lastSun	1:00u	2:00	CEST
     Rule	Troll	2004	max	-	Oct	lastSun	1:00u	0:00	UTC
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
    -     			0:00	Troll	%s
    +			0:00	Troll	%s
     
     # Poland - year-round base
     # Arctowski, King George Island, -620945-0582745, since 1977
     
    +# Romania - year-bound base
    +# Law-Racoviță, Larsemann Hills, -692319+0762251, since 1986
    +
     # Russia - year-round bases
     # Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
     # Mirny, Davis coast, -6633+09301, since 1956-02
    @@ -301,8 +302,8 @@ Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
     #	year-round from 1960/61 to 1992
     
     # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
    -# 
    -# From Craig Mundell (1994-12-15):
    +# From Craig Mundell (1994-12-15):
    +# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP
     # Vostok, which is one of the Russian stations, is set on the same
     # time as Moscow, Russia.
     #
    @@ -317,7 +318,7 @@ Zone Antarctica/Troll	0	-	zzz	2005 Feb 12
     #
     # From Paul Eggert (2001-05-04):
     # This seems to be hopelessly confusing, so I asked Lee Hotz about it
    -# in person.  He said that some Antartic locations set their local
    +# in person.  He said that some Antarctic locations set their local
     # time so that noon is the warmest part of the day, and that this
     # changes during the year and does not necessarily correspond to mean
     # solar noon.  So the Vostok time might have been whatever the clocks
    @@ -329,9 +330,12 @@ Zone Antarctica/Vostok	0	-	zzz	1957 Dec 16
     
     # S Africa - year-round bases
     # Marion Island, -4653+03752
    -# Sanae, -7141-00250
    +# SANAE IV, Vesleskarvet, Queen Maud Land, -714022-0025026, since 1997
     
    -# UK
    +# Ukraine - year-round base
    +# Vernadsky (formerly Faraday), Galindez Island, -651445-0641526, since 1954
    +
    +# United Kingdom
     #
     # British Antarctic Territories (BAT) claims
     # South Orkney Islands
    @@ -387,7 +391,7 @@ Zone Antarctica/Palmer	0	-	zzz	1965
     # but that he found it more convenient to keep GMT+12
     # as supplies for the station were coming from McMurdo Sound,
     # which was on GMT+12 because New Zealand was on GMT+12 all year
    -# at that time (1957).  (Source: Siple's book 90 degrees SOUTH.)
    +# at that time (1957).  (Source: Siple's book 90 Degrees South.)
     #
     # From Susan Smith
     # http://www.cybertours.com/whs/pole10.html
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia
    index 595c8ed7245..906c0a97cda 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/asia
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia
    @@ -21,13 +21,13 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
     # From Paul Eggert (2013-08-11):
     #
    @@ -49,13 +49,17 @@
     # I found in the UCLA library.
     #
     # For data circa 1899, a common source is:
    -# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
    -# .
    +# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
    +# http://www.jstor.org/stable/1774359
    +#
    +# For Russian data circa 1919, a source is:
    +# Byalokoz EL. New Counting of Time in Russia since July 1, 1919.
    +# (See the 'europe' file for a fuller citation.)
     #
     # A reliable and entertaining source about time zones is
     # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
     #
    -# I invented the abbreviations marked `*' in the following table;
    +# I invented the abbreviations marked '*' in the following table;
     # the rest are from earlier versions of this file, or from other sources.
     # Corrections are welcome!
     #	     std  dst
    @@ -70,13 +74,14 @@
     #	7:00 WIB	west Indonesia (Waktu Indonesia Barat)
     #	8:00 WITA	central Indonesia (Waktu Indonesia Tengah)
     #	8:00 CST	China
    -#	9:00 CJT	Central Japanese Time (1896/1937)*
    +#	8:00 JWST	Western Standard Time (Japan, 1896/1937)*
    +#	9:00 JCST	Central Standard Time (Japan, 1896/1937)
     #	9:00 WIT	east Indonesia (Waktu Indonesia Timur)
     #	9:00 JST  JDT	Japan
     #	9:00 KST  KDT	Korea
    -#	9:30 CST	(Australian) Central Standard Time
    +#	9:30 ACST	Australian Central Standard Time
     #
    -# See the `europe' file for Russia and Turkey in Asia.
    +# See the 'europe' file for Russia and Turkey in Asia.
     
     # From Guy Harris:
     # Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
    @@ -86,7 +91,7 @@
     
     ###############################################################################
     
    -# These rules are stolen from the `europe' file.
    +# These rules are stolen from the 'europe' file.
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
     Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
    @@ -138,11 +143,11 @@ Zone	Asia/Kabul	4:36:48 -	LMT	1890
     # 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
    +			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
    +			3:00 RussiaAsia	AM%sT	1995 Sep 24  2:00s
     			4:00	-	AMT	1997
    -			4:00 RussiaAsia	AM%sT	2012 Mar 25 2:00s
    +			4:00 RussiaAsia	AM%sT	2012 Mar 25  2:00s
     			4:00	-	AMT
     
     # Azerbaijan
    @@ -155,16 +160,16 @@ Rule	Azer	1997	max	-	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
    +			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 lastSat 23:00
    -			4:00	-	AZT	1996 # Azerbaijan time
    +			4:00	-	AZT	1996     # Azerbaijan Time
     			4:00	EUAsia	AZ%sT	1997
     			4:00	Azer	AZ%sT
     
     # Bahrain
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
    +Zone	Asia/Bahrain	3:22:20 -	LMT	1920     # Manamah
     			4:00	-	GST	1972 Jun
     			3:00	-	AST
     
    @@ -174,13 +179,8 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
     # Daylight Saving Time from June 16 to Sept 30
     #
     # Bangladesh to introduce daylight saving time likely from June 16
    -# 
     # http://www.asiantribune.com/?q=node/17288
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_bangladesh02.html
    -# 
     #
     # "... Bangladesh government has decided to switch daylight saving time from
     # June
    @@ -195,17 +195,11 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
     # the 19th and 20th, and they have not set the end date yet.
     #
     # Some sources:
    -# 
     # http://in.reuters.com/article/southAsiaNews/idINIndia-40017620090601
    -# 
    -# 
     # http://bdnews24.com/details.php?id=85889&cid=2
    -# 
     #
     # Our wrap-up:
    -# 
     # http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
    -# 
     
     # From A. N. M. Kamrus Saadat (2009-06-15):
     # Finally we've got the official mail regarding DST start time where DST start
    @@ -220,13 +214,8 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
     #
     # Following report by same newspaper-"The Daily Star Friday":
     # "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
    -# 
     # http://www.thedailystar.net/newDesign/news-details.php?nid=107021
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
    -# 
     
     # From Steffen Thorsen (2009-10-13):
     # IANS (Indo-Asian News Service) now reports:
    @@ -235,22 +224,15 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
     # "continue for an indefinite period."
     #
     # One of many places where it is published:
    -# 
     # http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
    -# 
     
     # From Alexander Krivenyshev (2009-12-24):
     # According to Bangladesh newspaper "The Daily Star,"
     # Bangladesh will change its clock back to Standard Time on Dec 31, 2009.
     #
     # Clock goes back 1-hr on Dec 31 night.
    -# 
     # http://www.thedailystar.net/newDesign/news-details.php?nid=119228
    -# 
    -# and
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_bangladesh05.html
    -# 
     #
     # "...The government yesterday decided to put the clock back by one hour
     # on December 31 midnight and the new time will continue until March 31,
    @@ -260,17 +242,12 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
     # From Alexander Krivenyshev (2010-03-22):
     # According to Bangladesh newspaper "The Daily Star,"
     # Cabinet cancels Daylight Saving Time
    -# 
     # http://www.thedailystar.net/newDesign/latest_news.php?nid=22817
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_bangladesh06.html
    -# 
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Dhaka	2009	only	-	Jun	19	23:00	1:00	S
    -Rule	Dhaka	2009	only	-	Dec	31	23:59	0	-
    +Rule	Dhaka	2009	only	-	Dec	31	24:00	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Dhaka	6:01:40 -	LMT	1890
    @@ -301,7 +278,7 @@ Zone	Indian/Chagos	4:49:40	-	LMT	1907
     
     # Brunei
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
    +Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar # Bandar Seri Begawan
     			7:30	-	BNT	1933
     			8:00	-	BNT
     
    @@ -310,16 +287,16 @@ Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
     # 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
    -			6:24:40	-	RMT	1920	   # Rangoon Mean Time?
    -			6:30	-	BURT	1942 May   # Burma Time
    -			9:00	-	JST	1945 May 3
    -			6:30	-	MMT		   # Myanmar Time
    +Zone	Asia/Rangoon	6:24:40 -	LMT	1880        # or Yangon
    +			6:24:40	-	RMT	1920        # Rangoon Mean Time?
    +			6:30	-	BURT	1942 May    # Burma Time
    +			9:00	-	JST	1945 May  3
    +			6:30	-	MMT	# Myanmar Time
     
     # Cambodia
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
    -			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
     			7:00	-	ICT	1912 May
     			8:00	-	ICT	1931 May
     			7:00	-	ICT
    @@ -332,12 +309,12 @@ Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
     # From Bob Devine (1988-01-28):
     # No they don't.  See TIME mag, 1986-02-17 p.52.  Even though
     # China is across 4 physical time zones, before Feb 1, 1986 only the
    -# Peking (Bejing) time zone was recognized.  Since that date, China
    -# has two of 'em -- Peking's and Urumqi (named after the capital of
    +# Peking (Beijing) time zone was recognized.  Since that date, China
    +# has two of 'em - Peking's and Ürümqi (named after the capital of
     # the Xinjiang Uyghur Autonomous Region).  I don't know about DST for it.
     #
     # . . .I just deleted the DST table and this editor makes it too
    -# painful to suck in another copy..  So, here is what I have for
    +# painful to suck in another copy.  So, here is what I have for
     # DST start/end dates for Peking's time zone (info from AP):
     #
     #     1986 May 4 - Sept 14
    @@ -347,15 +324,16 @@ Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
     # CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
     # CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
     
    -# From Paul Eggert (2006-03-22):
    -# Shanks & Pottenger write that China (except for Hong Kong and Macau)
    -# has had a single time zone since 1980 May 1, observing summer DST
    -# from 1986 through 1991; this contradicts Devine's
    -# note about Time magazine, though apparently _something_ happened in 1986.
    -# Go with Shanks & Pottenger for now.  I made up names for the other
    -# pre-1980 time zones.
    +# From Paul Eggert (2008-02-11):
    +# Jim Mann, "A clumsy embrace for another western custom: China on daylight
    +# time - sort of", Los Angeles Times, 1986-05-05 ... [says] that China began
    +# observing daylight saving time in 1986.
     
    -# From Shanks & Pottenger:
    +# From Paul Eggert (2014-06-30):
    +# Shanks & Pottenger have China switching to a single time zone in 1980, but
    +# this doesn't seem to be correct.  They also write that China observed summer
    +# DST from 1986 through 1991, which seems to match the above commentary, so
    +# go with them for DST rules as follows:
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
     Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
    @@ -369,7 +347,7 @@ Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
     # historic timezones from some Taiwan websites.  And yes, there are official
     # Chinese names for these locales (before 1949).
     #
    -# From Jesper Norgaard Welen (2006-07-14):
    +# From Jesper Nørgaard Welen (2006-07-14):
     # I have investigated the timezones around 1970 on the
     # http://www.astro.com/atlas site [with provinces and county
     # boundaries summarized below]....  A few other exceptions were two
    @@ -380,65 +358,97 @@ Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
     # (could be true), for the moment I am assuming that those two
     # counties are mistakes in the astro.com data.
     
    -# From Paul Eggert (2008-02-11):
    -# I just now checked Google News for western news sources that talk
    -# about China's single time zone, and couldn't find anything before 1986
    -# talking about China being in one time zone.  (That article was: Jim
    -# Mann, "A clumsy embrace for another western custom: China on daylight
    -# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
    -# article confirms the tz database's data claiming that China began
    -# observing daylight saving time in 1986.
    +# From Paul Eggert (2014-06-30):
    +# Alois Treindl kindly sent me translations of the following two sources:
     #
    -# From Thomas S. Mullaney (2008-02-11):
    -# I think you're combining two subjects that need to treated
    -# separately: daylight savings (which, you're correct, wasn't
    -# implemented until the 1980s) and the unified time zone centered near
    -# Beijing (which was implemented in 1949). Briefly, there was also a
    -# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was
    -# ceased, and the second eventually recognized (again, in the 1980s).
    +# (1)
    +# Guo Qingsheng (National Time-Service Center, CAS, Xi'an 710600, China)
    +# Beijing Time at the Beginning of the PRC
    +# China Historical Materials of Science and Technology
    +# (Zhongguo ke ji shi liao, 中国科技史料), Vol. 24, No. 1 (2003)
    +# It gives evidence that at the beginning of the PRC, Beijing time was
    +# officially apparent solar time!  However, Guo also says that the
    +# evidence is dubious, as the relevant institute of astronomy had not
    +# been taken over by the PRC yet.  It's plausible that apparent solar
    +# time was announced but never implemented, and that people continued
    +# to use UT+8.  As the Shanghai radio station (and I presume the
    +# observatory) was still under control of French missionaries, it
    +# could well have ignored any such mandate.
     #
    -# From Paul Eggert (2008-06-30):
    -# There seems to be a good chance China switched to a single time zone in 1949
    -# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
    -# reliable documentary source saying so yet, so for now we still go with
    -# Shanks & Pottenger.
    -
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -# Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
    +# (2)
    +# Guo Qing-sheng (Shaanxi Astronomical Observatory, CAS, Xi'an 710600, China)
    +# A Study on the Standard Time Changes for the Past 100 Years in China
    +# [undated and unknown publication location]
    +# It says several things:
    +#   * The Qing dynasty used local apparent solar time throughout China.
    +#   * The Republic of China instituted Beijing mean solar time effective
    +#     the official calendar book of 1914.
    +#   * The French Concession in Shanghai set up signal stations in
    +#     French docks in the 1890s, controlled by Xujiahui (Zikawei)
    +#     Observatory and set to local mean time.
    +#   * "From the end of the 19th century" it changed to UT+8.
    +#   * Chinese Customs (by then reduced to a tool of foreign powers)
    +#     eventually standardized on this time for all ports, and it
    +#     became used by railways as well.
    +#   * In 1918 the Central Observatory proposed dividing China into
    +#     five time zones (see below for details).  This caught on
    +#     at first only in coastal areas observing UT+8.
    +#   * During WWII all of China was in theory was at UT+7.  In practice
    +#     this was ignored in the west, and I presume was ignored in
    +#     Japanese-occupied territory.
    +#   * Japanese-occupied Manchuria was at UT+9, i.e., Japan time.
    +#   * The five-zone plan was resurrected after WWII and officially put into
    +#     place (with some modifications) in March 1948.  It's not clear
    +#     how well it was observed in areas under Nationalist control.
    +#   * The People's Liberation Army used UT+8 during the civil war.
    +#
    +# An AP article "Shanghai Internat'l Area Little Changed" in the
    +# 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.
    +#
    +# 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.
    +# This has now been simplified to the two entries Asia/Shanghai and
    +# Asia/Urumqi, with the others being links for backward compatibility.
    +# 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
    +# Asia/Harbin (currently a link to Asia/Shanghai)
     # Heilongjiang (except Mohe county), Jilin
    -Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
    -			8:30	-	CHAT	1932 Mar # Changbai Time
    -			8:00	-	CST	1940
    -			9:00	-	CHAT	1966 May
    -			8:30	-	CHAT	1980 May
    -			8:00	PRC	C%sT
    -# Zhongyuan Time ("Central plain Time")
    +#
    +# Zhongyuan Time ("Central plain Time") UT+8
    +# Asia/Shanghai
     # most of China
    -# Milne gives 8:05:56.7; round to nearest.
    -Zone	Asia/Shanghai	8:05:57	-	LMT	1928
    -			8:00	Shang	C%sT	1949
    -			8:00	PRC	C%sT
    -# Long-shu Time (probably due to Long and Shu being two names of that area)
    +# 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".
    +#
    +# Long-shu Time (probably due to Long and Shu being two names of that area) UT+7
    +# 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.
    -Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
    -			7:00	-	LONT	1980 May # Long-shu Time
    -			8:00	PRC	C%sT
    -# Xin-zang Time ("Xinjiang-Tibet Time")
    +#
    +# Xin-zang Time ("Xinjiang-Tibet Time") UT+6
    +# Asia/Urumqi
    +# This currently represents Kunlun Time as well,
    +# as apparently the two regions have been the same since 1970.
     # The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
     # the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
     # Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
     # east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
    -# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
    +# east Xinjiang, including Ürümqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
     # Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
     # Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
     # Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
    -Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
    -			6:00	-	URUT	1980 May # Urumqi Time
    -			8:00	PRC	C%sT
    -# Kunlun Time
    +#
    +# Kunlun Time UT+5.5
    +# 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,
     # Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
    @@ -455,9 +465,9 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
     # population of Xinjiang, typically use "Xinjiang time" which is two
     # hours behind Beijing time, or UTC +0600. The government of the Xinjiang
     # Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as
    -# local governments such as the Urumqi city government use both times in
    +# local governments such as the Ürümqi city government use both times in
     # publications, referring to what is popularly called Xinjiang time as
    -# "Urumqi time." When Uyghurs make an appointment in the Uyghur language
    +# "Ürümqi time." When Uyghurs make an appointment in the Uyghur language
     # they almost invariably use Xinjiang time.
     #
     # (Their ethnic Han compatriots would typically have no clue of its
    @@ -469,21 +479,6 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
     # the province not having dual times but four times in use at the same
     # time. Some areas remained on standard Xinjiang time or Beijing time and
     # others moving their clocks ahead.)
    -#
    -# ...an example of an official website using of Urumqi time.
    -#
    -# The first few lines of the Google translation of
    -# 
    -# http://www.fjysgl.gov.cn/show.aspx?id=2379&cid=39
    -# 
    -# (retrieved 2009-10-13)
    -# > Urumqi fire seven people are missing the alleged losses of at least
    -# > 500 million yuan
    -# >
    -# > (Reporter Dong Liu) the day before 20:20 or so (Urumqi Time 18:20),
    -# > Urumqi City Department of International Plaza Luther Qiantang River
    -# > burst fire. As of yesterday, 18:30, Urumqi City Fire officers and men
    -# > have worked continuously for 22 hours...
     
     # From Luther Ma (2009-11-19):
     # With the risk of being redundant to previous answers these are the most common
    @@ -494,7 +489,7 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
     # 3. Urumqi...
     # 4. Kashgar...
     # ...
    -# 5. It seems that Uyghurs in Urumqi has been using Xinjiang since at least the
    +# 5. It seems that Uyghurs in Ürümqi has been using Xinjiang since at least the
     # 1960's. I know of one Han, now over 50, who grew up in the surrounding
     # countryside and used Xinjiang time as a child.
     #
    @@ -506,10 +501,55 @@ Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
     # Autonomous Region under the PRC. (Before that Uyghurs, of course, would also
     # not be using Beijing time, but some local time.)
     
    -Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
    -			5:30	-	KAST	1940	 # Kashgar Time
    -			5:00	-	KAST	1980 May
    +# From David Cochrane (2014-03-26):
    +# Just a confirmation that Ürümqi time was implemented in Ürümqi on 1 Feb 1986:
    +# http://content.time.com/time/magazine/article/0,9171,960684,00.html
    +
    +# From Luther Ma (2014-04-22):
    +# I have interviewed numerous people of various nationalities and from
    +# different localities in Xinjiang and can confirm the information in Guo's
    +# report regarding Xinjiang, as well as the Time article reference by David
    +# Cochrane.  Whether officially recognized or not (and both are officially
    +# recognized), two separate times have been in use in Xinjiang since at least
    +# the Cultural Revolution: Xinjiang Time (XJT), aka Ürümqi Time or local time;
    +# and Beijing Time.  There is no confusion in Xinjiang as to which name refers
    +# to which time. Both are widely used in the province, although in some
    +# population groups might be use one to the exclusion of the other.  The only
    +# problem is that computers and smart phones list Ürümqi (or Kashgar) as
    +# 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,
    +# 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.
    +#
    +# Xinjiang Time is well-documented as being officially recognized.  E.g., see
    +# "The Working-Calendar for The Xinjiang Uygur Autonomous Region Government"
    +#  (2014-04-22).
    +# Unfortunately, we have no good records of time in Xinjiang before 1986.
    +# During the 20th century parts of Xinjiang were ruled by the Qing dynasty,
    +# the Republic of China, various warlords, the First and Second East Turkestan
    +# 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,
    +# 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
    +# that the sort of users who prefer Asia/Urumqi now typically ignored the
    +# UT+8 mandate back then.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Beijing time, used throughout China; represented by Shanghai.
    +Zone	Asia/Shanghai	8:05:43	-	LMT	1901
    +			8:00	Shang	C%sT	1949
     			8:00	PRC	C%sT
    +# Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi
    +# / Wulumuqi.  (Please use Asia/Shanghai if you prefer Beijing time.)
    +Zone	Asia/Urumqi	5:50:20	-	LMT	1928
    +			6:00	-	XJT
     
     
     # Hong Kong (Xianggang)
    @@ -524,15 +564,11 @@ Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
     # and incorrect rules. Although the exact switch over time is missing, I
     # think 3:30 is correct. The official DST record for Hong Kong can be
     # obtained from
    -# 
     # http://www.hko.gov.hk/gts/time/Summertime.htm
    -# .
     
     # From Arthur David Olson (2009-10-28):
     # Here are the dates given at
    -# 
     # http://www.hko.gov.hk/gts/time/Summertime.htm
    -# 
     # as of 2009-10-28:
     # Year        Period
     # 1941        1 Apr to 30 Sep
    @@ -612,35 +648,113 @@ Zone	Asia/Hong_Kong	7:36:42 -	LMT	1904 Oct 30
     
     # Taiwan
     
    -# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
    -# was still controlled by Japan.  This is hard to believe, but we don't
    -# have any other information.
    -
     # From smallufo (2010-04-03):
    -# According to Taiwan's CWB,
    -# 
    +# According to Taiwan's CWB [Central Weather Bureau],
     # http://www.cwb.gov.tw/V6/astronomy/cdata/summert.htm
    -# 
     # Taipei has DST in 1979 between July 1st and Sep 30.
     
    -# From Arthur David Olson (2010-04-07):
    -# Here's Google's translation of the table at the bottom of the "summert.htm" page:
    -# Decade 	                                                    Name                      Start and end date
    -# Republic of China 34 years to 40 years (AD 1945-1951 years) Summer Time               May 1 to September 30
    -# 41 years of the Republic of China (AD 1952)                 Daylight Saving Time      March 1 to October 31
    -# Republic of China 42 years to 43 years (AD 1953-1954 years) Daylight Saving Time      April 1 to October 31
    -# In the 44 years to 45 years (AD 1955-1956 years)            Daylight Saving Time      April 1 to September 30
    -# Republic of China 46 years to 48 years (AD 1957-1959)       Summer Time               April 1 to September 30
    -# Republic of China 49 years to 50 years (AD 1960-1961)       Summer Time               June 1 to September 30
    -# Republic of China 51 years to 62 years (AD 1962-1973 years) Stop Summer Time
    -# Republic of China 63 years to 64 years (1974-1975 AD)       Daylight Saving Time      April 1 to September 30
    -# Republic of China 65 years to 67 years (1976-1978 AD)       Stop Daylight Saving Time
    -# Republic of China 68 years (AD 1979)                        Daylight Saving Time      July 1 to September 30
    -# Republic of China since 69 years (AD 1980)                  Stop Daylight Saving Time
    +# From Yu-Cheng Chuang (2013-07-12):
    +# On Dec 28, 1895, the Meiji Emperor announced Ordinance No. 167 of
    +# Meiji Year 28 "The clause about standard time", mentioned that
    +# Taiwan and Penghu Islands, as well as Yaeyama and Miyako Islands
    +# (both in Okinawa) adopt the Western Standard Time which is based on
    +# 120E. The adoption began from Jan 1, 1896. The original text can be
    +# found on Wikisource:
    +# http://ja.wikisource.org/wiki/標準時ニ關スル件_(公布時)
    +# ... This could be the first adoption of time zone in Taiwan, because
    +# during the Qing Dynasty, it seems that there was no time zone
    +# declared officially.
    +#
    +# Later, in the beginning of World War II, on Sep 25, 1937, the Showa
    +# Emperor announced Ordinance No. 529 of Showa Year 12 "The clause of
    +# revision in the ordinance No. 167 of Meiji year 28 about standard
    +# time", in which abolished the adoption of Western Standard Time in
    +# western islands (listed above), which means the whole Japan
    +# territory, including later occupations, adopt Japan Central Time
    +# (UTC+9). The adoption began on Oct 1, 1937. The original text can
    +# be found on Wikisource:
    +# http://ja.wikisource.org/wiki/明治二十八年勅令第百六十七號標準時ニ關スル件中改正ノ件
    +#
    +# That is, the time zone of Taipei switched to UTC+9 on Oct 1, 1937.
    +
    +# From Yu-Cheng Chuang (2014-07-02):
    +# I've found more evidence about when the time zone was switched from UTC+9
    +# back to UTC+8 after WW2.  I believe it was on Sep 21, 1945.  In a document
    +# during Japanese era [1] in which the officer told the staff to change time
    +# zone back to Western Standard Time (UTC+8) on Sep 21.  And in another
    +# history page of National Cheng Kung University [2], on Sep 21 there is a
    +# note "from today, switch back to Western Standard Time".  From these two
    +# materials, I believe that the time zone change happened on Sep 21.  And
    +# today I have found another monthly journal called "The Astronomical Herald"
    +# from The Astronomical Society of Japan [3] in which it mentioned the fact
    +# that:
    +#
    +# 1. Standard Time of the Country (Japan) was adopted on Jan 1, 1888, using
    +# the time at 135E (GMT+9)
    +#
    +# 2. Standard Time of the Country was renamed to Central Standard Time, on Jan
    +# 1, 1898, and on the same day, the new territories Taiwan and Penghu islands,
    +# as well as Yaeyama and Miyako islands, adopted a new time zone called
    +# Western Standard Time, which is in GMT+8.
    +#
    +# 3. Western Standard Time was deprecated on Sep 30, 1937. From then all the
    +# territories of Japan adopted the same time zone, which is Central Standard
    +# Time.
    +#
    +# [1] Academica Historica, Taiwan:
    +# http://163.29.208.22:8080/govsaleShowImage/connect_img.php?s=00101738900090036&e=00101738900090037
    +# [2] Nat'l Cheng Kung University 70th Anniversary Special Site:
    +# http://www.ncku.edu.tw/~ncku70/menu/001/01_01.htm
    +# [3] Yukio Niimi, The Standard Time in Japan (1997), p.475:
    +# http://www.asj.or.jp/geppou/archive_open/1997/pdf/19971001c.pdf
    +
    +# Yu-Cheng Chuang (2014-07-03):
    +# I finally have found the real official gazette about changing back to
    +# Western Standard Time on Sep 21 in Taiwan.  It's Taiwan Governor-General
    +# Bulletin No. 386 in Showa 20 years (1945), published on Sep 19, 1945. [1] ...
    +# [It] abolishes Bulletin No. 207 in Showa 12 years (1937), which is a local
    +# bulletin in Taiwan for that Ordinance No. 529. It also mentioned that 1am on
    +# Sep 21, 1945 will be 12am on Sep 21.  I think this bulletin is much more
    +# official than the one I mentioned in my first mail, because it's from the
    +# top-level government in Taiwan. If you're going to quote any resource, this
    +# would be a good one.
    +# [1] Taiwan Governor-General Gazette, No. 1018, Sep 19, 1945:
    +# http://db2.th.gov.tw/db2/view/viewImg.php?imgcode=0072031018a&num=19&bgn=019&end=019&otherImg=&type=gener
    +
    +# From Yu-Cheng Chuang (2014-07-02):
    +# In 1946, DST in Taiwan was from May 15 and ended on Sep 30. The info from
    +# Central Weather Bureau website was not correct.
    +#
    +# Original Bulletin:
    +# http://subtpg.tpg.gov.tw/og/image2.asp?f=03502F0AKM1AF
    +# http://subtpg.tpg.gov.tw/og/image2.asp?f=0350300AKM1B0 (cont.)
    +#
    +# In 1947, DST in Taiwan was expanded to Oct 31. There is a backup of that
    +# telegram announcement from Taiwan Province Government:
    +#
    +# http://subtpg.tpg.gov.tw/og/image2.asp?f=0360310AKZ431
    +#
    +# Here is a brief translation:
    +#
    +#   The Summer Time this year is adopted from midnight Apr 15 until Sep 20
    +#   midnight. To save (energy?) consumption, we're expanding Summer Time
    +#   adoption till Oct 31 midnight.
    +#
    +# The Central Weather Bureau website didn't mention that, however it can
    +# 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
    +# until 1945-09-21 at 01:00, overriding Shanks & Pottenger.
    +# Likewise, use Yu-Cheng Chuang's data for DST in Taiwan.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
    -Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
    +Rule	Taiwan	1946	only	-	May	15	0:00	1:00	D
    +Rule	Taiwan	1946	only	-	Oct	1	0:00	0	S
    +Rule	Taiwan	1947	only	-	Apr	15	0:00	1:00	D
    +Rule	Taiwan	1947	only	-	Nov	1	0:00	0	S
    +Rule	Taiwan	1948	1951	-	May	1	0:00	1:00	D
    +Rule	Taiwan	1948	1951	-	Oct	1	0:00	0	S
     Rule	Taiwan	1952	only	-	Mar	1	0:00	1:00	D
     Rule	Taiwan	1952	1954	-	Nov	1	0:00	0	S
     Rule	Taiwan	1953	1959	-	Apr	1	0:00	1:00	D
    @@ -648,11 +762,14 @@ Rule	Taiwan	1955	1961	-	Oct	1	0:00	0	S
     Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
     Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
     Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
    -Rule	Taiwan	1979	only	-	Jun	30	0:00	1:00	D
    -Rule	Taiwan	1979	only	-	Sep	30	0:00	0	S
    +Rule	Taiwan	1979	only	-	Jul	1	0:00	1:00	D
    +Rule	Taiwan	1979	only	-	Oct	1	0:00	0	S
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
    +# Taipei or Taibei or T'ai-pei
    +Zone	Asia/Taipei	8:06:00 -	LMT	1896 Jan  1
    +			8:00	-	JWST	1937 Oct  1
    +			9:00	-	JST	1945 Sep 21  1:00
     			8:00	Taiwan	C%sT
     
     # Macau (Macao, Aomen)
    @@ -672,7 +789,7 @@ Rule	Macau	1975	1977	-	Apr	Sun>=15	3:30	1:00	S
     Rule	Macau	1978	1980	-	Apr	Sun>=15	0:00	1:00	S
     Rule	Macau	1978	1980	-	Oct	Sun>=15	0:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Macau	7:34:20 -	LMT	1912
    +Zone	Asia/Macau	7:34:20 -	LMT	1912 Jan  1
     			8:00	Macau	MO%sT	1999 Dec 20 # return to China
     			8:00	PRC	C%sT
     
    @@ -721,7 +838,7 @@ Link	Asia/Nicosia	Europe/Nicosia
     # republic has changed its time zone back to that of Moscow.  As a result it
     # is now just four hours ahead of Greenwich Mean Time, rather than five hours
     # ahead.  The switch was decreed by the pro-Western president of Georgia,
    -# Mikhail Saakashvili, who said the change was partly prompted by the process
    +# Mikheil Saakashvili, who said the change was partly prompted by the process
     # of integration into Europe.
     
     # From Teimuraz Abashidze (2005-11-07):
    @@ -734,29 +851,31 @@ Link	Asia/Nicosia	Europe/Nicosia
     # I don't know what can be done, especially knowing that some years ago our
     # DST rules where changed THREE TIMES during one month.
     
    +# Milne 1899 says Tbilisi (Tiflis) time was 2:59:05.7.
    +# Byalokoz 1919 says Georgia was 2:59:11.
    +# Go with Byalokoz.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
    -			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
    +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
    +			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 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
    +			3:00 RussiaAsia	GE%sT	2005 Mar lastSun  2:00
     			4:00	-	GET
     
     # East Timor
     
     # See Indonesia for the 1945 transition.
     
    -# From Joao Carrascalao, brother of the former governor of East Timor, in
    -# 
    +# From João Carrascalão, brother of the former governor of East Timor, in
     # East Timor may be late for its millennium
    -#  (1999-12-26/31):
    +#  (1999-12-26/31):
     # Portugal tried to change the time forward in 1974 because the sun
     # rises too early but the suggestion raised a lot of problems with the
     # Timorese and I still don't think it would work today because it
    @@ -766,25 +885,25 @@ Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
     # We don't have any record of the above attempt.
     # Most likely our records are incomplete, but we have no better data.
     
    -# 
     # From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
    -# (2000-08-16):
    +# http://www.hri.org/news/world/undh/2000/00-08-16.undh.html
    +# (2000-08-16):
     # The Cabinet of the East Timor Transition Administration decided
     # today to advance East Timor's time by one hour.  The time change,
     # which will be permanent, with no seasonal adjustment, will happen at
     # midnight on Saturday, September 16.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Dili	8:22:20 -	LMT	1912
    +Zone	Asia/Dili	8:22:20 -	LMT	1912 Jan  1
     			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
     			9:00	-	JST	1945 Sep 23
     			9:00	-	TLT	1976 May  3
    -			8:00	-	WITA	2000 Sep 17 00:00
    +			8:00	-	WITA	2000 Sep 17  0:00
     			9:00	-	TLT
     
     # India
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
    +Zone	Asia/Kolkata	5:53:28 -	LMT	1880        # Kolkata
     			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
     			6:30	-	BURT	1942 May 15 # Burma Time
     			5:30	-	IST	1942 Sep
    @@ -798,7 +917,7 @@ Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
     # Indonesia
     #
     # From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
    -# 
    +# http://www.sumatera-inc.com/go_to_invest/about_indonesia.asp#standtime
     # says that Indonesia's time zones changed on 1988-01-01.  Looking at some
     # time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
     # and Kalimantan Tengah) switching from UTC+8 to UTC+7.
    @@ -810,7 +929,7 @@ Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
     # other formal surrender ceremonies were September 9, 11, and 13, plus
     # September 12 for the regional surrender to Mountbatten in Singapore.
     # These would be the earliest possible times for a change.
    -# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
    +# 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
     # (Hollandia).  For now, assume all Indonesian locations other than Jayapura
    @@ -835,7 +954,7 @@ Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
     # Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
     # but this must be a typo.
     			7:07:12	-	BMT	1923 Dec 31 23:47:12 # Batavia
    -			7:20	-	JAVT	1932 Nov	 # Java Time
    +			7:20	-	JAVT	1932 Nov    # Java Time
     			7:30	-	WIB	1942 Mar 23
     			9:00	-	JST	1945 Sep 23
     			7:30	-	WIB	1948 May
    @@ -861,7 +980,7 @@ Zone Asia/Makassar	7:57:36 -	LMT	1920
     # Maluku Islands, West Papua, Papua
     Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
     			9:00	-	WIT	1944 Sep  1
    -			9:30	-	CST	1964
    +			9:30	-	ACST	1964
     			9:00	-	WIT
     
     # Iran
    @@ -927,7 +1046,7 @@ Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
     # Several of my users have reported that Iran will not observe DST anymore:
     # http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
     #
    -# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
    +# From Reuters (2007-09-16), with a heads-up from Jesper Nørgaard Welen:
     # ... the Guardian Council ... approved a law on Sunday to re-introduce
     # daylight saving time ...
     # http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
    @@ -993,7 +1112,7 @@ Rule	Iran	2036	2037	-	Mar	21	0:00	1:00	D
     Rule	Iran	2036	2037	-	Sep	21	0:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Tehran	3:25:44	-	LMT	1916
    -			3:25:44	-	TMT	1946	# Tehran Mean Time
    +			3:25:44	-	TMT	1946     # Tehran Mean Time
     			3:30	-	IRST	1977 Nov
     			4:00	Iran	IR%sT	1979
     			3:30	Iran	IR%sT
    @@ -1018,17 +1137,11 @@ Zone	Asia/Tehran	3:25:44	-	LMT	1916
     # From Steffen Thorsen (2008-03-10):
     # The cabinet in Iraq abolished DST last week, according to the following
     # news sources (in Arabic):
    -# 
     # http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
    -# 
    -# 
     # http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
    -# 
     #
     # We have published a short article in English about the change:
    -# 
     # http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
    -# 
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
    @@ -1037,14 +1150,14 @@ Rule	Iraq	1983	only	-	Mar	31	0:00	1:00	D
     Rule	Iraq	1984	1985	-	Apr	1	0:00	1:00	D
     Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
     Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
    -# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
    +# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the ':01' is a typo.
     # Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
     #
     Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
     Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Baghdad	2:57:40	-	LMT	1890
    -			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
    +			2:57:36	-	BMT	1918     # Baghdad Mean Time?
     			3:00	-	AST	1982 May
     			3:00	Iraq	A%sT
     
    @@ -1272,7 +1385,7 @@ Rule	Zion	2013	max	-	Oct	lastSun	2:00	0	S
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Jerusalem	2:20:54 -	LMT	1880
    -			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
    +			2:20:40	-	JMT	1918 # Jerusalem Mean Time?
     			2:00	Zion	I%sT
     
     
    @@ -1281,15 +1394,15 @@ Zone	Asia/Jerusalem	2:20:54 -	LMT	1880
     
     # Japan
     
    -# `9:00' and `JST' is from Guy Harris.
    +# '9:00' and 'JST' is from Guy Harris.
     
     # From Paul Eggert (1995-03-06):
     # Today's _Asahi Evening News_ (page 4) reports that Japan had
    -# daylight saving between 1948 and 1951, but ``the system was discontinued
    -# because the public believed it would lead to longer working hours.''
    +# daylight saving between 1948 and 1951, but "the system was discontinued
    +# because the public believed it would lead to longer working hours."
     
    -# From Mayumi Negishi in the 2005-08-10 Japan Times
    -# :
    +# From Mayumi Negishi in the 2005-08-10 Japan Times:
    +# http://www.japantimes.co.jp/cgi-bin/getarticle.pl5?nn20050810f2.htm
     # Occupation authorities imposed daylight-saving time on Japan on
     # [1948-05-01]....  But lack of prior debate and the execution of
     # daylight-saving time just three days after the bill was passed generated
    @@ -1313,7 +1426,8 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
     
     # From Hideyuki Suzuki (1998-11-09):
     # 'Tokyo' usually stands for the former location of Tokyo Astronomical
    -# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
    +# Observatory: 139 degrees 44' 40.90" E (9h 18m 58.727s),
    +# 35 degrees 39' 16.0" N.
     # This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
     # edited by National Astronomical Observatory of Japan....
     # JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
    @@ -1321,10 +1435,10 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
     
     # From Hideyuki Suzuki (1998-11-16):
     # The ordinance No. 51 (1886) established "standard time" in Japan,
    -# which stands for the time on E 135 degree.
    +# which stands for the time on 135 degrees E.
     # In the ordinance No. 167 (1895), "standard time" was renamed to "central
     # standard time".  And the same ordinance also established "western standard
    -# time", which stands for the time on E 120 degree....  But "western standard
    +# time", which stands for the time on 120 degrees E....  But "western standard
     # time" was abolished in the ordinance No. 529 (1937).  In the ordinance No.
     # 167, there is no mention regarding for what place western standard time is
     # standard....
    @@ -1332,27 +1446,33 @@ Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
     # I wrote "ordinance" above, but I don't know how to translate.
     # In Japanese it's "chokurei", which means ordinance from emperor.
     
    -# Shanks & Pottenger claim JST in use since 1896, and that a few
    -# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
    -# ordinances took effect on Jan 1.
    +# From Yu-Cheng Chuang (2013-07-12):
    +# ...the Meiji Emperor announced Ordinance No. 167 of Meiji Year 28 "The clause
    +# about standard time" ... The adoption began from Jan 1, 1896.
    +# http://ja.wikisource.org/wiki/標準時ニ關スル件_(公布時)
    +#
    +# ...the Showa Emperor announced Ordinance No. 529 of Showa Year 12 ... which
    +# means the whole Japan territory, including later occupations, adopt Japan
    +# Central Time (UTC+9). The adoption began on Oct 1, 1937.
    +# http://ja.wikisource.org/wiki/明治二十八年勅令第百六十七號標準時ニ關スル件中改正ノ件
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
    -			9:00	-	JST	1896
    -			9:00	-	CJT	1938
    +			9:00	-	JST	1896 Jan  1
    +			9:00	-	JCST	1937 Oct  1
     			9:00	Japan	J%sT
     # Since 1938, all Japanese possessions have been like Asia/Tokyo.
     
     # Jordan
     #
    -# From 
    -# Jordan Week (1999-07-01)  via Steffen Thorsen (1999-09-09):
    +# From 
    +# Jordan Week (1999-07-01) via Steffen Thorsen (1999-09-09):
     # Clocks in Jordan were forwarded one hour on Wednesday at midnight,
     # in accordance with the government's decision to implement summer time
     # all year round.
     #
    -# From 
    -# Jordan Week (1999-09-30)  via Steffen Thorsen (1999-11-09):
    +# From 
    +# Jordan Week (1999-09-30) via Steffen Thorsen (1999-11-09):
     # Winter time starts today Thursday, 30 September. Clocks will be turned back
     # by one hour.  This is the latest government decision and it's final!
     # The decision was taken because of the increase in working hours in
    @@ -1372,9 +1492,7 @@ Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
     
     # From Steffen Thorsen (2009-04-02):
     # This single one might be good enough, (2009-03-24, Arabic):
    -# 
     # http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
    -# 
     #
     # Google's translation:
     #
    @@ -1465,9 +1583,8 @@ Zone	Asia/Amman	2:23:44 -	LMT	1931
     # - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
     # - Oral switched from +5:00 to +4:00 in spring 1989.
     
    -# 
    -# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
    -# 
    +# From Kazakhstan Embassy's News Bulletin #11
    +#  (2005-03-21):
     # The Government of Kazakhstan passed a resolution March 15 abolishing
     # daylight saving time citing lack of economic benefits and health
     # complications coupled with a decrease in productivity.
    @@ -1500,10 +1617,10 @@ Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
     			6:00	-	KIZT	1982 Apr  1
     			5:00 RussiaAsia	KIZ%sT	1991
     			5:00	-	KIZT	1991 Dec 16 # independence
    -			5:00	-	QYZT	1992 Jan 19 2:00
    +			5:00	-	QYZT	1992 Jan 19  2:00
     			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
     			6:00	-	QYZT
    -# Aqtobe (aka Aktobe, formerly Akt'ubinsk)
    +# Aqtobe (aka Aktobe, formerly Aktyubinsk)
     Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
     			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
     			5:00	-	AKTT	1981 Apr  1
    @@ -1523,7 +1640,7 @@ Zone	Asia/Aqtau	3:21:04	-	LMT	1924 May  2
     			6:00	-	SHET	1982 Apr  1
     			5:00 RussiaAsia	SHE%sT	1991
     			5:00	-	SHET	1991 Dec 16 # independence
    -			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
    +			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun  2:00 # Aqtau Time
     			4:00 RussiaAsia	AQT%sT	2005 Mar 15
     			5:00	-	AQTT
     # West Kazakhstan
    @@ -1532,7 +1649,7 @@ Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
     			5:00	-	URAT	1981 Apr  1
     			5:00	1:00	URAST	1981 Oct  1
     			6:00	-	URAT	1982 Apr  1
    -			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
    +			5:00 RussiaAsia	URA%sT	1989 Mar 26  2:00
     			4:00 RussiaAsia	URA%sT	1991
     			4:00	-	URAT	1991 Dec 16 # independence
     			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
    @@ -1543,7 +1660,7 @@ Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
     
     # From Paul Eggert (2005-08-15):
     # According to an article dated today in the Kyrgyzstan Development Gateway
    -# 
    +# http://eng.gateway.kg/cgi-bin/page.pl?id=1&story_name=doc9979.shtml
     # Kyrgyzstan is canceling the daylight saving time system.  I take the article
     # to mean that they will leave their clocks at 6 hours ahead of UTC.
     # From Malik Abdugaliev (2005-09-21):
    @@ -1558,17 +1675,17 @@ 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 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
     
     ###############################################################################
     
     # Korea (North and South)
     
    -# From Annie I. Bang (2006-07-10) in
    -# :
    +# From Annie I. Bang (2006-07-10):
    +# http://www.koreaherald.co.kr/SITE/data/html_dir/2006/07/10/200607100012.asp
     # The Ministry of Commerce, Industry and Energy has already
     # commissioned a research project [to reintroduce DST] and has said
     # the system may begin as early as 2008....  Korea ran a daylight
    @@ -1581,19 +1698,29 @@ Rule	ROK	1960	only	-	Sep	13	0:00	0	S
     Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
     Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
     
    +# From Paul Eggert (2014-07-01):
    +# The following entries are from Shanks & Pottenger, except that 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.
    +
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Seoul	8:27:52	-	LMT	1890
     			8:30	-	KST	1904 Dec
    -			9:00	-	KST	1928
    +			9:00	-	JCST	1928
     			8:30	-	KST	1932
    +			9:00	-	JCST	1937 Oct  1
    +			9:00	-	JST	1945 Sep  8
     			9:00	-	KST	1954 Mar 21
     			8:00	ROK	K%sT	1961 Aug 10
     			8:30	-	KST	1968 Oct
     			9:00	ROK	K%sT
     Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
     			8:30	-	KST	1904 Dec
    -			9:00	-	KST	1928
    +			9:00	-	JCST	1928
     			8:30	-	KST	1932
    +			9:00	-	JCST	1937 Oct  1
    +			9:00	-	JST	1945 Aug 24
     			9:00	-	KST	1954 Mar 21
     			8:00	-	KST	1961 Aug 10
     			9:00	-	KST
    @@ -1602,21 +1729,13 @@ Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
     
     # Kuwait
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -# From the Arab Times (2007-03-14):
    -# The Civil Service Commission (CSC) has approved a proposal forwarded
    -# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
    -# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
    -# .
    -# From Paul Eggert (2007-03-29):
    -# We don't know the details, or whether the approval means it'll happen,
    -# so for now we assume no DST.
     Zone	Asia/Kuwait	3:11:56 -	LMT	1950
     			3:00	-	AST
     
     # Laos
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9 # or Viangchan
    -			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9       # or Viangchan
    +			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
     			7:00	-	ICT	1912 May
     			8:00	-	ICT	1931 May
     			7:00	-	ICT
    @@ -1657,8 +1776,8 @@ Rule	NBorneo	1935	1941	-	Sep	14	0:00	0:20	TS # one-Third Summer
     Rule	NBorneo	1935	1941	-	Dec	14	0:00	0	-
     #
     # peninsular Malaysia
    -# The data here are taken from Mok Ly Yng (2003-10-30)
    -# .
    +# taken from Mok Ly Yng (2003-10-30)
    +# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
     			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
    @@ -1670,12 +1789,12 @@ Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
     			7:30	-	MALT	1982 Jan  1
     			8:00	-	MYT	# Malaysia Time
     # Sabah & Sarawak
    -# From Paul Eggert (2006-03-22):
    -# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
    -# transition dates are from Mok Ly Yng.
    +# From Paul Eggert (2014-08-12):
    +# The data entries here are mostly from Shanks & Pottenger, but the 1942, 1945
    +# and 1982 transition dates are from Mok Ly Yng.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
    -			7:30	-	BORT	1933	# Borneo Time
    +			7:30	-	BORT	1933        # Borneo Time
     			8:00	NBorneo	BOR%sT	1942 Feb 16
     			9:00	-	JST	1945 Sep 12
     			8:00	-	BORT	1982 Jan  1
    @@ -1683,22 +1802,21 @@ Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
     
     # Maldives
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
    -			4:54:00	-	MMT	1960	# Male Mean Time
    -			5:00	-	MVT		# Maldives Time
    +Zone	Indian/Maldives	4:54:00 -	LMT	1880 # Male
    +			4:54:00	-	MMT	1960 # Male Mean Time
    +			5:00	-	MVT	# Maldives Time
     
     # Mongolia
     
     # Shanks & Pottenger say that Mongolia has three time zones, but
    -# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
    -# both say that it has just one.
    +# The USNO (1995-12-21) and the CIA map Standard Time Zones of the World
    +# (2005-03) both say that it has just one.
     
     # From Oscar van Vlijmen (1999-12-11):
    -# 
     # General Information Mongolia
    -#  (1999-09)
    +#  (1999-09)
     # "Time: Mongolia has two time zones. Three westernmost provinces of
    -# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
    +# Bayan-Ölgii, Uvs, and Hovd are one hour earlier than the capital city, and
     # the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
     # eight hours."
     
    @@ -1709,7 +1827,7 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
     # of implementation may have been different....
     # Some maps in the past have indicated that there was an additional time
     # zone in the eastern part of Mongolia, including the provinces of Dornod,
    -# Suhbaatar, and possibly Khentij.
    +# Sükhbaatar, and possibly Khentii.
     
     # From Paul Eggert (1999-12-15):
     # Naming and spelling is tricky in Mongolia.
    @@ -1723,10 +1841,10 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
     # (adopted DST on 2001-04-27 02:00 local time, ending 2001-09-28),
     # there are three time zones.
     #
    -# Provinces [at 7:00]: Bayan-ulgii, Uvs, Khovd, Zavkhan, Govi-Altai
    -# Provinces [at 8:00]: Khovsgol, Bulgan, Arkhangai, Khentii, Tov,
    -#	Bayankhongor, Ovorkhangai, Dundgovi, Dornogovi, Omnogovi
    -# Provinces [at 9:00]: Dornod, Sukhbaatar
    +# Provinces [at 7:00]: Bayan-Ölgii, Uvs, Khovd, Zavkhan, Govi-Altai
    +# Provinces [at 8:00]: Khövsgöl, Bulgan, Arkhangai, Khentii, Töv,
    +#	Bayankhongor, Övörkhangai, Dundgovi, Dornogovi, Ömnögovi
    +# Provinces [at 9:00]: Dornod, Sükhbaatar
     #
     # [The province of Selenge is omitted from the above lists.]
     
    @@ -1743,16 +1861,16 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
     # We have wildly conflicting information about Mongolia's time zones.
     # 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 Nykanen (2005-05-16) reports that
    +# 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.
     # 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
    -# 
    +# http://ubpost.mongolnews.mn/index.php?subaction=showcomments&id=1111634894&archive=&start_from=&ucat=1&
     # which also says that there is DST, and which has a comment by "Toddius"
     # (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
     # The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
    -# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
    +# and some Eastern provinces are +9 GMT but Sükhbaatar Aimag is SUHK +8.5 GMT.
     # The SUKH timezone is new this year, it is one of the few things the
     # parliament passed during the tumultuous winter session."
     # For now, let's ignore this information, until we have more confirmation.
    @@ -1768,29 +1886,23 @@ Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
     # +08:00 instead. Different sources appear to disagree with the tz
     # database on this, e.g.:
     #
    -# 
     # http://www.timeanddate.com/worldclock/city.html?n=1026
    -# 
    -# 
     # http://www.worldtimeserver.com/current_time_in_MN.aspx
    -# 
     #
     # both say GMT+08:00.
     
     # From Steffen Thorsen (2008-03-31):
     # eznis airways, which operates several domestic flights, has a flight
     # schedule here:
    -# 
     # http://www.eznis.com/Container.jsp?id=112
    -# 
     # (click the English flag for English)
     #
    -# There it appears that flights between Choibalsan and Ulaanbatar arrive
    +# There it appears that flights between Choibalsan and Ulaanbaatar arrive
     # about 1:35 - 1:50 hours later in local clock time, no matter the
    -# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
    -# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
    +# direction, while Ulaanbaatar-Khovd takes 2 hours in the Eastern
    +# direction and 3:35 back, which indicates that Ulaanbaatar and Khovd are
     # in different time zones (like we know about), while Choibalsan and
    -# Ulaanbatar are in the same time zone (correction needed).
    +# Ulaanbaatar are in the same time zone (correction needed).
     
     # From Arthur David Olson (2008-05-19):
     # Assume that Choibalsan is indeed offset by 8:00.
    @@ -1806,7 +1918,7 @@ Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
     # (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
     #
     # Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
    -# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
    +# in Choibalsan (more precisely, in Dornod and Sükhbaatar) took place
     # at 02:00 standard time, not at 00:00 local time as in the rest of
     # the country.  That would be odd, and possibly is a result of their
     # correction of 02:00 (in the previous edition) not being done correctly
    @@ -1822,13 +1934,13 @@ Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     # Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
     Zone	Asia/Hovd	6:06:36 -	LMT	1905 Aug
    -			6:00	-	HOVT	1978	# Hovd Time
    +			6:00	-	HOVT	1978     # Hovd Time
     			7:00	Mongol	HOV%sT
     # Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
     Zone	Asia/Ulaanbaatar 7:07:32 -	LMT	1905 Aug
    -			7:00	-	ULAT	1978	# Ulaanbaatar Time
    +			7:00	-	ULAT	1978     # Ulaanbaatar Time
     			8:00	Mongol	ULA%sT
    -# Choibalsan, a.k.a. Bajan Tuemen, Bajan Tumen, Chojbalsan,
    +# Choibalsan, a.k.a. Bajan Tümen, Bajan Tumen, Chojbalsan,
     # Choybalsan, Sanbejse, Tchoibalsan
     Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
     			7:00	-	ULAT	1978
    @@ -1860,7 +1972,7 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     # 00:01 was to make it clear which day it was on.
     
     # From Paul Eggert (2002-03-15):
    -# Jesper Norgaard found this URL:
    +# Jesper Nørgaard found this URL:
     # http://www.pak.gov.pk/public/news/app/app06_dec.htm
     # (dated 2001-12-06) which says that the Cabinet adopted a scheme "to
     # advance the clocks by one hour on the night between the first
    @@ -1892,43 +2004,30 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     # Here is an article that Pakistan plan to introduce Daylight Saving Time
     # on June 1, 2008 for 3 months.
     #
    -# "... The federal cabinet on Wednesday announced a new conservation plan to help
    -# reduce load shedding by approving the closure of commercial centres at 9pm and
    -# moving clocks forward by one hour for the next three months.
    -# ...."
    +# "... The federal cabinet on Wednesday announced a new conservation plan to
    +# help reduce load shedding by approving the closure of commercial centres at
    +# 9pm and moving clocks forward by one hour for the next three months. ...."
     #
    -# 
     # http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
    -# 
    -# OR
    -# 
     # http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
    -# 
     
     # From Arthur David Olson (2008-05-19):
     # XXX--midnight transitions is a guess; 2008 only is a guess.
     
     # From Alexander Krivenyshev (2008-08-28):
     # Pakistan government has decided to keep the watches one-hour advanced
    -# for another 2 months--plan to return to Standard Time on October 31
    +# for another 2 months - plan to return to Standard Time on October 31
     # instead of August 31.
     #
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
    -# 
    -# OR
    -# 
     # http://dailymailnews.com/200808/28/news/dmbrn03.html
    -# 
     
     # From Alexander Krivenyshev (2009-04-08):
     # Based on previous media reports that "... proposed plan to
     # advance clocks by one hour from May 1 will cause disturbance
     # to the working schedules rather than bringing discipline in
     # official working."
    -# 
     # http://www.thenews.com.pk/daily_detail.asp?id=171280
    -# 
     #
     # recent news that instead of May 2009 - Pakistan plan to
     # introduce DST from April 15, 2009
    @@ -1936,15 +2035,8 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     # FYI: Associated Press Of Pakistan
     # April 08, 2009
     # Cabinet okays proposal to advance clocks by one hour from April 15
    -# 
     # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
    -# 
    -#
    -# or
    -#
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
    -# 
     #
     # ....
     # The Federal Cabinet on Wednesday approved the proposal to
    @@ -1957,34 +2049,20 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     # clocks backward by one hour from October 1. A formal announcement to
     # this effect will be made after the Prime Minister grants approval in
     # this regard."
    -# 
     # http://www.thenews.com.pk/updates.asp?id=87168
    -# 
     
     # From Alexander Krivenyshev (2009-09-28):
     # According to Associated Press Of Pakistan, it is confirmed that
    -# Pakistan clocks across the country would be turned back by an hour from October
    -# 1, 2009.
    +# Pakistan clocks across the country would be turned back by an hour from
    +# October 1, 2009.
     #
     # "Clocks to go back one hour from 1 Oct"
    -# 
     # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
    -# 
    -
    -# From Steffen Thorsen (2009-09-29):
    -# Alexander Krivenyshev wrote:
    -# > According to Associated Press Of Pakistan, it is confirmed that
    -# > Pakistan clocks across the country would be turned back by an hour from October
    -# > 1, 2009.
     #
    +# From Steffen Thorsen (2009-09-29):
     # Now they seem to have changed their mind, November 1 is the new date:
    -# 
     # http://www.thenews.com.pk/top_story_detail.asp?Id=24742
    -# 
     # "The country's clocks will be reversed by one hour on November 1.
     # Officials of Federal Ministry for Interior told this to Geo News on
     # Monday."
    @@ -1996,11 +2074,9 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     #
     # We have confirmed this year's end date with both with the Ministry of
     # Water and Power and the Pakistan Electric Power Company:
    -# 
     # http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
    -# 
     
    -# From Christoph Goehre (2009-10-01):
    +# From Christoph Göhre (2009-10-01):
     # [T]he German Consulate General in Karachi reported me today that Pakistan
     # will go back to standard time on 1st of November.
     
    @@ -2016,22 +2092,17 @@ Zone	Asia/Muscat	3:54:24 -	LMT	1920
     # Now, it seems that the decision to not observe DST in final:
     #
     # "Govt Withdraws Plan To Advance Clocks"
    -# 
     # http://www.apakistannews.com/govt-withdraws-plan-to-advance-clocks-172041
    -# 
     #
     # "People laud PM's announcement to end DST"
    -# 
     # http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=99374&Itemid=2
    -# 
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
     Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
     Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
    -Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
    +Rule Pakistan	2008	2009	-	Nov	1	0:00	0	-
     Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
    -Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Karachi	4:28:12 -	LMT	1907
    @@ -2105,10 +2176,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # the PA has decided to implement DST in April.
     
     # From Paul Eggert (1999-09-20):
    -# Daoud Kuttab writes in
    -# 
    -# Holiday havoc
    -#  (Jerusalem Post, 1999-04-22) that
    +# Daoud Kuttab writes in Holiday havoc
    +# http://www.jpost.com/com/Archive/22.Apr.1999/Opinion/Article-2.html
    +# (Jerusalem Post, 1999-04-22) that
     # the Palestinian National Authority changed to DST on 1999-04-15.
     # I vaguely recall that they switch back in October (sorry, forgot the source).
     # For now, let's assume that the spring switch was at 24:00,
    @@ -2121,7 +2191,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # A user from Gaza reported that Gaza made the change early because of
     # the Ramadan.  Next year Ramadan will be even earlier, so I think
     # there is a good chance next year's end date will be around two weeks
    -# earlier--the same goes for Jordan.
    +# earlier - the same goes for Jordan.
     
     # From Steffen Thorsen (2006-08-17):
     # I was informed by a user in Bethlehem that in Bethlehem it started the
    @@ -2140,7 +2210,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # I guess it is likely that next year's date will be moved as well,
     # because of the Ramadan.
     
    -# From Jesper Norgaard Welen (2007-09-18):
    +# From Jesper Nørgaard Welen (2007-09-18):
     # According to Steffen Thorsen's web site the Gaza Strip and the rest of the
     # Palestinian territories left DST early on 13.th. of September at 2:00.
     
    @@ -2157,16 +2227,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
     # the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
     #
    -# 
     # http://www.guardian.co.uk/world/feedarticle/7759001
    -# 
    -# 
     # http://www.abcnews.go.com/International/wireStory?id=5676087
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
    -# 
     
     # From Alexander Krivenyshev (2009-03-26):
     # According to the Palestine News Network (arabic.pnn.ps), Palestinian
    @@ -2174,24 +2237,17 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # 26 and continue until the night of 27 September 2009.
     #
     # (in Arabic)
    -# 
     # http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
    -# 
     #
    -# or
     # (English translation)
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
    -# 
     
     # From Steffen Thorsen (2009-08-31):
     # Palestine's Council of Ministers announced that they will revert back to
     # winter time on Friday, 2009-09-04.
     #
     # One news source:
    -# 
     # http://www.safa.ps/ara/?action=showdetail&seid=4158
    -# 
     # (Palestinian press agency, Arabic),
     # Google translate: "Decided that the Palestinian government in Ramallah
     # headed by Salam Fayyad, the start of work in time for the winter of
    @@ -2200,9 +2256,7 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     #
     # We are not sure if Gaza will do the same, last year they had a different
     # end date, we will keep this page updated:
    -# 
     # http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
    -# 
     
     # From Alexander Krivenyshev (2009-09-02):
     # Seems that Gaza Strip will go back to Winter Time same date as West Bank.
    @@ -2212,51 +2266,35 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     #
     # "Winter time unite the West Bank and Gaza"
     # (from Palestinian National Authority):
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
    -# 
     
     # From Alexander Krivenyshev (2010-03-19):
     # According to Voice of Palestine DST will last for 191 days, from March
     # 26, 2010 till "the last Sunday before the tenth day of Tishri
     # (October), each year" (October 03, 2010?)
     #
    -# 
     # http://palvoice.org/forums/showthread.php?t=245697
    -# 
     # (in Arabic)
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_westbank03.html
    -# 
     
     # From Steffen Thorsen (2010-03-24):
     # ...Ma'an News Agency reports that Hamas cabinet has decided it will
     # start one day later, at 12:01am. Not sure if they really mean 12:01am or
     # noon though:
     #
    -# 
     # http://www.maannews.net/eng/ViewDetails.aspx?ID=271178
    -# 
     # (Ma'an News Agency)
     # "At 12:01am Friday, clocks in Israel and the West Bank will change to
     # 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
     
     # From Steffen Thorsen (2010-08-11):
     # According to several sources, including
    -# 
     # http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
    -# 
     # the clocks were set back one hour at 2010-08-11 00:00:00 local time in
     # Gaza and the West Bank.
     # Some more background info:
    -# 
     # http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
    -# 
     
     # From Steffen Thorsen (2011-08-26):
     # Gaza and the West Bank did go back to standard time in the beginning of
    @@ -2264,13 +2302,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # 00:00 (so two periods of DST in 2011). The pause was because of
     # Ramadan.
     #
    -# 
     # http://www.maannews.net/eng/ViewDetails.aspx?ID=416217
    -# 
     # Additional info:
    -# 
     # http://www.timeanddate.com/news/time/palestine-dst-2011.html
    -# 
     
     # From Alexander Krivenyshev (2011-08-27):
     # According to the article in The Jerusalem Post:
    @@ -2280,14 +2314,9 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # The Hamas government said on Saturday that it won't observe summertime after
     # the Muslim feast of Id al-Fitr, which begins on Tuesday..."
     # ...
    -# 
     # http://www.jpost.com/MiddleEast/Article.aspx?id=235650
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_gazastrip05.html
    -# 
    -# The rules for Egypt are stolen from the `africa' file.
    +# The rules for Egypt are stolen from the 'africa' file.
     
     # From Steffen Thorsen (2011-09-30):
     # West Bank did end Daylight Saving Time this morning/midnight (2011-09-30
    @@ -2295,26 +2324,18 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
     # So West Bank and Gaza now have the same time again.
     #
     # Many sources, including:
    -# 
     # http://www.maannews.net/eng/ViewDetails.aspx?ID=424808
    -# 
     
     # From Steffen Thorsen (2012-03-26):
     # Palestinian news sources tell that both Gaza and West Bank will start DST
     # on Friday (Thursday midnight, 2012-03-29 24:00).
     # Some of many sources in Arabic:
    -# 
     # http://www.samanews.com/index.php?act=Show&id=122638
    -# 
     #
    -# 
     # http://safa.ps/details/news/74352/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-%D8%A8%D8%A7%D9%84%D8%B6%D9%81%D8%A9-%D9%88%D8%BA%D8%B2%D8%A9-%D9%84%D9%8A%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D9%85%D8%B9%D8%A9.html
    -# 
     #
     # Our brief summary:
    -# 
     # http://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html
    -# 
     
     # From Steffen Thorsen (2013-03-26):
     # The following news sources tells that Palestine will "start daylight saving
    @@ -2374,10 +2395,10 @@ Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
     			2:00 EgyptAsia	EE%sT	1967 Jun  5
     			2:00	Zion	I%sT	1996
     			2:00	Jordan	EE%sT	1999
    -			2:00 Palestine	EE%sT	2008 Aug 29 0:00
    +			2:00 Palestine	EE%sT	2008 Aug 29  0:00
     			2:00	-	EET	2008 Sep
     			2:00 Palestine	EE%sT	2010
    -			2:00	-	EET	2010 Mar 27 0:01
    +			2:00	-	EET	2010 Mar 27  0:01
     			2:00 Palestine	EE%sT	2011 Aug  1
     			2:00	-	EET	2012
     			2:00 Palestine	EE%sT
    @@ -2393,25 +2414,27 @@ Zone	Asia/Hebron	2:20:23	-	LMT	1900 Oct
     # no information
     
     # Philippines
    -# On 1844-08-16, Narciso Claveria, governor-general of the
    +# On 1844-08-16, Narciso Clavería, governor-general of the
     # Philippines, issued a proclamation announcing that 1844-12-30 was to
    -# be immediately followed by 1845-01-01.  Robert H. van Gent has a
    -# transcript of the decree in .
    -# The rest of the data are from Shanks & Pottenger.
    +# be immediately followed by 1845-01-01; see R.H. van Gent's
    +# History of the International Date Line
    +# http://www.staff.science.uu.nl/~gent0113/idl/idl_philippines.htm
    +# The rest of the data entries are from Shanks & Pottenger.
     
    -# From Paul Eggert (2006-04-25):
    -# Tomorrow's Manila Standard reports that the Philippines Department of
    -# Trade and Industry is considering adopting DST this June when the
    -# rainy season begins.  See
    -# .
    -# For now, we'll ignore this, since it's not definite and we lack details.
    -#
    -# From Jesper Norgaard Welen (2006-04-26):
    +# From Jesper Nørgaard Welen (2006-04-26):
     # ... claims that Philippines had DST last time in 1990:
     # http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
     # [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
     # but no details]
     
    +# From Paul Eggert (2014-08-14):
    +# The following source says DST may be instituted November-January and again
    +# March-June, but this is not definite.  It also says DST was last proclaimed
    +# during the Ramos administration (1992-1998); but again, no details.
    +# Carcamo D. PNoy urged to declare use of daylight saving time.
    +# Philippine Star 2014-08-05
    +# http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time
    +
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
     Rule	Phil	1937	only	-	Feb	1	0:00	0	-
    @@ -2428,18 +2451,39 @@ Zone	Asia/Manila	-15:56:00 -	LMT	1844 Dec 31
     
     # Qatar
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Qatar	3:26:08 -	LMT	1920	# Al Dawhah / Doha
    +Zone	Asia/Qatar	3:26:08 -	LMT	1920     # Al Dawhah / Doha
     			4:00	-	GST	1972 Jun
     			3:00	-	AST
     
     # Saudi Arabia
    +#
    +# From Paul Eggert (2014-07-15):
    +# Time in Saudi Arabia and other countries in the Arabian peninsula was not
    +# standardized until relatively recently; we don't know when, and possibly it
    +# has never been made official.  Richard P Hunt, in "Islam city yielding to
    +# modern times", New York Times (1961-04-09), p 20, wrote that only airlines
    +# observed standard time, and that people in Jeddah mostly observed quasi-solar
    +# time, doing so by setting their watches at sunrise to 6 o'clock (or to 12
    +# o'clock for "Arab" time).
    +#
    +# The TZ database cannot represent quasi-solar time; airline time is the best
    +# we can do.  The 1946 foreign air news digest of the U.S. Civil Aeronautics
    +# Board (OCLC 42299995) reported that the "... Arabian Government, inaugurated
    +# a weekly Dhahran-Cairo service, via the Saudi Arabian cities of Riyadh and
    +# Jidda, on March 14, 1947".  Shanks & Pottenger guessed 1950; go with the
    +# 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
    +# the country.  Ignore this, as it's before our 1970 cutoff.
    +#
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Riyadh	3:06:52 -	LMT	1950
    +Zone	Asia/Riyadh	3:06:52 -	LMT	1947 Mar 14
     			3:00	-	AST
     
     # Singapore
    -# The data here are taken from Mok Ly Yng (2003-10-30)
    -# .
    +# taken from Mok Ly Yng (2003-10-30)
    +# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
     			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
    @@ -2465,26 +2509,24 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
     
     # From Paul Eggert (1996-09-03):
     # "Sri Lanka advances clock by an hour to avoid blackout"
    -# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
    +# (, 1996-05-24,
     # no longer available as of 1999-08-17)
    -# reported ``the country's standard time will be put forward by one hour at
    -# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
    +# reported "the country's standard time will be put forward by one hour at
    +# midnight Friday (1830 GMT) 'in the light of the present power crisis'."
     #
     # From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
    -# by Shamindra in
    -# 
    -# Daily News - Hot News Section (1996-10-26)
    -# :
    +# by Shamindra in Daily News - Hot News Section
    +#  (1996-10-26):
     # With effect from 12.30 a.m. on 26th October 1996
     # Sri Lanka will be six (06) hours ahead of GMT.
     
    -# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
    +# From Jesper Nørgaard Welen (2006-04-14), quoting Sri Lanka News Online
     #  (2006-04-13):
     # 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
     # at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
     
     # From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
    -# 
    +# http://today.reuters.co.uk/news/newsArticle.aspx?type=scienceNews&storyID=2006-04-12T172228Z_01_COL295762_RTRIDST_0_SCIENCE-SRILANKA-TIME-DC.XML
     # [The Tamil Tigers] never accepted the original 1996 time change and simply
     # kept their clocks set five and a half hours ahead of Greenwich Mean
     # Time (GMT), in line with neighbor India.
    @@ -2498,7 +2540,7 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
     # twice in 1996 and probably SL Government or its standardization
     # agencies never declared an abbreviation as a national standard.
     #
    -# I recollect before the recent change the government annoucemments
    +# I recollect before the recent change the government announcements
     # mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
     # Time and no mention was made about the abbreviation.
     #
    @@ -2508,7 +2550,7 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
     # item....
     #
     # Within Sri Lanka I think LKT is well known among computer users and
    -# adminsitrators.  In my opinion SLT may not be a good choice because the
    +# administrators.  In my opinion SLT may not be a good choice because the
     # nation's largest telcom / internet operator Sri Lanka Telcom is well
     # known by that abbreviation - simply as SLT (there IP domains are
     # slt.lk and sltnet.lk).
    @@ -2523,13 +2565,13 @@ Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Colombo	5:19:24 -	LMT	1880
    -			5:19:32	-	MMT	1906	# Moratuwa Mean Time
    +			5:19:32	-	MMT	1906        # Moratuwa Mean Time
     			5:30	-	IST	1942 Jan  5
     			5:30	0:30	IHST	1942 Sep
    -			5:30	1:00	IST	1945 Oct 16 2:00
    -			5:30	-	IST	1996 May 25 0:00
    -			6:30	-	LKT	1996 Oct 26 0:30
    -			6:00	-	LKT	2006 Apr 15 0:30
    +			5:30	1:00	IST	1945 Oct 16  2:00
    +			5:30	-	IST	1996 May 25  0:00
    +			6:30	-	LKT	1996 Oct 26  0:30
    +			6:00	-	LKT	2006 Apr 15  0:30
     			5:30	-	IST
     
     # Syria
    @@ -2580,7 +2622,7 @@ Rule	Syria	2006	only	-	Sep	22	0:00	0	-
     # Today the AP reported "Syria will switch to summertime at midnight Thursday."
     # http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
     Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
    -# From Jesper Norgard (2007-10-27):
    +# From Jesper Nørgaard (2007-10-27):
     # The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
     # not take place 1st November at 0:00 o'clock but 1st November at 24:00 or
     # rather Midnight between Thursday and Friday. This does make more sense than
    @@ -2589,7 +2631,7 @@ Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
     # it is implemented at midnight of the last workday before weekend...
     #
     # From Steffen Thorsen (2007-10-27):
    -# Jesper Norgaard Welen wrote:
    +# Jesper Nørgaard Welen wrote:
     #
     # > "Winter local time in Syria will be observed at midnight of Thursday 1
     # > November 2007, and the clock will be put back 1 hour."
    @@ -2605,8 +2647,7 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
     
     # From Stephen Colebourne (2008-03-17):
     # For everyone's info, I saw an IATA time zone change for [Syria] for
    -# this month (March 2008) in the last day or so...This is the data IATA
    -# are now using:
    +# this month (March 2008) in the last day or so....
     # Country     Time Standard   --- DST Start ---   --- DST End ---  DST
     # Name        Zone Variation   Time    Date        Time    Date
     # Variation
    @@ -2618,16 +2659,15 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
     # From Arthur David Olson (2008-03-17):
     # Here's a link to English-language coverage by the Syrian Arab News
     # Agency (SANA)...
    -# 
     # http://www.sana.sy/eng/21/2008/03/11/165173.htm
    -# ...which reads (in part) "The Cabinet approved the suggestion of the
    +# ...which reads (in part) "The Cabinet approved the suggestion of the
     # Ministry of Electricity to begin daylight savings time on Friday April
     # 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
     # Since Syria is two hours east of UTC, the 2200 and 2100 transition times
     # shown above match up with midnight in Syria.
     
     # From Arthur David Olson (2008-03-18):
    -# My buest guess at a Syrian rule is "the Friday nearest April 1";
    +# My best guess at a Syrian rule is "the Friday nearest April 1";
     # coding that involves either using a "Mar Fri>=29" construct that old time zone
     # compilers can't handle  or having multiple Rules (a la Israel).
     # For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
    @@ -2640,37 +2680,27 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
     # winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
     # clocks back 60 minutes).
     #
    -# 
     # http://sana.sy/ara/2/2008/10/07/195459.htm
    -# 
     
     # From Steffen Thorsen (2009-03-19):
     # Syria will start DST on 2009-03-27 00:00 this year according to many sources,
     # two examples:
     #
    -# 
     # http://www.sana.sy/eng/21/2009/03/17/217563.htm
    -# 
     # (English, Syrian Arab News # Agency)
    -# 
     # http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
    -# 
     # (Arabic, gov-site)
     #
     # We have not found any sources saying anything about when DST ends this year.
     #
     # Our summary
    -# 
     # http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
    -# 
     
     # From Steffen Thorsen (2009-10-27):
     # The Syrian Arab News Network on 2009-09-29 reported that Syria will
     # revert back to winter (standard) time on midnight between Thursday
     # 2009-10-29 and Friday 2009-10-30:
    -# 
     # http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
    -# 
     
     # From Arthur David Olson (2009-10-28):
     # We'll see if future DST switching times turn out to be end of the last
    @@ -2681,23 +2711,17 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
     # The "Syrian News Station" reported on 2010-03-16 that the Council of
     # Ministers has decided that Syria will start DST on midnight Thursday
     # 2010-04-01: (midnight between Thursday and Friday):
    -# 
     # http://sns.sy/sns/?path=news/read/11421 (Arabic)
    -# 
     
     # From Steffen Thorsen (2012-03-26):
     # Today, Syria's government announced that they will start DST early on Friday
     # (00:00). This is a bit earlier than the past two years.
     #
     # From Syrian Arab News Agency, in Arabic:
    -# 
     # http://www.sana.sy/ara/2/2012/03/26/408215.htm
    -# 
     #
     # Our brief summary:
    -# 
     # http://www.timeanddate.com/news/time/syria-dst-2012.html
    -# 
     
     # From Arthur David Olson (2012-03-27):
     # Assume last Friday in March going forward XXX.
    @@ -2710,7 +2734,7 @@ Rule	Syria	2012	max	-	Mar	lastFri	0:00	1:00	S
     Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
    +Zone	Asia/Damascus	2:25:12 -	LMT	1920 # Dimashq
     			2:00	Syria	EE%sT
     
     # Tajikistan
    @@ -2718,9 +2742,9 @@ Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
     # 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
    +			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
     
     # Thailand
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -2733,9 +2757,9 @@ Zone	Asia/Bangkok	6:42:04	-	LMT	1880
     # 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
    +			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
    +			4:00 RussiaAsia	TM%sT	1992 Jan 19  2:00
     			5:00	-	TMT
     
     # United Arab Emirates
    @@ -2744,8 +2768,9 @@ Zone	Asia/Dubai	3:41:12 -	LMT	1920
     			4:00	-	GST
     
     # Uzbekistan
    +# Byalokoz 1919 says Uzbekistan was 4:27:53.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
    +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
    @@ -2753,9 +2778,10 @@ Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
     			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
     			5:00 RussiaAsia	UZ%sT	1992
     			5:00	-	UZT
    -Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
    +# 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
    +			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
    @@ -2769,13 +2795,13 @@ Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
     # and Pottenger.
     
     # From Arthur David Olson (2008-03-18):
    -# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
    -# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
    +# The English-language name of Vietnam's most populous city is "Ho Chi Minh
    +# City"; use Ho_Chi_Minh below to avoid a name of more than 14 characters.
     
     # From Shanks & Pottenger:
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
    -			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +			7:06:20	-	SMT	1911 Mar 11  0:01 # Saigon MT?
     			7:00	-	ICT	1912 May
     			8:00	-	ICT	1931 May
     			7:00	-	ICT
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/australasia b/jdk/test/sun/util/calendar/zi/tzdata/australasia
    index 94c9adb912c..52d32904178 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/australasia
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia
    @@ -21,7 +21,6 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    @@ -36,13 +35,13 @@
     # Please see the notes below for the controversy about "EST" versus "AEST" etc.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	-
    -Rule	Aus	1917	only	-	Mar	25	2:00	0	-
    -Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	-
    -Rule	Aus	1942	only	-	Mar	29	2:00	0	-
    -Rule	Aus	1942	only	-	Sep	27	2:00	1:00	-
    -Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	-
    -Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
    +Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	D
    +Rule	Aus	1917	only	-	Mar	25	2:00	0	S
    +Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	D
    +Rule	Aus	1942	only	-	Mar	29	2:00	0	S
    +Rule	Aus	1942	only	-	Sep	27	2:00	1:00	D
    +Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	S
    +Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	D
     # Go with Whitman and the Australian National Standards Commission, which
     # says W Australia didn't use DST in 1943/1944.  Ignore Whitman's claim that
     # 1944/1945 was just like 1943/1944.
    @@ -50,26 +49,26 @@ Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     # Northern Territory
     Zone Australia/Darwin	 8:43:20 -	LMT	1895 Feb
    -			 9:00	-	CST	1899 May
    -			 9:30	Aus	CST
    +			 9:00	-	ACST	1899 May
    +			 9:30	Aus	AC%sT
     # Western Australia
     #
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
    -Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
    -Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
    -Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AW	1991	only	-	Nov	17	2:00s	1:00	D
    +Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	D
    +Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	S
    +Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	D
     Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
    -			 8:00	Aus	WST	1943 Jul
    -			 8:00	AW	WST
    +			 8:00	Aus	AW%sT	1943 Jul
    +			 8:00	AW	AW%sT
     Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
    -			 8:45	Aus	CWST	1943 Jul
    -			 8:45	AW	CWST
    +			 8:45	Aus	ACW%sT	1943 Jul
    +			 8:45	AW	ACW%sT
     
     # Queensland
     #
    @@ -85,150 +84,150 @@ Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
     # so use Lindeman.
     #
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	-
    -Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	-
    -Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	-
    -Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	S
    +Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	S
    +Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	D
    +Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	S
     Zone Australia/Brisbane	10:12:08 -	LMT	1895
    -			10:00	Aus	EST	1971
    -			10:00	AQ	EST
    +			10:00	Aus	AE%sT	1971
    +			10:00	AQ	AE%sT
     Zone Australia/Lindeman  9:55:56 -	LMT	1895
    -			10:00	Aus	EST	1971
    -			10:00	AQ	EST	1992 Jul
    -			10:00	Holiday	EST
    +			10:00	Aus	AE%sT	1971
    +			10:00	AQ	AE%sT	1992 Jul
    +			10:00	Holiday	AE%sT
     
     # South Australia
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
    -Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AS	1972	only	-	Feb	27	2:00s	0	-
    -Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
    -Rule	AS	1991	only	-	Mar	3	2:00s	0	-
    -Rule	AS	1992	only	-	Mar	22	2:00s	0	-
    -Rule	AS	1993	only	-	Mar	7	2:00s	0	-
    -Rule	AS	1994	only	-	Mar	20	2:00s	0	-
    -Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
    -Rule	AS	2006	only	-	Apr	2	2:00s	0	-
    -Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
    -Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AS	1986	only	-	Oct	19	2:00s	1:00	D
    +Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AS	1972	only	-	Feb	27	2:00s	0	S
    +Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	S
    +Rule	AS	1991	only	-	Mar	3	2:00s	0	S
    +Rule	AS	1992	only	-	Mar	22	2:00s	0	S
    +Rule	AS	1993	only	-	Mar	7	2:00s	0	S
    +Rule	AS	1994	only	-	Mar	20	2:00s	0	S
    +Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	S
    +Rule	AS	2006	only	-	Apr	2	2:00s	0	S
    +Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	S
    +Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
    -			9:00	-	CST	1899 May
    -			9:30	Aus	CST	1971
    -			9:30	AS	CST
    +			9:00	-	ACST	1899 May
    +			9:30	Aus	AC%sT	1971
    +			9:30	AS	AC%sT
     
     # Tasmania
     #
     # From Paul Eggert (2005-08-16):
    -# 
    +# http://www.bom.gov.au/climate/averages/tables/dst_times.shtml
     # says King Island didn't observe DST from WWII until late 1971.
     #
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
    -Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
    -Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	-
    -Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	-
    -Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	-
    -Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
    -Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	-
    -Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
    -Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
    -Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
    -Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
    -Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
    -Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
    -Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	D
    +Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	S
    +Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	S
    +Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	S
    +Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	S
    +Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	D
    +Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	S
    +Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	D
    +Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	D
    +Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	S
    +Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	D
    +Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	D
    +Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	S
    +Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
    -			10:00	-	EST	1916 Oct 1 2:00
    -			10:00	1:00	EST	1917 Feb
    -			10:00	Aus	EST	1967
    -			10:00	AT	EST
    +			10:00	-	AEST	1916 Oct  1  2:00
    +			10:00	1:00	AEDT	1917 Feb
    +			10:00	Aus	AE%sT	1967
    +			10:00	AT	AE%sT
     Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
    -			10:00	-	EST	1916 Oct 1 2:00
    -			10:00	1:00	EST	1917 Feb
    -			10:00	Aus	EST	1971 Jul
    -			10:00	AT	EST
    +			10:00	-	AEST	1916 Oct  1  2:00
    +			10:00	1:00	AEDT	1917 Feb
    +			10:00	Aus	AE%sT	1971 Jul
    +			10:00	AT	AE%sT
     
     # Victoria
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	-
    -Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	-
    -Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
    -Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
    -Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
    -Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
    -Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	S
    +Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	S
    +Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	D
    +Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	S
    +Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	D
    +Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	S
    +Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
    -			10:00	Aus	EST	1971
    -			10:00	AV	EST
    +			10:00	Aus	AE%sT	1971
    +			10:00	AV	AE%sT
     
     # New South Wales
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AN	1972	only	-	Feb	27	2:00s	0	-
    -Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	-
    -Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
    -Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
    -Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
    -Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
    -Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
    -Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
    -Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
    -Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AN	1972	only	-	Feb	27	2:00s	0	S
    +Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	S
    +Rule	AN	1986	only	-	Oct	19	2:00s	1:00	D
    +Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	S
    +Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	S
    +Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	D
    +Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	D
    +Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	S
    +Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	S
    +Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	D
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
    -			10:00	Aus	EST	1971
    -			10:00	AN	EST
    +			10:00	Aus	AE%sT	1971
    +			10:00	AN	AE%sT
     Zone Australia/Broken_Hill 9:25:48 -	LMT	1895 Feb
    -			10:00	-	EST	1896 Aug 23
    -			9:00	-	CST	1899 May
    -			9:30	Aus	CST	1971
    -			9:30	AN	CST	2000
    -			9:30	AS	CST
    +			10:00	-	AEST	1896 Aug 23
    +			9:00	-	ACST	1899 May
    +			9:30	Aus	AC%sT	1971
    +			9:30	AN	AC%sT	2000
    +			9:30	AS	AC%sT
     
     # Lord Howe Island
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	-
    -Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	-
    -Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	-
    -Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	-
    -Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
    -Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
    -Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
    -Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
    -Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
    -Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
    -Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
    -Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
    -Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
    -Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
    +Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	D
    +Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	S
    +Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	D
    +Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	S
    +Rule	LH	1986	only	-	Oct	19	2:00	0:30	D
    +Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	D
    +Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	S
    +Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	S
    +Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	D
    +Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	D
    +Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	S
    +Rule	LH	2007	only	-	Mar	lastSun	2:00	0	S
    +Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	S
    +Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	D
     Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
    -			10:00	-	EST	1981 Mar
    -			10:30	LH	LHST
    +			10:00	-	AEST	1981 Mar
    +			10:30	LH	LH%sT
     
     # Australian miscellany
     #
    @@ -244,8 +243,8 @@ Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
     # Permanent occupation (scientific station) 1911-1915 and since 25 March 1948;
     # sealing and penguin oil station operated Nov 1899 to Apr 1919.  See the
     # Tasmania Parks & Wildlife Service history of sealing at Macquarie Island
    -# 
    -# .
    +# http://www.parks.tas.gov.au/index.aspx?base=1828
    +# http://www.parks.tas.gov.au/index.aspx?base=1831
     # Guess that it was like Australia/Hobart while inhabited before 2010.
     #
     # From Steffen Thorsen (2010-03-10):
    @@ -256,16 +255,16 @@ Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
     #
     # From Arthur David Olson (2013-05-23):
     # The 1919 transition is overspecified below so pre-2013 zics
    -# will produce a binary file with an EST-type as the first 32-bit type;
    +# will produce a binary file with an [A]EST-type as the first 32-bit type;
     # this is required for correct handling of times before 1916 by
     # pre-2013 versions of localtime.
     Zone Antarctica/Macquarie 0	-	zzz	1899 Nov
    -			10:00	-	EST	1916 Oct 1 2:00
    -			10:00	1:00	EST	1917 Feb
    -			10:00	Aus	EST	1919 Apr 1 0:00s
    +			10:00	-	AEST	1916 Oct  1  2:00
    +			10:00	1:00	AEDT	1917 Feb
    +			10:00	Aus	AE%sT	1919 Apr  1  0:00s
     			0	-	zzz	1948 Mar 25
    -			10:00	Aus	EST	1967
    -			10:00	AT	EST	2010 Apr 4 3:00
    +			10:00	Aus	AE%sT	1967
    +			10:00	AT	AE%sT	2010 Apr  4  3:00
     			11:00	-	MIST	# Macquarie I Standard Time
     
     # Christmas
    @@ -273,24 +272,14 @@ Zone Antarctica/Macquarie 0	-	zzz	1899 Nov
     Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
     			7:00	-	CXT	# Christmas Island Time
     
    -# Cook Is
    -# From Shanks & Pottenger:
    -# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
    -Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
    -Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
    -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901		# Avarua
    -			-10:30	-	CKT	1978 Nov 12	# Cook Is Time
    -			-10:00	Cook	CK%sT
    -
    -# Cocos
    +# Cocos (Keeling) Is
     # These islands were ruled by the Ross family from about 1830 to 1978.
     # We don't know when standard time was introduced; for now, we guess 1900.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Indian/Cocos	6:27:40	-	LMT	1900
     			6:30	-	CCT	# Cocos Islands Time
     
    +
     # Fiji
     
     # Milne gives 11:55:44 for Suva.
    @@ -300,20 +289,13 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
     # from November 29th 2009  to April 25th 2010.
     #
     # "Daylight savings to commence this month"
    -# 
     # http://www.radiofiji.com.fj/fullstory.php?id=23719
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_fiji01.html
    -# 
     
     # From Steffen Thorsen (2009-11-10):
     # The Fiji Government has posted some more details about the approved
     # amendments:
    -# 
     # http://www.fiji.gov.fj/publish/page_16198.shtml
    -# 
     
     # From Steffen Thorsen (2010-03-03):
     # The Cabinet in Fiji has decided to end DST about a month early, on
    @@ -322,35 +304,24 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
     # 2011 (last Sunday a good guess?).
     #
     # Official source:
    -# 
     # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
    -# 
     #
     # A bit more background info here:
    -# 
     # http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
    -# 
     
     # From Alexander Krivenyshev (2010-10-24):
     # According to Radio Fiji and Fiji Times online, Fiji will end DST 3
     # weeks earlier than expected - on March 6, 2011, not March 27, 2011...
     # Here is confirmation from Government of the Republic of the Fiji Islands,
     # Ministry of Information (fiji.gov.fj) web site:
    -# 
     # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
    -# 
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
    -# 
     
     # From Steffen Thorsen (2011-10-03):
     # Now the dates have been confirmed, and at least our start date
     # assumption was correct (end date was one week wrong).
     #
    -# 
    -# www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
    -# 
    +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
     # which says
     # Members of the public are reminded to change their time to one hour in
     # advance at 2am to 3am on October 23, 2011 and one hour back at 3am to
    @@ -360,9 +331,7 @@ Zone	Indian/Cocos	6:27:40	-	LMT	1900
     # Another change to the Fiji DST end date. In the TZ database the end date for
     # Fiji DST 2012, is currently Feb 26. This has been changed to Jan 22.
     #
    -# 
     # http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=5017:amendments-to-daylight-savings&catid=71:press-releases&Itemid=155
    -# 
     # states:
     #
     # The end of daylight saving scheduled initially for the 26th of February 2012
    @@ -400,16 +369,16 @@ Rule	Fiji	2011	only	-	Mar	Sun>=1	3:00	0	-
     Rule	Fiji	2012	2013	-	Jan	Sun>=18	3:00	0	-
     Rule	Fiji	2014	max	-	Jan	Sun>=18	2:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Fiji	11:55:44 -	LMT	1915 Oct 26	# Suva
    +Zone	Pacific/Fiji	11:55:44 -	LMT	1915 Oct 26 # Suva
     			12:00	Fiji	FJ%sT	# Fiji Time
     
     # French Polynesia
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct	# Rikitea
    +Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct # Rikitea
     			 -9:00	-	GAMT	# Gambier Time
     Zone	Pacific/Marquesas -9:18:00 -	LMT	1912 Oct
     			 -9:30	-	MART	# Marquesas Time
    -Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
    +Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct # Papeete
     			-10:00	-	TAHT	# Tahiti Time
     # Clipperton (near North America) is administered from French Polynesia;
     # it is uninhabited.
    @@ -417,14 +386,14 @@ Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
     # Guam
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Pacific/Guam	-14:21:00 -	LMT	1844 Dec 31
    -			 9:39:00 -	LMT	1901		# Agana
    -			10:00	-	GST	2000 Dec 23	# Guam
    +			 9:39:00 -	LMT	1901        # Agana
    +			10:00	-	GST	2000 Dec 23 # Guam
     			10:00	-	ChST	# Chamorro Standard Time
     
     # Kiribati
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Pacific/Tarawa	 11:32:04 -	LMT	1901		# Bairiki
    -			 12:00	-	GILT		 # Gilbert Is Time
    +Zone Pacific/Tarawa	 11:32:04 -	LMT	1901 # Bairiki
    +			 12:00	-	GILT	# Gilbert Is Time
     Zone Pacific/Enderbury	-11:24:20 -	LMT	1901
     			-12:00	-	PHOT	1979 Oct # Phoenix Is Time
     			-11:00	-	PHOT	1995
    @@ -438,7 +407,7 @@ Zone Pacific/Kiritimati	-10:29:20 -	LMT	1901
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Pacific/Saipan	-14:17:00 -	LMT	1844 Dec 31
     			 9:43:00 -	LMT	1901
    -			 9:00	-	MPT	1969 Oct # N Mariana Is Time
    +			 9:00	-	MPT	1969 Oct    # N Mariana Is Time
     			10:00	-	MPT	2000 Dec 23
     			10:00	-	ChST	# Chamorro Standard Time
     
    @@ -449,24 +418,24 @@ Zone Pacific/Majuro	11:24:48 -	LMT	1901
     			12:00	-	MHT
     Zone Pacific/Kwajalein	11:09:20 -	LMT	1901
     			11:00	-	MHT	1969 Oct
    -			-12:00	-	KWAT	1993 Aug 20	# Kwajalein Time
    +			-12:00	-	KWAT	1993 Aug 20 # Kwajalein Time
     			12:00	-	MHT
     
     # Micronesia
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Pacific/Chuuk	10:07:08 -	LMT	1901
    -			10:00	-	CHUT			# Chuuk Time
    -Zone Pacific/Pohnpei	10:32:52 -	LMT	1901		# Kolonia
    -			11:00	-	PONT			# Pohnpei Time
    +			10:00	-	CHUT	# Chuuk Time
    +Zone Pacific/Pohnpei	10:32:52 -	LMT	1901 # Kolonia
    +			11:00	-	PONT	# Pohnpei Time
     Zone Pacific/Kosrae	10:51:56 -	LMT	1901
    -			11:00	-	KOST	1969 Oct	# Kosrae Time
    +			11:00	-	KOST	1969 Oct # Kosrae Time
     			12:00	-	KOST	1999
     			11:00	-	KOST
     
     # Nauru
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15	# Uaobe
    -			11:30	-	NRT	1942 Mar 15	# Nauru Time
    +Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15 # Uaobe
    +			11:30	-	NRT	1942 Mar 15 # Nauru Time
     			9:00	-	JST	1944 Aug 15
     			11:30	-	NRT	1979 May
     			12:00	-	NRT
    @@ -479,7 +448,7 @@ Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
     # Shanks & Pottenger say the following was at 2:00; go with IATA.
     Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
    +Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13 # Nouméa
     			11:00	NC	NC%sT
     
     
    @@ -496,7 +465,8 @@ Rule	NZ	1934	1940	-	Apr	lastSun	2:00	0	M
     Rule	NZ	1934	1940	-	Sep	lastSun	2:00	0:30	S
     Rule	NZ	1946	only	-	Jan	 1	0:00	0	S
     # Since 1957 Chatham has been 45 minutes ahead of NZ, but there's no
    -# convenient notation for this so we must duplicate the Rule lines.
    +# convenient single notation for the date and time of this transition
    +# so we must duplicate the Rule lines.
     Rule	NZ	1974	only	-	Nov	Sun>=1	2:00s	1:00	D
     Rule	Chatham	1974	only	-	Nov	Sun>=1	2:45s	1:00	D
     Rule	NZ	1975	only	-	Feb	lastSun	2:00s	0	S
    @@ -519,13 +489,14 @@ Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
     Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
     			11:30	NZ	NZ%sT	1946 Jan  1
     			12:00	NZ	NZ%sT
    -Zone Pacific/Chatham	12:13:48 -	LMT	1957 Jan  1
    +Zone Pacific/Chatham	12:13:48 -	LMT	1868 Nov  2
    +			12:15	-	CHAST	1946 Jan  1
     			12:45	Chatham	CHA%sT
     
     Link Pacific/Auckland Antarctica/McMurdo
     
     # Auckland Is
    -# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
    +# uninhabited; Māori and Moriori, colonial settlers, pastoralists, sealers,
     # and scientific personnel have wintered
     
     # Campbell I
    @@ -534,48 +505,58 @@ Link Pacific/Auckland Antarctica/McMurdo
     # previously whalers, sealers, pastoralists, and scientific personnel wintered
     # was probably like Pacific/Auckland
     
    +# Cook Is
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
    +Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
    +Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901        # Avarua
    +			-10:30	-	CKT	1978 Nov 12 # Cook Is Time
    +			-10:00	Cook	CK%sT
    +
     ###############################################################################
     
     
     # Niue
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Niue	-11:19:40 -	LMT	1901		# Alofi
    -			-11:20	-	NUT	1951	# Niue Time
    -			-11:30	-	NUT	1978 Oct 1
    +Zone	Pacific/Niue	-11:19:40 -	LMT	1901        # Alofi
    +			-11:20	-	NUT	1951        # Niue Time
    +			-11:30	-	NUT	1978 Oct  1
     			-11:00	-	NUT
     
     # Norfolk
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Norfolk	11:11:52 -	LMT	1901		# Kingston
    -			11:12	-	NMT	1951	# Norfolk Mean Time
    -			11:30	-	NFT		# Norfolk Time
    +Zone	Pacific/Norfolk	11:11:52 -	LMT	1901 # Kingston
    +			11:12	-	NMT	1951 # Norfolk Mean Time
    +			11:30	-	NFT	# Norfolk Time
     
     # Palau (Belau)
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Pacific/Palau	8:57:56 -	LMT	1901		# Koror
    +Zone Pacific/Palau	8:57:56 -	LMT	1901 # Koror
     			9:00	-	PWT	# Palau Time
     
     # Papua New Guinea
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Pacific/Port_Moresby 9:48:40 -	LMT	1880
    -			9:48:32	-	PMMT	1895	# Port Moresby Mean Time
    -			10:00	-	PGT		# Papua New Guinea Time
    +			9:48:32	-	PMMT	1895 # Port Moresby Mean Time
    +			10:00	-	PGT	# Papua New Guinea Time
     
     # Pitcairn
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901		# Adamstown
    -			-8:30	-	PNT	1998 Apr 27 00:00
    +Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901        # Adamstown
    +			-8:30	-	PNT	1998 Apr 27  0:00
     			-8:00	-	PST	# Pitcairn Standard Time
     
     # American Samoa
     Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
     			-11:22:48 -	LMT	1911
    -			-11:30	-	SAMT	1950		# Samoa Time
    -			-11:00	-	NST	1967 Apr	# N=Nome
    -			-11:00	-	BST	1983 Nov 30	# B=Bering
    -			-11:00	-	SST			# S=Samoa
    +			-11:00	-	NST	1967 Apr    # N=Nome
    +			-11:00	-	BST	1983 Nov 30 # B=Bering
    +			-11:00	-	SST	            # S=Samoa
     
    -# Samoa
    +# Samoa (formerly and also known as Western Samoa)
     
     # From Steffen Thorsen (2009-10-16):
     # We have been in contact with the government of Samoa again, and received
    @@ -586,141 +567,80 @@ Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
     # Sunday of April 2011."
     #
     # Background info:
    -# 
     # http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
    -# 
     #
     # Samoa's Daylight Saving Time Act 2009 is available here, but does not
     # contain any dates:
    -# 
     # http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
    -# 
     
     # From Laupue Raymond Hughes (2010-10-07):
     # Please see
    -# 
     # http://www.mcil.gov.ws
    -# ,
     # the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
     # September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
     # to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
     # backwards from 1:00am to 12:00am"
     
     # From Laupue Raymond Hughes (2011-03-07):
    -# I believe this will be posted shortly on the website
    -# 
    -# www.mcil.gov.ws
    -# 
    +# [http://www.mcil.gov.ws/ftcd/daylight_saving_2011.pdf]
     #
    -# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
    -#
    -# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
    -# businesses and the general public are hereby advised that daylight
    -# saving time is on the first Saturday of April 2011 (02/04/11).
    -#
    -# The public is therefore advised that when the standard time strikes
    -# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
    -# then all instruments used to measure standard time are to be
    -# adjusted/changed to three oclock (3:00am or 0300Hrs).
    -#
    -# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
    -# INDUSTRY AND LABOUR 28th February 2011
    +# ... when the standard time strikes the hour of four o'clock (4.00am
    +# or 0400 Hours) on the 2nd April 2011, then all instruments used to
    +# measure standard time are to be adjusted/changed to three o'clock
    +# (3:00am or 0300Hrs).
     
    -# From David Zuelke (2011-05-09):
    +# From David Zülke (2011-05-09):
     # Subject: Samoa to move timezone from east to west of international date line
     #
    -# 
     # http://www.morningstar.co.uk/uk/markets/newsfeeditem.aspx?id=138501958347963
    -# 
     
    -# From Mark Sim-Smith (2011-08-17):
    -# I have been in contact with Leilani Tuala Warren from the Samoa Law
    -# Reform Commission, and she has sent me a copy of the Bill that she
    -# confirmed has been passed...Most of the sections are about maps rather
    -# than the time zone change, but I'll paste the relevant bits below. But
    -# the essence is that at midnight 29 Dec (UTC-11 I suppose), Samoa
    -# changes from UTC-11 to UTC+13:
    -#
    -# International Date Line Bill 2011
    -#
    -# AN ACT to provide for the change to standard time in Samoa and to make
    -# consequential amendments to the position of the International Date
    -# Line, and for related purposes.
    -#
    -# BE IT ENACTED by the Legislative Assembly of Samoa in Parliament
    -# assembled as follows:
    -#
    -# 1. Short title and commencement-(1) This Act may be cited as the
    -# International Date Line Act 2011. (2) Except for section 5(3) this Act
    -# commences at 12 o'clock midnight, on Thursday 29th December 2011. (3)
    -# Section 5(3) commences on the date of assent by the Head of State.
    -#
    -# [snip]
    -#
    -# 3. Interpretation - [snip] "Samoa standard time" in this Act and any
    -# other statute of Samoa which refers to 'Samoa standard time' means the
    -# time 13 hours in advance of Co-ordinated Universal Time.
    -#
    -# 4. Samoa standard time - (1) Upon the commencement of this Act, Samoa
    -# standard time shall be set at 13 hours in advance of Co-ordinated
    -# Universal Time for the whole of Samoa. (2) All references to Samoa's
    -# time zone and to Samoa standard time in Samoa in all legislation and
    -# instruments after the commencement of this Act shall be references to
    -# Samoa standard time as provided for in this Act. (3) Nothing in this
    -# Act affects the provisions of the Daylight Saving Act 2009, except that
    -# it defines Samoa standard time....
    +# 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
    +# Thursday 29th December 2011".  The International Date Line was adjusted
    +# accordingly.
     
     # From Laupue Raymond Hughes (2011-09-02):
    -# 
     # http://www.mcil.gov.ws/mcil_publications.html
    -# 
     #
     # here is the official website publication for Samoa DST and dateline change
     #
     # DST
    -# Year	End	Time	Start	Time
    -# 2011	- - -	- - -	24 September	3:00am to 4:00am
    -# 2012	01 April	4:00am to 3:00am	- - -	- - -
    +# Year  End      Time              Start        Time
    +# 2011  - - -    - - -             24 September 3:00am to 4:00am
    +# 2012  01 April 4:00am to 3:00am  - - -        - - -
     #
     # Dateline Change skip Friday 30th Dec 2011
     # Thursday 29th December 2011	23:59:59 Hours
     # Saturday 31st December 2011	00:00:00 Hours
     #
    -# Clarification by Tim Parenti (2012-01-03):
    -# Although Samoa has used Daylight Saving Time in the 2010-2011 and 2011-2012
    -# seasons, there is not yet any indication that this trend will continue on
    -# a regular basis. For now, we have explicitly listed the transitions below.
    -#
    -# From Nicky (2012-09-10):
    +# From Nicholas Pereira (2012-09-10):
     # Daylight Saving Time commences on Sunday 30th September 2012 and
    -# ends on Sunday 7th of April 2013.
    -#
    -# Please find link below for more information.
    +# ends on Sunday 7th of April 2013....
     # http://www.mcil.gov.ws/mcil_publications.html
     #
    -# That publication also includes dates for Summer of 2013/4 as well
    -# which give the impression of a pattern in selecting dates for the
    -# future, so for now, we will guess this will continue.
    +# From Paul Eggert (2014-07-08):
    +# That web page currently lists transitions for 2012/3 and 2013/4.
    +# Assume the pattern instituted in 2012 will continue indefinitely.
     
    -# Western Samoa
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	WS	2010	only	-	Sep	lastSun	0:00	1	D
    +Rule	WS	2011	only	-	Apr	Sat>=1	4:00	0	S
    +Rule	WS	2011	only	-	Sep	lastSat	3:00	1	D
    +Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	S
     Rule	WS	2012	max	-	Sep	lastSun	3:00	1	D
    -Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
     			-11:26:56 -	LMT	1911
    -			-11:30	-	SAMT	1950		# Samoa Time
    -			-11:00	-	WST	2010 Sep 26
    -			-11:00	1:00	WSDT	2011 Apr 2 4:00
    -			-11:00	-	WST	2011 Sep 24 3:00
    -			-11:00	1:00	WSDT	2011 Dec 30
    -			 13:00	1:00	WSDT	2012 Apr Sun>=1 4:00
    +			-11:30	-	WSST	1950
    +			-11:00	WS	S%sT	2011 Dec 29 24:00 # S=Samoa
     			 13:00	WS	WS%sT
     
     # Solomon Is
     # excludes Bougainville, for which see Papua New Guinea
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
    +Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct # Honiara
     			11:00	-	SBT	# Solomon Is Time
     
     # Tokelau Is
    @@ -744,7 +664,7 @@ Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Pacific/Fakaofo	-11:24:56 -	LMT	1901
    -			-11:00	-	TKT 2011 Dec 30	# Tokelau Time
    +			-11:00	-	TKT	2011 Dec 30 # Tokelau Time
     			13:00	-	TKT
     
     # Tonga
    @@ -804,8 +724,8 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
     # time from Operation Newsreel (Hardtack I/Teak shot, 1958-08-01) to the last
     # Operation Fishbowl shot (Tightrope, 1962-11-04).... [See] Herman Hoerlin,
     # "The United States High-Altitude Test Experience: A Review Emphasizing the
    -# Impact on the Environment", Los Alamos LA-6405, Oct 1976
    -# .
    +# Impact on the Environment", Los Alamos LA-6405, Oct 1976.
    +# http://www.fas.org/sgp/othergov/doe/lanl/docs1/00322994.pdf
     # See the table on page 4 where he lists GMT and local times for the tests; a
     # footnote for the JI tests reads that local time is "JI time = Hawaii Time
     # Minus One Hour".
    @@ -820,7 +740,7 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
     # From Mark Brader (2005-01-23):
     # [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
     # published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
    -# reproduced a Pan American Airways timeables from 1936, for their weekly
    +# reproduced a Pan American Airways timetable from 1936, for their weekly
     # "Orient Express" flights between San Francisco and Manila, and connecting
     # flights to Chicago and the US East Coast.  As it uses some time zone
     # designations that I've never seen before:....
    @@ -830,9 +750,9 @@ Zone Pacific/Funafuti	11:56:52 -	LMT	1901
     Zone Pacific/Midway	-11:49:28 -	LMT	1901
     			-11:00	-	NST	1956 Jun  3
     			-11:00	1:00	NDT	1956 Sep  2
    -			-11:00	-	NST	1967 Apr	# N=Nome
    -			-11:00	-	BST	1983 Nov 30	# B=Bering
    -			-11:00	-	SST			# S=Samoa
    +			-11:00	-	NST	1967 Apr    # N=Nome
    +			-11:00	-	BST	1983 Nov 30 # B=Bering
    +			-11:00	-	SST	            # S=Samoa
     
     # Palmyra
     # uninhabited since World War II; was probably like Pacific/Kiritimati
    @@ -852,7 +772,7 @@ Rule	Vanuatu	1985	1991	-	Sep	Sun>=23	0:00	1:00	S
     Rule	Vanuatu	1992	1993	-	Jan	Sun>=23	0:00	0	-
     Rule	Vanuatu	1992	only	-	Oct	Sun>=23	0:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13		# Vila
    +Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13 # Vila
     			11:00	Vanuatu	VU%sT	# Vanuatu Time
     
     # Wallis and Futuna
    @@ -864,9 +784,10 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     
     # NOTES
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
     # From Paul Eggert (2013-02-21):
     # A good source for time zone historical data outside the U.S. is
    @@ -887,165 +808,188 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # I found in the UCLA library.
     #
     # For data circa 1899, a common source is:
    -# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
    -# .
    +# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
    +# http://www.jstor.org/stable/1774359
     #
     # A reliable and entertaining source about time zones is
     # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
     #
    -# I invented the abbreviations marked `*' in the following table;
    +# I invented the abbreviations marked '*' in the following table;
     # the rest are from earlier versions of this file, or from other sources.
     # Corrections are welcome!
    -#		std dst
    -#		LMT	Local Mean Time
    -#	  8:00	WST WST	Western Australia
    -#	  8:45	CWST CWST Central Western Australia*
    -#	  9:00	JST	Japan
    -#	  9:30	CST CST	Central Australia
    -#	 10:00	EST EST	Eastern Australia
    -#	 10:00	ChST	Chamorro
    -#	 10:30	LHST LHST Lord Howe*
    -#	 11:30	NZMT NZST New Zealand through 1945
    -#	 12:00	NZST NZDT New Zealand 1946-present
    -#	 12:45	CHAST CHADT Chatham*
    -#	-11:00	SST	Samoa
    -#	-10:00	HST	Hawaii
    -#	- 8:00	PST	Pitcairn*
    +#		std	dst
    +#		LMT		Local Mean Time
    +#	  8:00	AWST	AWDT	Western Australia
    +#	  8:45	ACWST	ACWDT	Central Western Australia*
    +#	  9:00	JST		Japan
    +#	  9:30	ACST	ACDT	Central Australia
    +#	 10:00	AEST	AEDT	Eastern Australia
    +#	 10:00	ChST		Chamorro
    +#	 10:30	LHST	LHDT	Lord Howe*
    +#	 11:30	NZMT	NZST	New Zealand through 1945
    +#	 12:00	NZST	NZDT	New Zealand 1946-present
    +#	 12:15	CHAST		Chatham through 1945*
    +#	 12:45	CHAST	CHADT	Chatham 1946-present*
    +#	 13:00	WSST	WSDT	(western) Samoa 2011-present*
    +#	-11:30	WSST		Western Samoa through 1950*
    +#	-11:00	SST		Samoa
    +#	-10:00	HST		Hawaii
    +#	- 8:00	PST		Pitcairn*
     #
    -# See the `northamerica' file for Hawaii.
    -# See the `southamerica' file for Easter I and the Galapagos Is.
    +# See the 'northamerica' file for Hawaii.
    +# See the 'southamerica' file for Easter I and the Galápagos Is.
     
     ###############################################################################
     
     # Australia
     
    +# From Paul Eggert (2014-06-30):
    +# Daylight saving time has long been controversial in Australia, pitting
    +# region against region, rural against urban, and local against global.
    +# For example, in her review of Graeme Davison's _The Unforgiving
    +# Minute: how Australians learned to tell the time_ (1993), Perth native
    +# Phillipa J Martyr wrote, "The section entitled 'Saving Daylight' was
    +# very informative, but was (as can, sadly, only be expected from a
    +# Melbourne-based study) replete with the usual chuckleheaded
    +# Queenslanders and straw-chewing yokels from the West prattling fables
    +# about fading curtains and crazed farm animals."
    +# Electronic Journal of Australian and New Zealand History (1997-03-03)
    +# http://www.jcu.edu.au/aff/history/reviews/davison.htm
    +
     # From Paul Eggert (2005-12-08):
    -# 
     # Implementation Dates of Daylight Saving Time within Australia
    -#  summarizes daylight saving issues in Australia.
    +# http://www.bom.gov.au/climate/averages/tables/dst_times.shtml
    +# summarizes daylight saving issues in Australia.
     
     # From Arthur David Olson (2005-12-12):
    -# 
     # Lawlink NSW:Daylight Saving in New South Wales
    -#  covers New South Wales in particular.
    +# http://www.lawlink.nsw.gov.au/lawlink/Corporate/ll_agdinfo.nsf/pages/community_relations_daylight_saving
    +# covers New South Wales in particular.
     
     # From John Mackin (1991-03-06):
    -# We in Australia have _never_ referred to DST as `daylight' time.
    -# It is called `summer' time.  Now by a happy coincidence, `summer'
    -# and `standard' happen to start with the same letter; hence, the
    +# We in Australia have _never_ referred to DST as 'daylight' time.
    +# It is called 'summer' time.  Now by a happy coincidence, 'summer'
    +# and 'standard' happen to start with the same letter; hence, the
     # abbreviation does _not_ change...
     # The legislation does not actually define abbreviations, at least
     # in this State, but the abbreviation is just commonly taken to be the
     # initials of the phrase, and the legislation here uniformly uses
    -# the phrase `summer time' and does not use the phrase `daylight
    +# the phrase 'summer time' and does not use the phrase 'daylight
     # time'.
     # Announcers on the Commonwealth radio network, the ABC (for Australian
    -# Broadcasting Commission), use the phrases `Eastern Standard Time'
    -# or `Eastern Summer Time'.  (Note, though, that as I say in the
    +# Broadcasting Commission), use the phrases 'Eastern Standard Time'
    +# or 'Eastern Summer Time'.  (Note, though, that as I say in the
     # current australasia file, there is really no such thing.)  Announcers
     # on its overseas service, Radio Australia, use the same phrases
    -# prefixed by the word `Australian' when referring to local times;
    +# prefixed by the word 'Australian' when referring to local times;
     # time announcements on that service, naturally enough, are made in UTC.
     
    -# From Arthur David Olson (1992-03-08):
    -# Given the above, what's chosen for year-round use is:
    -#	CST	for any place operating at a GMTOFF of 9:30
    -#	WST	for any place operating at a GMTOFF of 8:00
    -#	EST	for any place operating at a GMTOFF of 10:00
    -
    -# From Chuck Soper (2006-06-01):
    -# I recently found this Australian government web page on time zones:
    -# 
    -# And this government web page lists time zone names and abbreviations:
    -# 
    -
    -# From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
    -# versus "AEST" etc.:
    +# From Paul Eggert (2014-06-30):
     #
    -# I see the following points of dispute:
    +# Inspired by Mackin's remarks quoted above, earlier versions of this
    +# file used "EST" for both Eastern Standard Time and Eastern Summer
    +# Time in Australia, and similarly for "CST", "CWST", and "WST".
    +# However, these abbreviations were confusing and were not common
    +# practice among Australians, and there were justifiable complaints
    +# about them, so I attempted to survey current Australian usage.
    +# For the tz database, the full English phrase is not that important;
    +# what matters is the abbreviation.  It's difficult to survey the web
    +# directly for abbreviation usage, as there are so many false hits for
    +# strings like "EST" and "EDT", so I looked for pages that defined an
    +# abbreviation for eastern or central DST in Australia, and got the
    +# following numbers of unique hits for the listed Google queries:
     #
    -# * How important are unique time zone abbreviations?
    +#   10 "Eastern Daylight Time AEST" site:au [some are false hits]
    +#   10 "Eastern Summer Time AEST" site:au
    +#   10 "Summer Time AEDT" site:au
    +#   13 "EDST Eastern Daylight Saving Time" site:au
    +#   18 "Summer Time ESST" site:au
    +#   28 "Eastern Daylight Saving Time EDST" site:au
    +#   39 "EDT Eastern Daylight Time" site:au [some are false hits]
    +#   53 "Eastern Daylight Time EDT" site:au [some are false hits]
    +#   54 "AEDT Australian Eastern Daylight Time" site:au
    +#  182 "Eastern Daylight Time AEDT" site:au
     #
    -#   Here I tend to agree with the point (most recently made by Chris
    -#   Newman) that unique abbreviations should not be essential for proper
    -#   operation of software.  We have other instances of ambiguity
    -#   (e.g. "IST" denoting both "Israel Standard Time" and "Indian
    -#   Standard Time"), and they are not likely to go away any time soon.
    -#   In the old days, some software mistakenly relied on unique
    -#   abbreviations, but this is becoming less true with time, and I don't
    -#   think it's that important to cater to such software these days.
    +#   17 "Central Daylight Time CDT" site:au [some are false hits]
    +#   46 "Central Daylight Time ACDT" site:au
     #
    -#   On the other hand, there is another motivation for unambiguous
    -#   abbreviations: it cuts down on human confusion.  This is
    -#   particularly true for Australia, where "EST" can mean one thing for
    -#   time T and a different thing for time T plus 1 second.
    +# I tried several other variants (e.g., "Eastern Summer Time EST") but
    +# they all returned fewer than 10 unique hits.  I also looked for pages
    +# mentioning both "western standard time" and an abbreviation, since
    +# there is no WST in the US to generate false hits, and found:
     #
    -# * Does the relevant legislation indicate which abbreviations should be used?
    +#  156 "western standard time" AWST site:au
    +#  226 "western standard time" WST site:au
     #
    -#   Here I tend to think that things are a mess, just as they are in
    -#   many other countries.  We Americans are currently disagreeing about
    -#   which abbreviation to use for the newly legislated Chamorro Standard
    -#   Time, for example.
    +# I then surveyed the top ten newspapers in Australia by circulation as
    +# listed in Wikipedia, using Google queries like "AEDT site:heraldsun.com.au"
    +# and obtaining estimated counts from the initial page of search results.
    +# All ten papers greatly preferred "AEDT" to "EDT".  The papers
    +# surveyed were the Herald Sun, The Daily Telegraph, The Courier-Mail,
    +# The Sydney Morning Herald, The West Australian, The Age, The Advertiser,
    +# The Australian, The Financial Review, and The Herald (Newcastle).
     #
    -#   Personally, I would prefer to use common practice; I would like to
    -#   refer to legislation only for examples of common practice, or as a
    -#   tiebreaker.
    +# I also searched for historical usage, to see whether abbreviations
    +# like "AEDT" are new.  A Trove search 
    +# found only one newspaper (The Canberra Times) with a house style
    +# dating back to the 1970s, I expect because other newspapers weren't
    +# fully indexed.  The Canberra Times strongly preferred abbreviations
    +# like "AEDT".  The first occurrence of "AEDT" was a World Weather
    +# column (1971-11-17, page 24), and of "ACDT" was a Scoreboard column
    +# (1993-01-24, p 16).  The style was the typical usage but was not
    +# strictly enforced; for example, "Welcome to the twilight zones ..."
    +# (1994-10-29, p 1) uses the abbreviations AEST/AEDT, CST/CDT, and
    +# WST, and goes on to say, "The confusion and frustration some feel
    +# about the lack of uniformity among Australia's six states and two
    +# territories has prompted one group to form its very own political
    +# party -- the Sydney-based Daylight Saving Extension Party."
     #
    -# * Do Australians more often use "Eastern Daylight Time" or "Eastern
    -#   Summer Time"?  Do they typically prefix the time zone names with
    -#   the word "Australian"?
    +# I also surveyed federal government sources.  They did not agree:
     #
    -#   My own impression is that both "Daylight Time" and "Summer Time" are
    -#   common and are widely understood, but that "Summer Time" is more
    -#   popular; and that the leading "A" is also common but is omitted more
    -#   often than not.  I just used AltaVista advanced search and got the
    -#   following count of page hits:
    +#   The Australian Government (2014-03-26)
    +#   http://australia.gov.au/about-australia/our-country/time
    +#   (This document was produced by the Department of Finance.)
    +#   AEST ACST AWST AEDT ACDT
     #
    -#     1,103 "Eastern Summer Time" AND domain:au
    -#       971 "Australian Eastern Summer Time" AND domain:au
    -#       613 "Eastern Daylight Time" AND domain:au
    -#       127 "Australian Eastern Daylight Time" AND domain:au
    +#   Bureau of Meteorology (2012-11-08)
    +#   http://www.bom.gov.au/climate/averages/tables/daysavtm.shtml
    +#   EST CST WST EDT CDT
     #
    -#   Here "Summer" seems quite a bit more popular than "Daylight",
    -#   particularly when we know the time zone is Australian and not US,
    -#   say.  The "Australian" prefix seems to be popular for Eastern Summer
    -#   Time, but unpopular for Eastern Daylight Time.
    +#   Civil Aviation Safety Authority (undated)
    +#   http://services.casa.gov.au/outnback/inc/pages/episode3/episode-3_time_zones.shtml
    +#   EST CST WST (no abbreviations given for DST)
     #
    -#   For abbreviations, tools like AltaVista are less useful because of
    -#   ambiguity.  Many hits are not really time zones, unfortunately, and
    -#   many hits denote US time zones and not Australian ones.  But here
    -#   are the hit counts anyway:
    +#   Geoscience Australia (2011-11-24)
    +#   http://www.ga.gov.au/geodesy/astro/sunrise.jsp
    +#   AEST ACST AWST AEDT ACDT
     #
    -#     161,304 "EST" and domain:au
    -#      25,156 "EDT" and domain:au
    -#      18,263 "AEST" and domain:au
    -#      10,416 "AEDT" and domain:au
    +#   Parliamentary Library (2008-11-10)
    +#   http://www.aph.gov.au/binaries/library/pubs/rp/2008-09/09rp14.pdf
    +#   EST CST WST preferred for standard time; AEST AEDT ACST ACDT also used
     #
    -#      14,538 "CST" and domain:au
    -#       5,728 "CDT" and domain:au
    -#         176 "ACST" and domain:au
    -#          29 "ACDT" and domain:au
    +#   The Transport Safety Bureau has an extensive series of accident reports,
    +#   and investigators seem to use whatever abbreviation they like.
    +#   Googling site:atsb.gov.au found the following number of unique hits:
    +#   311 "ESuT", 195 "EDT", 26 "AEDT", 83 "CSuT", 46 "CDT".
    +#   "_SuT" tended to appear in older reports, and "A_DT" tended to
    +#   appear in reports of events with international implications.
     #
    -#       7,539 "WST" and domain:au
    -#          68 "AWST" and domain:au
    -#
    -#   This data suggest that Australians tend to omit the "A" prefix in
    -#   practice.  The situation for "ST" versus "DT" is less clear, given
    -#   the ambiguities involved.
    -#
    -# * How do Australians feel about the abbreviations in the tz database?
    -#
    -#   If you just count Australians on this list, I count 2 in favor and 3
    -#   against.  One of the "against" votes (David Keegel) counseled delay,
    -#   saying that both AEST/AEDT and EST/EST are widely used and
    -#   understood in Australia.
    +# From the above it appears that there is a working consensus in
    +# Australia to use trailing "DT" for daylight saving time; although
    +# some sources use trailing "SST" or "ST" or "SuT" they are by far in
    +# the minority.  The case for leading "A" is weaker, but since it
    +# seems to be preferred in the overall web and is preferred in all
    +# the leading newspaper websites and in many government departments,
    +# it has a stronger case than omitting the leading "A".  The current
    +# version of the database therefore uses abbreviations like "AEST" and
    +# "AEDT" for Australian time zones.
     
     # From Paul Eggert (1995-12-19):
     # Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
     # Mark Prior writes that his newspaper
     # reports that NSW's fall 1995 change will occur at 2:00,
     # but Robert Elz says it's been 3:00 in Victoria since 1970
    -# and perhaps the newspaper's `2:00' is referring to standard time.
    +# and perhaps the newspaper's '2:00' is referring to standard time.
     # For now we'll continue to assume 2:00s for changes since 1960.
     
     # From Eric Ulevik (1998-01-05):
    @@ -1055,17 +999,14 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # relevant entries in this database.
     #
     # NSW (including LHI and Broken Hill):
    -# 
     # Standard Time Act 1987 (updated 1995-04-04)
    -# 
    +# http://www.austlii.edu.au/au/legis/nsw/consol_act/sta1987137/index.html
     # ACT
    -# 
     # Standard Time and Summer Time Act 1972
    -# 
    +# http://www.austlii.edu.au/au/legis/act/consol_act/stasta1972279/index.html
     # SA
    -# 
     # Standard Time Act, 1898
    -# 
    +# http://www.austlii.edu.au/au/legis/sa/consol_act/sta1898137/index.html
     
     # From David Grosz (2005-06-13):
     # It was announced last week that Daylight Saving would be extended by
    @@ -1083,7 +1024,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # Victoria: I wasn't able to find anything separate, but the other articles
     # allude to it.
     # But not Queensland
    -# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
    +# http://www.news.com.au/story/0,10117,15564030-1248,00.html
     
     # Northern Territory
     
    @@ -1130,9 +1071,9 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # The 1992 ending date used in the rules is a best guess;
     # it matches what was used in the past.
     
    -# 
     # The Australian Bureau of Meteorology FAQ
    -#  (1999-09-27) writes that Giles Meteorological Station uses
    +# http://www.bom.gov.au/faq/faqgen.htm
    +# (1999-09-27) writes that Giles Meteorological Station uses
     # South Australian time even though it's located in Western Australia.
     
     # Queensland
    @@ -1173,9 +1114,9 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
     
     # From Christopher Hunt (2006-11-21), after an advance warning
    -# from Jesper Norgaard Welen (2006-11-01):
    +# from Jesper Nørgaard Welen (2006-11-01):
     # WA are trialing DST for three years.
    -# 
    +# http://www.parliament.wa.gov.au/parliament/bills.nsf/9A1B183144403DA54825721200088DF1/$File/Bill175-1B.pdf
     
     # From Rives McDow (2002-04-09):
     # The most interesting region I have found consists of three towns on the
    @@ -1189,7 +1130,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # From Paul Eggert (2002-04-09):
     # This is confirmed by the section entitled
     # "What's the deal with time zones???" in
    -# .
    +# http://www.earthsci.unimelb.edu.au/~awatkins/null.html
     #
     # From Alex Livingston (2006-12-07):
     # ... it was just on four years ago that I drove along the Eyre Highway,
    @@ -1337,7 +1278,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # Based on law library research by John Mackin,
     # who notes:
     #	In Australia, time is not legislated federally, but rather by the
    -#	individual states.  Thus, while such terms as ``Eastern Standard Time''
    +#	individual states.  Thus, while such terms as "Eastern Standard Time"
     #	[I mean, of course, Australian EST, not any other kind] are in common
     #	use, _they have NO REAL MEANING_, as they are not defined in the
     #	legislation.  This is very important to understand.
    @@ -1345,48 +1286,42 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     
     # From Eric Ulevik (1999-05-26):
     # DST will start in NSW on the last Sunday of August, rather than the usual
    -# October in 2000.  [See: Matthew Moore,
    -# 
    -# Two months more daylight saving
    -# 
    -# Sydney Morning Herald (1999-05-26).]
    +# October in 2000.  See: Matthew Moore,
    +# Two months more daylight saving, Sydney Morning Herald (1999-05-26).
    +# http://www.smh.com.au/news/9905/26/pageone/pageone4.html
     
     # From Paul Eggert (1999-09-27):
     # See the following official NSW source:
    -# 
     # Daylight Saving in New South Wales.
    -# 
    +# http://dir.gis.nsw.gov.au/cgi-bin/genobject/document/other/daylightsaving/tigGmZ
     #
     # Narrabri Shire (NSW) council has announced it will ignore the extension of
     # daylight saving next year.  See:
    -# 
     # Narrabri Council to ignore daylight saving
    -#  (1999-07-22).  For now, we'll wait to see if this really happens.
    +# http://abc.net.au/news/regionals/neweng/monthly/regeng-22jul1999-1.htm
    +# (1999-07-22).  For now, we'll wait to see if this really happens.
     #
     # Victoria will following NSW.  See:
    -# 
    -# Vic to extend daylight saving
    -#  (1999-07-28).
    +# Vic to extend daylight saving (1999-07-28)
    +# http://abc.net.au/local/news/olympics/1999/07/item19990728112314_1.htm
     #
     # However, South Australia rejected the DST request.  See:
    -# 
    -# South Australia rejects Olympics daylight savings request
    -#  (1999-07-19).
    +# South Australia rejects Olympics daylight savings request (1999-07-19)
    +# http://abc.net.au/news/olympics/1999/07/item19990719151754_1.htm
     #
     # Queensland also will not observe DST for the Olympics.  See:
    -# 
     # Qld says no to daylight savings for Olympics
    -#  (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
    -# ``Look you've got to remember in my family when this came up last time
    +# http://abc.net.au/news/olympics/1999/06/item19990601114608_1.htm
    +# (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
    +# "Look you've got to remember in my family when this came up last time
     # I voted for it, my wife voted against it and she said to me it's all very
     # well for you, you don't have to worry about getting the children out of
     # bed, getting them to school, getting them to sleep at night.
    -# I've been through all this argument domestically...my wife rules.''
    +# I've been through all this argument domestically...my wife rules."
     #
     # Broken Hill will stick with South Australian time in 2000.  See:
    -# 
    -# Broken Hill to be behind the times
    -#  (1999-07-21).
    +# Broken Hill to be behind the times (1999-07-21)
    +# http://abc.net.au/news/regionals/brokenh/monthly/regbrok-21jul1999-6.htm
     
     # IATA SSIM (1998-09) says that the spring 2000 change for Australian
     # Capital Territory, New South Wales except Lord Howe Island and Broken
    @@ -1402,7 +1337,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # Yancowinna
     
     # From John Mackin (1989-01-04):
    -# `Broken Hill' means the County of Yancowinna.
    +# 'Broken Hill' means the County of Yancowinna.
     
     # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
     # # YANCOWINNA..  [ Confirmation courtesy of Broken Hill Postmaster ]
    @@ -1459,9 +1394,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # summer (southern hemisphere).
     #
     # From
    -# 
     # http://www.safework.sa.gov.au/uploaded_files/DaylightDatesSet.pdf
    -# 
     # The extended daylight saving period that South Australia has been trialling
     # for over the last year is now set to be ongoing.
     # Daylight saving will continue to start on the first Sunday in October each
    @@ -1471,9 +1404,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # the ACT for all 52 weeks of the year...
     #
     # We have a wrap-up here:
    -# 
     # http://www.timeanddate.com/news/time/south-australia-extends-dst.html
    -# 
     ###############################################################################
     
     # New Zealand
    @@ -1482,7 +1413,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # the 1989/90 year was a trial of an extended "daylight saving" period.
     # This trial was deemed successful and the extended period adopted for
     # subsequent years (with the addition of a further week at the start).
    -# source -- phone call to Ministry of Internal Affairs Head Office.
    +# source - phone call to Ministry of Internal Affairs Head Office.
     
     # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
     # # The Country of New Zealand   (Australia's east island -) Gee they hate that!
    @@ -1524,6 +1455,19 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # that DST will begin on 2007-09-30 2008-04-06.
     # http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
     
    +# From Paul Eggert (2014-07-14):
    +# Chatham Island time was formally standardized on 1957-01-01 by
    +# New Zealand's Standard Time Amendment Act 1956 (1956-10-26).
    +# http://www.austlii.edu.au/nz/legis/hist_act/staa19561956n100244.pdf
    +# According to Google Books snippet view, a speaker in the New Zealand
    +# parliamentary debates in 1956 said "Clause 78 makes provision for standard
    +# time in the Chatham Islands.  The time there is 45 minutes in advance of New
    +# 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
    +# not observe New Zealand's prewar DST.
    +
     ###############################################################################
     
     
    @@ -1543,7 +1487,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     
     # From the BBC World Service in
     # http://news.bbc.co.uk/2/hi/asia-pacific/205226.stm (1998-10-31 16:03 UTC):
    -# The Fijiian government says the main reasons for the time change is to
    +# The Fijian government says the main reasons for the time change is to
     # improve productivity and reduce road accidents.... [T]he move is also
     # intended to boost Fiji's ability to attract tourists to witness the dawning
     # of the new millennium.
    @@ -1551,16 +1495,12 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
     # reports that Fiji has discontinued DST.
     
    -# Johnston
    -
    -# Johnston data is from usno1995.
    -
     
     # Kiribati
     
     # From Paul Eggert (1996-01-22):
     # Today's _Wall Street Journal_ (page 1) reports that Kiribati
    -# ``declared it the same day [throughout] the country as of Jan. 1, 1995''
    +# "declared it the same day [throughout] the country as of Jan. 1, 1995"
     # as part of the competition to be first into the 21st century.
     
     
    @@ -1575,8 +1515,8 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     
     # N Mariana Is, Guam
     
    -# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
    -# Philippines and the Ladrones from America,'' and implies that the Ladrones
    +# Howse writes (p 153) "The Spaniards, on the other hand, reached the
    +# Philippines and the Ladrones from America," and implies that the Ladrones
     # (now called the Marianas) kept American date for quite some time.
     # For now, we assume the Ladrones switched at the same time as the Philippines;
     # see Asia/Manila.
    @@ -1590,17 +1530,16 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # Micronesia
     
     # Alan Eugene Davis writes (1996-03-16),
    -# ``I am certain, having lived there for the past decade, that "Truk"
    -# (now properly known as Chuuk) ... is in the time zone GMT+10.''
    +# "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
     # 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)
    +# 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.
     
    @@ -1646,27 +1585,34 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # Sacramento but it was changed a couple of years ago.
     
     
    -# Samoa
    +# (Western) Samoa and American Samoa
     
     # Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
     # that in 1879 the King of Samoa decided to change
    -# ``the date in his kingdom from the Antipodean to the American system,
    -# ordaining -- by a masterpiece of diplomatic flattery -- that
    -# the Fourth of July should be celebrated twice in that year.''
    +# "the date in his kingdom from the Antipodean to the American system,
    +# 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
    +# 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,
    +# 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.
     
     # Tonga
     
     # From Paul Eggert (1996-01-22):
    -# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
    -# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
    +# Today's _Wall Street Journal_ (p 1) reports that "Tonga has been plotting
    +# to sneak ahead of [New Zealanders] by introducing daylight-saving time."
     # Since Kiribati has moved the Date Line it's not clear what Tonga will do.
     
     # Don Mundell writes in the 1997-02-20 Tonga Chronicle
    -# 
    -# How Tonga became `The Land where Time Begins'
    -# :
    -
    +# How Tonga became 'The Land where Time Begins':
    +# http://www.tongatapu.net.to/tonga/homeland/timebegins.htm
    +#
     # Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
     # 12 hours and 20 minutes ahead of GMT.  When New Zealand adjusted its
     # standard time in 1940s, Tonga had the choice of subtracting from its
    @@ -1674,8 +1620,8 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # advancing its time to maintain the differential of 13 degrees
     # (approximately 50 minutes ahead of New Zealand time).
     #
    -# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
    -# Tungi, preferred to ensure Tonga's title as the land where time
    +# Because His Majesty King Tāufaʻāhau Tupou IV, then Crown Prince
    +# Tungī, preferred to ensure Tonga's title as the land where time
     # begins, the Legislative Assembly approved the latter change.
     #
     # But some of the older, more conservative members from the outer
    @@ -1701,9 +1647,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # * Tonga will introduce DST in November
     #
     # I was given this link by John Letts:
    -# 
     # http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
    -# 
     #
     # I have not been able to find exact dates for the transition in November
     # yet. By reading this article it seems like Fiji will be 14 hours ahead
    @@ -1711,9 +1655,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # (12 + 1 hour DST).
     
     # From Arthur David Olson (1999-09-20):
    -# According to 
    -# http://www.tongaonline.com/news/sept1799.html
    -# :
    +# According to :
     # "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
     # and annually thereafter from the first Saturday in October through the
     # third Saturday of April.  Under the system approved by Privy Council on
    @@ -1731,7 +1673,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # instead of the original reported date April 16. Unfortunately, the article
     # is no longer available on the site, and I did not make a copy of the
     # text, and I have forgotten to report it here.
    -# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
    +# (Original URL was )
     
     # From Rives McDow (2000-12-01):
     # Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
    @@ -1751,7 +1693,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # From Vernice Anderson, Personal Secretary to Philip Jessup,
     # US Ambassador At Large (oral history interview, 1971-02-02):
     #
    -# Saturday, the 14th [of October, 1950] -- ...  The time was all the
    +# Saturday, the 14th [of October, 1950] - ...  The time was all the
     # more confusing at that point, because we had crossed the
     # International Date Line, thus getting two Sundays.  Furthermore, we
     # discovered that Wake Island had two hours of daylight saving time
    @@ -1796,7 +1738,7 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # on the high seas.  Whenever a ship was within the territorial waters of any
     # nation it would use that nation's standard time.  The captain was permitted
     # to change his ship's clocks at a time of his choice following his ship's
    -# entry into another zone time--he often chose midnight.  These zones were
    +# entry into another zone time - he often chose midnight.  These zones were
     # adopted by all major fleets between 1920 and 1925 but not by many
     # independent merchant ships until World War II.
     
    @@ -1804,6 +1746,6 @@ Zone	Pacific/Wallis	12:15:20 -	LMT	1901
     # (2005-03-20):
     #
     # The American Practical Navigator (2002)
    -# 
    +# http://pollux.nss.nima.mil/pubs/pubs_j_apn_sections.html?rid=187
     # talks only about the 180-degree meridian with respect to ships in
     # international waters; it ignores the international date line.
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/backward b/jdk/test/sun/util/calendar/zi/tzdata/backward
    index 5afe9a317ff..ba012f45733 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/backward
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/backward
    @@ -21,15 +21,15 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
     # This file provides links between current names for time zones
     # and their old names.  Many names changed in late 1993.
     
    +# Link	TARGET			LINK-NAME
     Link	Africa/Asmara		Africa/Asmera
    -Link	Africa/Bamako		Africa/Timbuktu
    +Link	Africa/Abidjan		Africa/Timbuktu
     Link	America/Argentina/Catamarca	America/Argentina/ComodRivadavia
     Link	America/Adak		America/Atka
     Link	America/Argentina/Buenos_Aires	America/Buenos_Aires
    @@ -50,8 +50,11 @@ Link	America/Port_of_Spain	America/Virgin
     Link	Pacific/Auckland	Antarctica/South_Pole
     Link	Asia/Ashgabat		Asia/Ashkhabad
     Link	Asia/Kolkata		Asia/Calcutta
    -Link	Asia/Chongqing		Asia/Chungking
    +Link	Asia/Shanghai		Asia/Chongqing
    +Link	Asia/Shanghai		Asia/Chungking
     Link	Asia/Dhaka		Asia/Dacca
    +Link	Asia/Shanghai		Asia/Harbin
    +Link	Asia/Urumqi		Asia/Kashgar
     Link	Asia/Kathmandu		Asia/Katmandu
     Link	Asia/Macau		Asia/Macao
     Link	Asia/Ho_Chi_Minh	Asia/Saigon
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/etcetera b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
    index ebaa5fdfc04..d2fb91c9dd6 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/etcetera
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
    @@ -21,7 +21,6 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    @@ -37,7 +36,7 @@ Zone	Etc/UTC		0	-	UTC
     Zone	Etc/UCT		0	-	UCT
     
     # The following link uses older naming conventions,
    -# but it belongs here, not in the file `backward',
    +# but it belongs here, not in the file 'backward',
     # as functions like gmtime load the "GMT" file to handle leap seconds properly.
     # We want this to work even on installations that omit the other older names.
     Link	Etc/GMT				GMT
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe
    index 226c393a0f2..0c5f5667da9 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/europe
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe
    @@ -21,15 +21,15 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
    -# From Paul Eggert (2006-03-22):
    +# From Paul Eggert (2014-05-31):
     # A good source for time zone historical data outside the U.S. is
     # Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
     # San Diego: ACS Publications, Inc. (2003).
    @@ -40,6 +40,9 @@
     # published semiannually.  Law sent in several helpful summaries
     # of the IATA's data after 1990.
     #
    +# A reliable and entertaining source about time zones is
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +#
     # Except where otherwise noted, Shanks & Pottenger is the source for
     # entries through 1991, and IATA SSIM is the source for entries afterwards.
     #
    @@ -49,9 +52,9 @@
     #	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
     #	which I found in the UCLA library.
     #
    -#	
     #	William Willett, The Waste of Daylight, 19th edition
    -#	 (1914-03)
    +#	
    +#	[PDF] (1914-03)
     #
     #	Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
     #	.  He writes:
    @@ -59,10 +62,20 @@
     #	may be sent to Mr. John Milne, Royal Geographical Society,
     #	Savile Row, London."  Nowadays please email them to tz@iana.org.
     #
    -#	Brazil's Departamento Servico da Hora (DSH),
    -#	
    +#	Byalokoz EL. New Counting of Time in Russia since July 1, 1919.
    +#	This Russian-language source was consulted by Vladimir Karpinsky; see
    +#	http://mm.icann.org/pipermail/tz/2014-August/021320.html
    +#	The full Russian citation is:
    +#	Бялокоз, Евгений Людвигович. Новый счет времени в течении суток
    +#	введенный декретом Совета народных комиссаров для всей России с 1-го
    +#	июля 1919 г. / Изд. 2-е Междуведомственной комиссии. - Петроград:
    +#	Десятая гос. тип., 1919.
    +#	http://resolver.gpntb.ru/purl?docushare/dsweb/Get/Resource-2011/Byalokoz__E.L.__Novyy__schet__vremeni__v__techenie__sutok__izd__2(1).pdf
    +#
    +#	Brazil's Divisão Serviço da Hora (DSHO),
     #	History of Summer Time
    -#	 (1998-09-21, in Portuguese)
    +#	
    +#	(1998-09-21, in Portuguese)
     
     #
     # I invented the abbreviations marked '*' in the following table;
    @@ -81,10 +94,8 @@
     #        1:00       CET CEST CEMT Central Europe
     #        1:00:14    SET           Swedish (1879-1899)*
     #        2:00       EET EEST      Eastern Europe
    -#        3:00       MSK MSD       Moscow
    -#
    -# A reliable and entertaining source about time zones, especially in Britain,
    -# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +#        3:00       FET           Further-eastern Europe*
    +#        3:00       MSK MSD  MSM* Moscow
     
     # From Peter Ilieve (1994-12-04),
     # The original six [EU members]: Belgium, France, (West) Germany, Italy,
    @@ -128,7 +139,7 @@
     # along the towpath within a few yards of it.'
     #
     # I have a one inch to one mile map of London and my estimate of the stone's
    -# position is 51 deg. 28' 30" N, 0 deg. 18' 45" W. The longitude should
    +# position is 51 degrees 28' 30" N, 0 degrees 18' 45" W. The longitude should
     # be within about +-2". The Ordnance Survey grid reference is TQ172761.
     #
     # [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
    @@ -160,8 +171,22 @@
     # transition date for London, namely 1847-12-01.  We don't know as much
     # about Dublin, so we use 1880-08-02, the legal transition time.
     
    -# From Paul Eggert (2003-09-27):
    -# Summer Time was first seriously proposed by William Willett (1857-1915),
    +# From Paul Eggert (2014-07-19):
    +# The ancients had no need for daylight saving, as they kept time
    +# informally or via hours whose length depended on the time of year.
    +# Daylight saving time in its modern sense was invented by the
    +# New Zealand entomologist George Vernon Hudson (1867-1946),
    +# whose day job as a postal clerk led him to value
    +# after-hours daylight in which to pursue his research.
    +# In 1895 he presented a paper to the Wellington Philosophical Society
    +# that proposed a two-hour daylight-saving shift.  See:
    +# Hudson GV. On seasonal time-adjustment in countries south of lat. 30 deg.
    +# Transactions and Proceedings of the New Zealand Institute. 1895;28:734
    +# http://rsnz.natlib.govt.nz/volume/rsnz_28/rsnz_28_00_006110.html
    +# Although some interest was expressed in New Zealand, his proposal
    +# did not find its way into law and eventually it was almost forgotten.
    +#
    +# In England, DST was independently reinvented by William Willett (1857-1915),
     # a London builder and member of the Royal Astronomical Society
     # who circulated a pamphlet "The Waste of Daylight" (1907)
     # that proposed advancing clocks 20 minutes on each of four Sundays in April,
    @@ -174,7 +199,7 @@
     # A monument to Willett was unveiled on 1927-05-21, in an open space in
     # a 45-acre wood near Chislehurst, Kent that was purchased by popular
     # subscription and open to the public.  On the south face of the monolith,
    -# designed by G. W. Miller, is the...William Willett Memorial Sundial,
    +# designed by G. W. Miller, is the William Willett Memorial Sundial,
     # which is permanently set to Summer Time.
     
     # From Winston Churchill (1934-04-28):
    @@ -183,9 +208,9 @@
     # between 160 and 170 hours more daylight leisure, to a war which
     # plunged Europe into darkness for four years, and shook the
     # foundations of civilization throughout the world.
    -#	-- 
    -#	"A Silent Toast to William Willett", Pictorial Weekly
    -#	
    +#	-- "A Silent Toast to William Willett", Pictorial Weekly;
    +#	republished in Finest Hour (Spring 2002) 1(114):26
    +#	http://www.winstonchurchill.org/images/finesthour/Vol.01%20No.114.pdf
     
     # From Paul Eggert (1996-09-03):
     # The OED Supplement says that the English originally said "Daylight Saving"
    @@ -194,7 +219,6 @@
     # proponents (who eventually won the argument) are quoted as using "Summer".
     
     # From Arthur David Olson (1989-01-19):
    -#
     # A source at the British Information Office in New York avers that it's
     # known as "British" Summer Time in all parts of the United Kingdom.
     
    @@ -221,8 +245,8 @@
     # official designation; the reply of the 21st was that there wasn't
     # but he couldn't think of anything better than the "Double British
     # Summer Time" that the BBC had been using informally.
    -# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
    -# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
    +# http://www.polyomino.org.uk/british-time/bbc-19410418.png
    +# http://www.polyomino.org.uk/british-time/ho-19410421.png
     
     # From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
     # [N]o official designation has as far as I know been adopted for the time
    @@ -239,23 +263,14 @@
     # the history of summer time legislation in the United Kingdom.
     # Since 1998 Joseph S. Myers has been updating
     # and extending this list, which can be found in
    -# http://student.cusu.cam.ac.uk/~jsm28/british-time/
    -# 
    -# History of legal time in Britain
    -# 
    -# Rob Crowther (2012-01-04) reports that that URL no longer
    -# exists, and the article can now be found at:
    -# 
     # http://www.polyomino.org.uk/british-time/
    -# 
     
     # From Joseph S. Myers (1998-01-06):
     #
     # The legal time in the UK outside of summer time is definitely GMT, not UTC;
     # see Lord Tanlaw's speech
    -# 
    -# (Lords Hansard 11 June 1997 columns 964 to 976)
    -# .
    +# http://www.publications.parliament.uk/pa/ld199798/ldhansrd/vo970611/text/70611-10.htm#70611-10_head0
    +# (Lords Hansard 11 June 1997 columns 964 to 976).
     
     # From Paul Eggert (2006-03-22):
     #
    @@ -295,8 +310,8 @@
     #   -- James Joyce, Ulysses
     
     # From Joseph S. Myers (2005-01-26):
    -# Irish laws are available online at www.irishstatutebook.ie.  These include
    -# various relating to legal time, for example:
    +# Irish laws are available online at .
    +# These include various relating to legal time, for example:
     #
     # ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
     #
    @@ -458,25 +473,27 @@ Rule	GB-Eire 1990	1995	-	Oct	Sun>=22	1:00u	0	GMT
     # Use Europe/London for Jersey, Guernsey, and the Isle of Man.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
    +Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1  0:00s
     			 0:00	GB-Eire	%s	1968 Oct 27
    -			 1:00	-	BST	1971 Oct 31 2:00u
    +			 1:00	-	BST	1971 Oct 31  2:00u
     			 0:00	GB-Eire	%s	1996
     			 0:00	EU	GMT/BST
     Link	Europe/London	Europe/Jersey
     Link	Europe/London	Europe/Guernsey
     Link	Europe/London	Europe/Isle_of_Man
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
    -			-0:25:21 -	DMT	1916 May 21 2:00
    -			-0:25:21 1:00	IST	1916 Oct  1 2:00s
    +			-0:25:21 -	DMT	1916 May 21  2:00
    +			-0:25:21 1:00	IST	1916 Oct  1  2:00s
     			 0:00	GB-Eire	%s	1921 Dec  6 # independence
    -			 0:00	GB-Eire	GMT/IST	1940 Feb 25 2:00
    -			 0:00	1:00	IST	1946 Oct  6 2:00
    -			 0:00	-	GMT	1947 Mar 16 2:00
    -			 0:00	1:00	IST	1947 Nov  2 2:00
    -			 0:00	-	GMT	1948 Apr 18 2:00
    +			 0:00	GB-Eire	GMT/IST	1940 Feb 25  2:00
    +			 0:00	1:00	IST	1946 Oct  6  2:00
    +			 0:00	-	GMT	1947 Mar 16  2:00
    +			 0:00	1:00	IST	1947 Nov  2  2:00
    +			 0:00	-	GMT	1948 Apr 18  2:00
     			 0:00	GB-Eire	GMT/IST	1968 Oct 27
    -			 1:00	-	IST	1971 Oct 31 2:00u
    +			 1:00	-	IST	1971 Oct 31  2:00u
     			 0:00	GB-Eire	GMT/IST	1996
     			 0:00	EU	GMT/IST
     
    @@ -495,10 +512,9 @@ Rule	EU	1979	1995	-	Sep	lastSun	 1:00u	0	-
     Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
     Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
     # The most recent directive covers the years starting in 2002.  See:
    -# 
     # Directive 2000/84/EC of the European Parliament and of the Council
     # of 19 January 2001 on summer-time arrangements.
    -# 
    +# http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=CELEX:32000L0084:EN:NOT
     
     # W-Eur differs from EU only in that W-Eur uses standard time.
     Rule	W-Eur	1977	1980	-	Apr	Sun>=1	 1:00s	1:00	S
    @@ -521,18 +537,18 @@ Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
     Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
     # Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
     Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
    -# From Jesper Norgaard Welen (2008-07-13):
    +# From Jesper Nørgaard Welen (2008-07-13):
     #
     # I found what is probably a typo of 2:00 which should perhaps be 2:00s
     # in the C-Eur rule from tz database version 2008d (this part was
    -# corrected in version 2008d). The circumstancial evidence is simply the
    +# corrected in version 2008d). The circumstantial evidence is simply the
     # tz database itself, as seen below:
     #
     # Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
     #    0:00 France WE%sT 1945 Sep 16  3:00
     #
     # Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
    -#    0:00 France WE%sT 1945 Sep 16 3:00
    +#    0:00 France WE%sT 1945 Sep 16  3:00
     #
     # Zone Europe/Belgrade 1:22:00 - LMT 1884
     #    1:00 1:00 CEST 1945 Sep 16  2:00s
    @@ -576,16 +592,16 @@ Rule	E-Eur	1981	max	-	Mar	lastSun	 0:00	1:00	S
     Rule	E-Eur	1996	max	-	Oct	lastSun	 0:00	0	-
     
     # 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
    -Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT	# Moscow Mean Time
    -Rule	Russia	1918	only	-	May	31	22:00	2:00	MDST	# Moscow Double Summer Time
    +Rule	Russia	1917	only	-	Jul	 1	23:00	1:00	MST  # Moscow Summer Time
    +Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT  # Moscow Mean Time
    +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
     Rule	Russia	1919	only	-	May	31	23:00	2:00	MDST
    -Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	S
    -Rule	Russia	1919	only	-	Aug	16	 0:00	0	-
    -Rule	Russia	1921	only	-	Feb	14	23:00	1:00	S
    -Rule	Russia	1921	only	-	Mar	20	23:00	2:00	M # Midsummer
    -Rule	Russia	1921	only	-	Sep	 1	 0:00	1:00	S
    +Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	MSD
    +Rule	Russia	1919	only	-	Aug	16	 0:00	0	MSK
    +Rule	Russia	1921	only	-	Feb	14	23:00	1:00	MSD
    +Rule	Russia	1921	only	-	Mar	20	23:00	2:00	MSM  # Midsummer
    +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):
     Rule	Russia	1981	1984	-	Apr	 1	 0:00	1:00	S
    @@ -607,14 +623,10 @@ Rule	Russia	1996	2010	-	Oct	lastSun	 2:00s	0	-
     # According to the law Russia is abolishing daylight saving time.
     #
     # Medvedev signed a law "On the Calculation of Time" (in russian):
    -# 
     # http://bmockbe.ru/events/?ID=7583
    -# 
     #
     # Medvedev signed a law on the calculation of the time (in russian):
    -# 
     # http://www.regnum.ru/news/polit/1413906.html
    -# 
     
     # From Arthur David Olson (2011-06-15):
     # Take "abolishing daylight saving time" to mean that time is now considered
    @@ -634,10 +646,10 @@ Zone	EET		2:00	EU	EE%sT
     # From Markus Kuhn (1996-07-12):
     # The official German names ... are
     #
    -#	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
    -#	Mitteleuropaeische Sommerzeit (MESZ)  = UTC+02:00
    +#	Mitteleuropäische Zeit (MEZ)         = UTC+01:00
    +#	Mitteleuropäische Sommerzeit (MESZ)  = UTC+02:00
     #
    -# as defined in the German Time Act (Gesetz ueber die Zeitbestimmung (ZeitG),
    +# as defined in the German Time Act (Gesetz über die Zeitbestimmung (ZeitG),
     # 1978-07-25, Bundesgesetzblatt, Jahrgang 1978, Teil I, S. 1110-1111)....
     # I wrote ... to the German Federal Physical-Technical Institution
     #
    @@ -692,7 +704,7 @@ Zone	Europe/Tirane	1:19:20 -	LMT	1914
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Andorra	0:06:04 -	LMT	1901
     			0:00	-	WET	1946 Sep 30
    -			1:00	-	CET	1985 Mar 31 2:00
    +			1:00	-	CET	1985 Mar 31  2:00
     			1:00	EU	CE%sT
     
     # Austria
    @@ -718,9 +730,9 @@ Rule	Austria	1980	only	-	Sep	28	0:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Vienna	1:05:21 -	LMT	1893 Apr
     			1:00	C-Eur	CE%sT	1920
    -			1:00	Austria	CE%sT	1940 Apr  1 2:00s
    -			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
    -			1:00	1:00	CEST	1945 Apr 12 2:00s
    +			1:00	Austria	CE%sT	1940 Apr  1  2:00s
    +			1:00	C-Eur	CE%sT	1945 Apr  2  2:00s
    +			1:00	1:00	CEST	1945 Apr 12  2:00s
     			1:00	-	CET	1946
     			1:00	Austria	CE%sT	1981
     			1:00	EU	CE%sT
    @@ -731,38 +743,29 @@ Zone	Europe/Vienna	1:05:21 -	LMT	1893 Apr
     # GMT+3 without DST (was GMT+2 with DST).
     #
     # Sources (Russian language):
    -# 1.
    -# 
     # http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
    -# 
    -# 2.
    -# 
     # http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
    -# 
    -# 3.
    -# 
     # http://news.tut.by/society/250578.html
    -# 
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Minsk	1:50:16 -	LMT	1880
    -			1:50	-	MMT	1924 May 2 # Minsk Mean Time
    +			1:50	-	MMT	1924 May  2 # Minsk Mean Time
     			2:00	-	EET	1930 Jun 21
     			3:00	-	MSK	1941 Jun 28
     			1:00	C-Eur	CE%sT	1944 Jul  3
     			3:00	Russia	MSK/MSD	1990
    -			3:00	-	MSK	1991 Mar 31 2:00s
    -			2:00	1:00	EEST	1991 Sep 29 2:00s
    -			2:00	-	EET	1992 Mar 29 0:00s
    -			2:00	1:00	EEST	1992 Sep 27 0:00s
    -			2:00	Russia	EE%sT	2011 Mar 27 2:00s
    -			3:00	-	FET # Further-eastern European Time
    +			3:00	-	MSK	1991 Mar 31  2:00s
    +			2:00	1:00	EEST	1991 Sep 29  2:00s
    +			2:00	-	EET	1992 Mar 29  0:00s
    +			2:00	1:00	EEST	1992 Sep 27  0:00s
    +			2:00	Russia	EE%sT	2011 Mar 27  2:00s
    +			3:00	-	FET
     
     # Belgium
     #
     # From Paul Eggert (1997-07-02):
     # Entries from 1918 through 1991 are taken from:
     #	Annuaire de L'Observatoire Royal de Belgique,
    -#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
    +#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe année, 1991
     #	(Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
     #	pp 8-9.
     # LMT before 1892 was 0:17:30, according to the official journal of Belgium:
    @@ -812,7 +815,7 @@ Rule	Belgium	1946	only	-	May	19	 2:00s	1:00	S
     Rule	Belgium	1946	only	-	Oct	 7	 2:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Brussels	0:17:30 -	LMT	1880
    -			0:17:30	-	BMT	1892 May  1 12:00 # Brussels MT
    +			0:17:30	-	BMT	1892 May  1 12:00  # Brussels MT
     			0:00	-	WET	1914 Nov  8
     			1:00	-	CET	1916 May  1  0:00
     			1:00	C-Eur	CE%sT	1918 Nov 11 11:00u
    @@ -828,8 +831,8 @@ Zone	Europe/Brussels	0:17:30 -	LMT	1880
     #
     # From Plamen Simenov via Steffen Thorsen (1999-09-09):
     # A document of Government of Bulgaria (No.94/1997) says:
    -# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
    -# EETDST --> EET is in 04:00 Local time in last Sunday of October
    +# EET -> EETDST is in 03:00 Local time in last Sunday of March ...
    +# EETDST -> EET is in 04:00 Local time in last Sunday of October
     #
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
    @@ -842,7 +845,7 @@ Zone	Europe/Sofia	1:33:16 -	LMT	1880
     			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
     			2:00	-	EET	1942 Nov  2  3:00
     			1:00	C-Eur	CE%sT	1945
    -			1:00	-	CET	1945 Apr 2 3:00
    +			1:00	-	CET	1945 Apr  2  3:00
     			2:00	-	EET	1979 Mar 31 23:00
     			2:00	Bulg	EE%sT	1982 Sep 26  2:00
     			2:00	C-Eur	EE%sT	1991
    @@ -866,15 +869,15 @@ Rule	Czech	1948	only	-	Apr	18	2:00s	1:00	S
     Rule	Czech	1949	only	-	Apr	 9	2:00s	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Prague	0:57:44 -	LMT	1850
    -			0:57:44	-	PMT	1891 Oct     # Prague Mean Time
    -			1:00	C-Eur	CE%sT	1944 Sep 17 2:00s
    +			0:57:44	-	PMT	1891 Oct    # Prague Mean Time
    +			1:00	C-Eur	CE%sT	1944 Sep 17  2:00s
     			1:00	Czech	CE%sT	1979
     			1:00	EU	CE%sT
     # Use Europe/Prague also for Slovakia.
     
     # Denmark, Faroe Islands, and Greenland
     
    -# From Jesper Norgaard Welen (2005-04-26):
    +# From Jesper Nørgaard Welen (2005-04-26):
     # http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
     # [introducing standard time] was in effect from 1894-01-01....
     # The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
    @@ -884,7 +887,7 @@ Zone	Europe/Prague	0:57:44 -	LMT	1850
     # http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
     #
     # This provoked a new law from 1974 to make possible summer time changes
    -# in subsequenet decrees with the law
    +# in subsequent decrees with the law
     # http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
     #
     # It seems however that no decree was set forward until 1980.  I have
    @@ -899,7 +902,7 @@ Zone	Europe/Prague	0:57:44 -	LMT	1850
     # was suspended on that night):
     # http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
     
    -# From Jesper Norgaard Welen (2005-06-11):
    +# From Jesper Nørgaard Welen (2005-06-11):
     # The Herning Folkeblad (1980-09-26) reported that the night between
     # Saturday and Sunday the clock is set back from three to two.
     
    @@ -923,11 +926,11 @@ Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
     			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
    -			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
    -			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
    +			 1:00	Denmark	CE%sT	1942 Nov  2  2:00s
    +			 1:00	C-Eur	CE%sT	1945 Apr  2  2:00
     			 1:00	Denmark	CE%sT	1980
     			 1:00	EU	CE%sT
    -Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
    +Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11 # Tórshavn
     			 0:00	-	WET	1981
     			 0:00	EU	WE%sT
     #
    @@ -939,11 +942,11 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
     # From Paul Eggert (2006-03-22):
     # Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
     # and left the EU on 1985-02-01.  It therefore should have been using EU
    -# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
    +# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthåb
     # used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
     # rules since at least 1991.  Assume EU rules since 1980.
     
    -# From Gwillin Law (2001-06-06), citing
    +# From Gwillim Law (2001-06-06), citing
     #  (2001-03-15),
     # and with translations corrected by Steffen Thorsen:
     #
    @@ -978,16 +981,16 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
     # DPC research station at Zackenberg.
     #
     # Scoresbysund and two small villages nearby keep time UTC-1 and use
    -# the same daylight savings time period as in West Greenland (Godthab).
    +# the same daylight savings time period as in West Greenland (Godthåb).
     #
    -# The rest of Greenland, including Godthab (this area, although it
    +# The rest of Greenland, including Godthåb (this area, although it
     # includes central Greenland, is known as west Greenland), keeps time
     # UTC-3, with daylight savings methods according to European rules.
     #
     # It is common procedure to use UTC 0 in the wilderness of East and
     # North Greenland, because it is mainly Icelandic aircraft operators
     # maintaining traffic in these areas.  However, the official status of
    -# this area is that it sticks with Godthab time.  This area might be
    +# this area is that it sticks with Godthåb time.  This area might be
     # considered a dual time zone in some respects because of this.
     
     # From Rives McDow (2001-11-19):
    @@ -996,8 +999,8 @@ Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
     
     # From Paul Eggert (2006-03-22):
     # From 1997 on the CIA map shows Danmarkshavn on GMT;
    -# the 1995 map as like Godthab.
    -# For lack of better info, assume they were like Godthab before 1996.
    +# the 1995 map as like Godthåb.
    +# For lack of better info, assume they were like Godthåb before 1996.
     # startkart.no says Thule does not observe DST, but this is clearly an error,
     # so go with Shanks & Pottenger for Thule transitions until this year.
     # For 2007 on assume Thule will stay in sync with US DST rules.
    @@ -1012,15 +1015,15 @@ Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
     #
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
    -			-3:00	-	WGT	1980 Apr  6 2:00
    +			-3:00	-	WGT	1980 Apr  6  2:00
     			-3:00	EU	WG%sT	1996
     			0:00	-	GMT
     Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
    -			-2:00	-	CGT	1980 Apr  6 2:00
    +			-2:00	-	CGT	1980 Apr  6  2:00
     			-2:00	C-Eur	CG%sT	1981 Mar 29
     			-1:00	EU	EG%sT
     Zone America/Godthab	-3:26:56 -	LMT	1916 Jul 28 # Nuuk
    -			-3:00	-	WGT	1980 Apr  6 2:00
    +			-3:00	-	WGT	1980 Apr  6  2:00
     			-3:00	EU	WG%sT
     Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
     			-4:00	Thule	A%sT
    @@ -1042,17 +1045,16 @@ Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
     # summer time next spring."
     
     # From Peter Ilieve (1998-11-04), heavily edited:
    -# 
     # The 1998-09-22 Estonian time law
    -# 
    +# http://trip.rk.ee/cgi-bin/thw?${BASE}=akt&${OOHTML}=rtd&TA=1998&TO=1&AN=1390
     # refers to the Eighth Directive and cites the association agreement between
    -# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
    +# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22-27, 120).
     #
     # I also asked [my relative] whether they use any standard abbreviation
     # for their standard and summer times. He says no, they use "suveaeg"
     # (summer time) and "talveaeg" (winter time).
     
    -# From The Baltic Times (1999-09-09)
    +# From The Baltic Times  (1999-09-09)
     # via Steffen Thorsen:
     # This year will mark the last time Estonia shifts to summer time,
     # a council of the ruling coalition announced Sept. 6....
    @@ -1070,19 +1072,19 @@ Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
     # The Estonian government has changed once again timezone politics.
     # Now we are using again EU rules.
     #
    -# From Urmet Jaanes (2002-03-28):
    +# From Urmet Jänes (2002-03-28):
     # The legislative reference is Government decree No. 84 on 2002-02-21.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Tallinn	1:39:00	-	LMT	1880
    -			1:39:00	-	TMT	1918 Feb # Tallinn Mean Time
    +			1:39:00	-	TMT	1918 Feb    # Tallinn Mean Time
     			1:00	C-Eur	CE%sT	1919 Jul
     			1:39:00	-	TMT	1921 May
     			2:00	-	EET	1940 Aug  6
     			3:00	-	MSK	1941 Sep 15
     			1:00	C-Eur	CE%sT	1944 Sep 22
    -			3:00	Russia	MSK/MSD	1989 Mar 26 2:00s
    -			2:00	1:00	EEST	1989 Sep 24 2:00s
    +			3:00	Russia	MSK/MSD	1989 Mar 26  2:00s
    +			2:00	1:00	EEST	1989 Sep 24  2:00s
     			2:00	C-Eur	EE%sT	1998 Sep 22
     			2:00	EU	EE%sT	1999 Nov  1
     			2:00	-	EET	2002 Feb 21
    @@ -1104,35 +1106,45 @@ Zone	Europe/Tallinn	1:39:00	-	LMT	1880
     # This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
     # Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
     # Finnish) at
    -#
    -# 
     # http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
    -# 
     #
     # Page 105 (56 in PDF version) has a handy table of all past daylight savings
     # transitions. It is easy enough to interpret without Finnish skills.
     #
     # This is also confirmed by Finnish Broadcasting Company's archive at:
    -#
    -# 
     # http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
    -# 
     #
     # The news clip from 1981 says that "the time between 2 and 3 o'clock does not
     # exist tonight."
     
    +# From Konstantin Hyppönen (2014-06-13):
    +# [Heikki Oja's book Aikakirja 2013]
    +# http://almanakka.helsinki.fi/images/aikakirja/Aikakirja2013kokonaan.pdf
    +# pages 104-105, including a scan from a newspaper published on Apr 2 1942
    +# say that ... [o]n Apr 2 1942, 24 o'clock (which means Apr 3 1942,
    +# 00:00), clocks were moved one hour forward. The newspaper
    +# mentions "on the night from Thursday to Friday"....
    +# On Oct 4 1942, clocks were moved at 1:00 one hour backwards.
    +#
    +# From Paul Eggert (2014-06-14):
    +# Go with Oja over Shanks.
    +
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
    -Rule	Finland	1942	only	-	Oct	3	0:00	0	-
    +Rule	Finland	1942	only	-	Apr	2	24:00	1:00	S
    +Rule	Finland	1942	only	-	Oct	4	1:00	0	-
     Rule	Finland	1981	1982	-	Mar	lastSun	2:00	1:00	S
     Rule	Finland	1981	1982	-	Sep	lastSun	3:00	0	-
    +
    +# Milne says Helsinki (Helsingfors) time was 1:39:49.2 (official document);
    +# round to nearest.
    +
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
    -			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
    +Zone	Europe/Helsinki	1:39:49 -	LMT	1878 May 31
    +			1:39:49	-	HMT	1921 May    # Helsinki Mean Time
     			2:00	Finland	EE%sT	1983
     			2:00	EU	EE%sT
     
    -# Aaland Is
    +# Åland Is
     Link	Europe/Helsinki	Europe/Mariehamn
     
     
    @@ -1140,14 +1152,14 @@ Link	Europe/Helsinki	Europe/Mariehamn
     
     # From Ciro Discepolo (2000-12-20):
     #
    -# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
    +# Henri Le Corre, Régimes horaires pour le monde entier, Éditions
     # Traditionnelles - Paris 2 books, 1993
     #
    -# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
    +# Gabriel, Traité de l'heure dans le monde, Guy Trédaniel,
     # Paris, 1991
     #
    -# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
    -# Guy tredaniel, Paris 1987
    +# Françoise Gauquelin, Problèmes de l'heure résolus en astrologie,
    +# Guy Trédaniel, Paris 1987
     
     
     #
    @@ -1188,16 +1200,16 @@ Rule	France	1939	only	-	Nov	18	23:00s	0	-
     Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
     # The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
     # write that they were used in Monaco and in many French locations.
    -# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
    -# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
    -# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
    +# Le Corre writes that the upper limit of the free zone was Arnéguy, Orthez,
    +# Mont-de-Marsan, Bazas, Langon, Lamothe-Montravel, Marœuil, La
    +# Rochefoucauld, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
     # Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
    -# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
    +# Paray-le-Monial, Montceau-les-Mines, Chalon-sur-Saône, Arbois,
     # Dole, Morez, St-Claude, and Collonges (Haute-Savoie).
     Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
     # Shanks & Pottenger say this transition occurred at Oct 6 1:00,
     # but go with Denis Excoffier (1997-12-12),
    -# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
    +# who quotes the Ephémérides astronomiques for 1998 from Bureau des Longitudes
     # as saying 5/10/41 22hUT.
     Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
     Rule	France	1942	only	-	Mar	 9	 0:00	2:00	M
    @@ -1218,7 +1230,7 @@ Rule	France	1976	only	-	Sep	26	 1:00	0	-
     # on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
    -			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
    +			0:09:21	-	PMT	1911 Mar 11  0:01 # Paris MT
     # Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
     			0:00	France	WE%sT	1940 Jun 14 23:00
     # Le Corre says Paris stuck with occupied-France time after the liberation;
    @@ -1235,15 +1247,13 @@ Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
     # Bundesanstalt contains DST information back to 1916.
     # [See tz-link.htm for the URL.]
     
    -# From Joerg Schilling (2002-10-23):
    +# From Jörg Schilling (2002-10-23):
     # In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
    -# 
    -# General [Nikolai] Bersarin.
    +# http://www.dhm.de/lemo/html/biografien/BersarinNikolai/
    +# General [Nikolai] Bersarin.
     
     # From Paul Eggert (2003-03-08):
    -# 
     # 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.
    @@ -1268,23 +1278,23 @@ Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
    -			1:00	C-Eur	CE%sT	1945 May 24 2:00
    +			1:00	C-Eur	CE%sT	1945 May 24  2:00
     			1:00 SovietZone	CE%sT	1946
     			1:00	Germany	CE%sT	1980
     			1:00	EU	CE%sT
     
     # From Tobias Conradi (2011-09-12):
    -# Busingen , surrounded by the Swiss canton
    +# Büsingen , surrounded by the Swiss canton
     # Schaffhausen, did not start observing DST in 1980 as the rest of DE
     # (West Germany at that time) and DD (East Germany at that time) did.
     # DD merged into DE, the area is currently covered by code DE in ISO 3166-1,
     # which in turn is covered by the zone Europe/Berlin.
     #
    -# Source for the time in Busingen 1980:
    +# Source for the time in Büsingen 1980:
     # http://www.srf.ch/player/video?id=c012c029-03b7-4c2b-9164-aa5902cd58d3
     
     # From Arthur David Olson (2012-03-03):
    -# Busingen and Zurich have shared clocks since 1970.
    +# Büsingen and Zurich have shared clocks since 1970.
     
     Link	Europe/Zurich	Europe/Busingen
     
    @@ -1295,8 +1305,8 @@ Link	Europe/Zurich	Europe/Busingen
     
     # Gibraltar
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
    -			0:00	GB-Eire	%s	1957 Apr 14 2:00
    +Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2  0:00s
    +			0:00	GB-Eire	%s	1957 Apr 14  2:00
     			1:00	-	CET	1982
     			1:00	EU	CE%sT
     
    @@ -1327,7 +1337,7 @@ Rule	Greece	1980	only	-	Apr	 1	0:00	1:00	S
     Rule	Greece	1980	only	-	Sep	28	0:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
    -			1:34:52	-	AMT	1916 Jul 28 0:01     # Athens MT
    +			1:34:52	-	AMT	1916 Jul 28  0:01 # Athens MT
     			2:00	Greece	EE%sT	1941 Apr 30
     			1:00	Greece	CE%sT	1944 Apr  4
     			2:00	Greece	EE%sT	1981
    @@ -1336,15 +1346,20 @@ Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
     			2:00	EU	EE%sT
     
     # Hungary
    +# From Paul Eggert (2014-07-15):
    +# Dates for 1916-1945 are taken from:
    +# Oross A. Jelen a múlt jövője: a nyári időszámítás Magyarországon 1916-1945.
    +# National Archives of Hungary (2012-10-29).
    +# http://mnl.gov.hu/a_het_dokumentuma/a_nyari_idoszamitas_magyarorszagon_19161945.html
    +# This source does not always give times, which are taken from Shanks
    +# & Pottenger (which disagree about the dates).
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Hungary	1918	only	-	Apr	 1	 3:00	1:00	S
    -Rule	Hungary	1918	only	-	Sep	29	 3:00	0	-
    +Rule	Hungary	1918	only	-	Sep	16	 3:00	0	-
     Rule	Hungary	1919	only	-	Apr	15	 3:00	1:00	S
    -Rule	Hungary	1919	only	-	Sep	15	 3:00	0	-
    -Rule	Hungary	1920	only	-	Apr	 5	 3:00	1:00	S
    -Rule	Hungary	1920	only	-	Sep	30	 3:00	0	-
    +Rule	Hungary	1919	only	-	Nov	24	 3:00	0	-
     Rule	Hungary	1945	only	-	May	 1	23:00	1:00	S
    -Rule	Hungary	1945	only	-	Nov	 3	 0:00	0	-
    +Rule	Hungary	1945	only	-	Nov	 1	 0:00	0	-
     Rule	Hungary	1946	only	-	Mar	31	 2:00s	1:00	S
     Rule	Hungary	1946	1949	-	Oct	Sun>=1	 2:00s	0	-
     Rule	Hungary	1947	1949	-	Apr	Sun>=4	 2:00s	1:00	S
    @@ -1360,7 +1375,7 @@ Rule	Hungary	1980	only	-	Apr	 6	 1:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
     			1:00	C-Eur	CE%sT	1918
    -			1:00	Hungary	CE%sT	1941 Apr  6  2:00
    +			1:00	Hungary	CE%sT	1941 Apr  8
     			1:00	C-Eur	CE%sT	1945
     			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
     			1:00	EU	CE%sT
    @@ -1423,7 +1438,7 @@ Rule	Iceland	1967	only	-	Oct	29	 1:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
     			-1:27:48 -	RMT	1908 # Reykjavik Mean Time?
    -			-1:00	Iceland	IS%sT	1968 Apr 7 1:00s
    +			-1:00	Iceland	IS%sT	1968 Apr  7  1:00s
     			 0:00	-	GMT
     
     # Italy
    @@ -1438,9 +1453,8 @@ Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
     # From Paul Eggert (2006-03-22):
     # For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
     # F. Pollastri
    -# 
     # Day-light Saving Time in Italy (2006-02-03)
    -# 
    +# http://toi.iriti.cnr.it/uk/ienitlt.html
     # ('FP' below), taken from an Italian National Electrotechnical Institute
     # publication. When the three sources disagree, guess who's right, as follows:
     #
    @@ -1500,8 +1514,8 @@ Rule	Italy	1978	only	-	Oct	 1	0:00s	0	-
     Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
    -			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
    -			1:00	Italy	CE%sT	1942 Nov  2 2:00s
    +			0:49:56	-	RMT	1893 Nov  1  0:00s # Rome Mean
    +			1:00	Italy	CE%sT	1942 Nov  2  2:00s
     			1:00	C-Eur	CE%sT	1944 Jul
     			1:00	Italy	CE%sT	1980
     			1:00	EU	CE%sT
    @@ -1548,18 +1562,18 @@ Link	Europe/Rome	Europe/San_Marino
     
     # From Andrei Ivanov (2000-03-06):
     # This year Latvia will not switch to Daylight Savings Time (as specified in
    -# 
     # The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
    -# 29-Feb-2000 (#79), in Latvian for subscribers only).
    +# 29-Feb-2000 (#79) ,
    +# in Latvian for subscribers only).
     
    -# 
    -# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
    -# 
    +# From RFE/RL Newsline
    +# http://www.rferl.org/newsline/2001/01/3-CEE/cee-030101.html
    +# (2001-01-03), noted after a heads-up by Rives McDow:
     # The Latvian government on 2 January decided that the country will
     # institute daylight-saving time this spring, LETA reported.
     # Last February the three Baltic states decided not to turn back their
     # clocks one hour in the spring....
    -# Minister of Economy Aigars Kalvitis noted that Latvia had too few
    +# Minister of Economy Aigars Kalvītis noted that Latvia had too few
     # daylight hours and thus decided to comply with a draft European
     # Commission directive that provides for instituting daylight-saving
     # time in EU countries between 2002 and 2006. The Latvian government
    @@ -1569,18 +1583,23 @@ Link	Europe/Rome	Europe/San_Marino
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Latvia	1989	1996	-	Mar	lastSun	 2:00s	1:00	S
     Rule	Latvia	1989	1996	-	Sep	lastSun	 2:00s	0	-
    +
    +# Milne 1899 says Riga was 1:36:28 (Polytechnique House time).
    +# Byalokoz 1919 says Latvia was 1:36:34.
    +# Go with Byalokoz.
    +
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Europe/Riga	1:36:24	-	LMT	1880
    -			1:36:24	-	RMT	1918 Apr 15 2:00 #Riga Mean Time
    -			1:36:24	1:00	LST	1918 Sep 16 3:00 #Latvian Summer
    -			1:36:24	-	RMT	1919 Apr  1 2:00
    -			1:36:24	1:00	LST	1919 May 22 3:00
    -			1:36:24	-	RMT	1926 May 11
    +Zone	Europe/Riga	1:36:34	-	LMT	1880
    +			1:36:34	-	RMT	1918 Apr 15  2:00 # Riga MT
    +			1:36:34	1:00	LST	1918 Sep 16  3:00 # Latvian ST
    +			1:36:34	-	RMT	1919 Apr  1  2:00
    +			1:36:34	1:00	LST	1919 May 22  3:00
    +			1:36:34	-	RMT	1926 May 11
     			2:00	-	EET	1940 Aug  5
     			3:00	-	MSK	1941 Jul
     			1:00	C-Eur	CE%sT	1944 Oct 13
    -			3:00	Russia	MSK/MSD	1989 Mar lastSun 2:00s
    -			2:00	1:00	EEST	1989 Sep lastSun 2:00s
    +			3:00	Russia	MSK/MSD	1989 Mar lastSun  2:00s
    +			2:00	1:00	EEST	1989 Sep lastSun  2:00s
     			2:00	Latvia	EE%sT	1997 Jan 21
     			2:00	EU	EE%sT	2000 Feb 29
     			2:00	-	EET	2001 Jan  2
    @@ -1614,7 +1633,7 @@ Link Europe/Zurich Europe/Vaduz
     # I would like to inform that in this year Lithuanian time zone
     # (Europe/Vilnius) was changed.
     
    -# From ELTA No. 972 (2582) (1999-09-29),
    +# From ELTA No. 972 (2582) (1999-09-29) ,
     # via Steffen Thorsen:
     # Lithuania has shifted back to the second time zone (GMT plus two hours)
     # to be valid here starting from October 31,
    @@ -1623,9 +1642,9 @@ Link Europe/Zurich Europe/Vaduz
     # motion to give up shifting to summer time in spring, as it was
     # already done by Estonia.
     
    -# From the 
    -# Fact File, Lithuanian State Department of Tourism
    -#  (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
    +# From the Fact File, Lithuanian State Department of Tourism
    +#  (2000-03-27):
    +# Local time is GMT+2 hours ..., no daylight saving.
     
     # From a user via Klaus Marten (2003-02-07):
     # As a candidate for membership of the European Union, Lithuania will
    @@ -1638,18 +1657,18 @@ Link Europe/Zurich Europe/Vaduz
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Vilnius	1:41:16	-	LMT	1880
    -			1:24:00	-	WMT	1917	    # Warsaw Mean Time
    +			1:24:00	-	WMT	1917        # Warsaw Mean Time
     			1:35:36	-	KMT	1919 Oct 10 # Kaunas Mean Time
     			1:00	-	CET	1920 Jul 12
     			2:00	-	EET	1920 Oct  9
     			1:00	-	CET	1940 Aug  3
     			3:00	-	MSK	1941 Jun 24
     			1:00	C-Eur	CE%sT	1944 Aug
    -			3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    -			2:00	1:00	EEST	1991 Sep 29 2:00s
    +			3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
    +			2:00	1:00	EEST	1991 Sep 29  2:00s
     			2:00	C-Eur	EE%sT	1998
    -			2:00	-	EET	1998 Mar 29 1:00u
    -			1:00	EU	CE%sT	1999 Oct 31 1:00u
    +			2:00	-	EET	1998 Mar 29  1:00u
    +			1:00	EU	CE%sT	1999 Oct 31  1:00u
     			2:00	-	EET	2003 Jan  1
     			2:00	EU	EE%sT
     
    @@ -1683,9 +1702,9 @@ Rule	Lux	1929	only	-	Apr	20	23:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Europe/Luxembourg	0:24:36 -	LMT	1904 Jun
     			1:00	Lux	CE%sT	1918 Nov 25
    -			0:00	Lux	WE%sT	1929 Oct  6 2:00s
    -			0:00	Belgium	WE%sT	1940 May 14 3:00
    -			1:00	C-Eur	WE%sT	1944 Sep 18 3:00
    +			0:00	Lux	WE%sT	1929 Oct  6  2:00s
    +			0:00	Belgium	WE%sT	1940 May 14  3:00
    +			1:00	C-Eur	WE%sT	1944 Sep 18  3:00
     			1:00	Belgium	CE%sT	1977
     			1:00	EU	CE%sT
     
    @@ -1702,9 +1721,9 @@ Rule	Malta	1975	1979	-	Apr	Sun>=15	2:00	1:00	S
     Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
     Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
    -			1:00	Italy	CE%sT	1942 Nov  2 2:00s
    -			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
    +Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2  0:00s # Valletta
    +			1:00	Italy	CE%sT	1942 Nov  2  2:00s
    +			1:00	C-Eur	CE%sT	1945 Apr  2  2:00s
     			1:00	Italy	CE%sT	1973 Mar 31
     			1:00	Malta	CE%sT	1981
     			1:00	EU	CE%sT
    @@ -1719,7 +1738,7 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
     # In early 1992 there was large-scale interethnic violence in the area
     # and it's possible that some Russophones continued to observe Moscow time.
     # But [two people] separately reported via
    -# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
    +# Jesper Nørgaard that as of 2001-01-24 Tiraspol was like Chisinau.
     # The Tiraspol entry has therefore been removed for now.
     #
     # From Alexander Krivenyshev (2011-10-17):
    @@ -1728,13 +1747,8 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
     # to the Winter Time).
     #
     # News (in Russian):
    -# 
     # http://www.kyivpost.ua/russia/news/pridnestrove-otkazalos-ot-perehoda-na-zimnee-vremya-30954.html
    -# 
    -#
    -# 
     # http://www.allmoldova.com/moldova-news/1249064116.html
    -# 
     #
     # The substance of this change (reinstatement of the Tiraspol entry)
     # is from a patch from Petr Machata (2011-10-17)
    @@ -1752,9 +1766,7 @@ Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
     # Following Moldova and neighboring Ukraine- Transnistria (Pridnestrovie)-
     # Tiraspol will go back to winter time on October 30, 2011.
     # News from Moldova (in russian):
    -# 
     # http://ru.publika.md/link_317061.html
    -# 
     
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -1777,8 +1789,8 @@ Zone	Europe/Chisinau	1:55:20 -	LMT	1880
     # more precise 0:09:21.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
    -			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    -			0:00	France	WE%sT	1945 Sep 16 3:00
    +			0:09:21	-	PMT	1911 Mar 11 # Paris Mean Time
    +			0:00	France	WE%sT	1945 Sep 16  3:00
     			1:00	France	CE%sT	1977
     			1:00	EU	CE%sT
     
    @@ -1822,8 +1834,8 @@ Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
     # was not until 1866 when they were all required by law to observe
     # Amsterdam mean time.
     
    -# The data before 1945 are taken from
    -# .
    +# The data entries before 1945 are taken from
    +# http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Neth	1916	only	-	May	 1	0:00	1:00	NST	# Netherlands Summer Time
    @@ -1854,8 +1866,8 @@ Rule	Neth	1945	only	-	Sep	16	2:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Europe/Amsterdam	0:19:32 -	LMT	1835
     			0:19:32	Neth	%s	1937 Jul  1
    -			0:20	Neth	NE%sT	1940 May 16 0:00 # Dutch Time
    -			1:00	C-Eur	CE%sT	1945 Apr  2 2:00
    +			0:20	Neth	NE%sT	1940 May 16  0:00 # Dutch Time
    +			1:00	C-Eur	CE%sT	1945 Apr  2  2:00
     			1:00	Neth	CE%sT	1977
     			1:00	EU	CE%sT
     
    @@ -1885,14 +1897,14 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
     # time they were declared as parts of Norway.  Svalbard was declared
     # as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan
     # Mayen by law of 1930-02-27 no 2, section 2. (From
    -# http://www.lovdata.no/all/nl-19250717-011.html and
    -# http://www.lovdata.no/all/nl-19300227-002.html).  The law/regulation
    +#  and
    +# ).  The law/regulation
     # for normal/standard time in Norway is from 1894-06-29 no 1 (came
     # into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a
     # part of this law since 1925/1930. (From
    -# http://www.lovdata.no/all/nl-18940629-001.html ) I have not been
    +# ) I have not been
     # able to find if Jan Mayen used a different time zone (e.g. -0100)
    -# before 1930. Jan Mayen has only been "inhabitated" since 1921 by
    +# before 1930. Jan Mayen has only been "inhabited" since 1921 by
     # Norwegian meteorologists and maybe used the same time as Norway ever
     # since 1921.  Svalbard (Arctic/Longyearbyen) has been inhabited since
     # before 1895, and therefore probably changed the local time somewhere
    @@ -1907,7 +1919,7 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
     #  says that the meteorologists
     # burned down their station in 1940 and left the island, but returned in
     # 1941 with a small Norwegian garrison and continued operations despite
    -# frequent air ttacks from Germans.  In 1943 the Americans established a
    +# frequent air attacks from Germans.  In 1943 the Americans established a
     # radiolocating station on the island, called "Atlantic City".  Possibly
     # the UT offset changed during the war, but I think it unlikely that
     # Jan Mayen used German daylight-saving rules.
    @@ -1918,7 +1930,7 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
     #  says that the Germans were
     # expelled on 1942-05-14.  However, small parties of Germans did return,
     # and according to Wilhelm Dege's book "War North of 80" (1954)
    -# 
    +# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html
     # the German armed forces at the Svalbard weather station code-named
     # Haudegen did not surrender to the Allies until September 1945.
     #
    @@ -1927,6 +1939,10 @@ Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
     Link	Europe/Oslo	Arctic/Longyearbyen
     
     # Poland
    +
    +# The 1919 dates and times can be found in Tygodnik Urzędowy nr 1 (1919-03-20),
    +#  pp 1-2.
    +
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
     Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
    @@ -1937,9 +1953,9 @@ Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
     Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
     Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
     # For 1946 on the source is Kazimierz Borkowski,
    -# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
    -# 
    -# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
    +# Toruń Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
    +# http://www.astro.uni.torun.pl/~kb/Artykuly/U-PA/Czas2.htm#tth_tAb1
    +# Thanks to Przemysław Augustyniak (2005-05-28) for this reference.
     # He also gives these further references:
     # Mon Pol nr 13, poz 162 (1995) 
     # Druk nr 2180 (2003) 
    @@ -1959,10 +1975,10 @@ Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
     Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Warsaw	1:24:00 -	LMT	1880
    -			1:24:00	-	WMT	1915 Aug  5   # Warsaw Mean Time
    -			1:00	C-Eur	CE%sT	1918 Sep 16 3:00
    +			1:24:00	-	WMT	1915 Aug  5 # Warsaw Mean Time
    +			1:00	C-Eur	CE%sT	1918 Sep 16  3:00
     			2:00	Poland	EE%sT	1922 Jun
    -			1:00	Poland	CE%sT	1940 Jun 23 2:00
    +			1:00	Poland	CE%sT	1940 Jun 23  2:00
     			1:00	C-Eur	CE%sT	1944 Oct
     			1:00	Poland	CE%sT	1977
     			1:00	W-Eur	CE%sT	1988
    @@ -1970,6 +1986,14 @@ Zone	Europe/Warsaw	1:24:00 -	LMT	1880
     
     # Portugal
     #
    +# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne:
    +# According to a Portuguese decree (1911-05-26)
    +# http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
    +# Lisbon was at -0:36:44.68, but switched to GMT on 1912-01-01 at 00:00.
    +# Round the old offset to -0:36:45.  This agrees with Willett but disagrees
    +# with Shanks, who says the transition occurred on 1911-05-24 at 00:00 for
    +# Europe/Lisbon, Atlantic/Azores, and Atlantic/Madeira.
    +#
     # From Rui Pedro Salgueiro (1992-11-12):
     # Portugal has recently (September, 27) changed timezone
     # (from WET to MET or CET) to harmonize with EEC.
    @@ -2049,35 +2073,34 @@ Rule	Port	1979	1982	-	Sep	lastSun	 1:00s	0	-
     Rule	Port	1980	only	-	Mar	lastSun	 0:00s	1:00	S
     Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
     Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
    +#
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
    -# Willett says 1912-01-01.  Go with Willett.
    -Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
    -			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
    -			 0:00	Port	WE%sT	1966 Apr  3 2:00
    -			 1:00	-	CET	1976 Sep 26 1:00
    -			 0:00	Port	WE%sT	1983 Sep 25 1:00s
    -			 0:00	W-Eur	WE%sT	1992 Sep 27 1:00s
    -			 1:00	EU	CE%sT	1996 Mar 31 1:00u
    +Zone	Europe/Lisbon	-0:36:45 -	LMT	1884
    +			-0:36:45 -	LMT	1912 Jan  1 # Lisbon Mean Time
    +			 0:00	Port	WE%sT	1966 Apr  3  2:00
    +			 1:00	-	CET	1976 Sep 26  1:00
    +			 0:00	Port	WE%sT	1983 Sep 25  1:00s
    +			 0:00	W-Eur	WE%sT	1992 Sep 27  1:00s
    +			 1:00	EU	CE%sT	1996 Mar 31  1:00u
     			 0:00	EU	WE%sT
    -Zone Atlantic/Azores	-1:42:40 -	LMT	1884		# Ponta Delgada
    -			-1:54:32 -	HMT	1911 May 24  # Horta Mean Time
    -			-2:00	Port	AZO%sT	1966 Apr  3 2:00 # Azores Time
    -			-1:00	Port	AZO%sT	1983 Sep 25 1:00s
    -			-1:00	W-Eur	AZO%sT	1992 Sep 27 1:00s
    -			 0:00	EU	WE%sT	1993 Mar 28 1:00u
    +Zone Atlantic/Azores	-1:42:40 -	LMT	1884        # Ponta Delgada
    +			-1:54:32 -	HMT	1912 Jan  1 # Horta Mean Time
    +			-2:00	Port	AZO%sT	1966 Apr  3  2:00  # Azores Time
    +			-1:00	Port	AZO%sT	1983 Sep 25  1:00s
    +			-1:00	W-Eur	AZO%sT	1992 Sep 27  1:00s
    +			 0:00	EU	WE%sT	1993 Mar 28  1:00u
     			-1:00	EU	AZO%sT
    -Zone Atlantic/Madeira	-1:07:36 -	LMT	1884		# Funchal
    -			-1:07:36 -	FMT	1911 May 24  # Funchal Mean Time
    -			-1:00	Port	MAD%sT	1966 Apr  3 2:00 # Madeira Time
    -			 0:00	Port	WE%sT	1983 Sep 25 1:00s
    +Zone Atlantic/Madeira	-1:07:36 -	LMT	1884        # Funchal
    +			-1:07:36 -	FMT	1912 Jan  1 # Funchal Mean Time
    +			-1:00	Port	MAD%sT	1966 Apr  3  2:00 # Madeira Time
    +			 0:00	Port	WE%sT	1983 Sep 25  1:00s
     			 0:00	EU	WE%sT
     
     # Romania
     #
     # From Paul Eggert (1999-10-07):
    -# 
    -# Nine O'clock (1998-10-23) reports that the switch occurred at
    +# Nine O'clock 
    +# (1998-10-23) reports that the switch occurred at
     # 04:00 local time in fall 1998.  For lack of better info,
     # assume that Romania and Moldova switched to EU rules in 1997,
     # the same year as Bulgaria.
    @@ -2094,32 +2117,28 @@ Rule	Romania	1991	1993	-	Mar	lastSun	 0:00s	1:00	S
     Rule	Romania	1991	1993	-	Sep	lastSun	 0:00s	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
    -			1:44:24	-	BMT	1931 Jul 24	# Bucharest MT
    -			2:00	Romania	EE%sT	1981 Mar 29 2:00s
    +			1:44:24	-	BMT	1931 Jul 24 # Bucharest MT
    +			2:00	Romania	EE%sT	1981 Mar 29  2:00s
     			2:00	C-Eur	EE%sT	1991
     			2:00	Romania	EE%sT	1994
     			2:00	E-Eur	EE%sT	1997
     			2:00	EU	EE%sT
     
    +
     # Russia
     
     # From Alexander Krivenyshev (2011-09-15):
     # Based on last Russian Government Decree # 725 on August 31, 2011
     # (Government document
    -# 
     # http://www.government.ru/gov/results/16355/print/
    -# 
     # in Russian)
     # there are few corrections have to be made for some Russian time zones...
     # All updated Russian Time Zones were placed in table and translated to English
     # by WorldTimeZone.com at the link below:
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_russia36.htm
    -# 
     
     # From Sanjeev Gupta (2011-09-27):
     # Scans of [Decree #23 of January 8, 1992] are available at:
    -# 
     # http://government.consultant.ru/page.aspx?1223966
     # They are in Cyrillic letters (presumably Russian).
     
    @@ -2128,16 +2147,12 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
     # changed in September 2011:
     #
     # One source is
    -# < a href="http://government.ru/gov/results/16355/>
     # http://government.ru/gov/results/16355/
    -# 
     # which, according to translate.google.com, begins "Decree of August 31,
     # 2011 No 725" and contains no other dates or "effective date" information.
     #
     # Another source is
    -# 
     # http://www.rg.ru/2011/09/06/chas-zona-dok.html
    -# 
     # which, according to translate.google.com, begins "Resolution of the
     # Government of the Russian Federation on August 31, 2011 N 725" and also
     # contains "Date first official publication: September 6, 2011 Posted on:
    @@ -2145,28 +2160,45 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
     # does not contain any "effective date" information.
     #
     # Another source is
    -# 
     # http://en.wikipedia.org/wiki/Oymyakonsky_District#cite_note-RuTime-7
    -# 
     # which, in note 8, contains "Resolution #725 of August 31, 2011...
     # Effective as of after 7 days following the day of the official publication"
     # but which does not contain any reference to September 6, 2011.
     #
     # The Wikipedia article refers to
    -# 
     # http://base.consultant.ru/cons/cgi/online.cgi?req=doc;base=LAW;n=118896
    -# 
     # which seems to copy the text of the government.ru page.
     #
     # Tobias Conradi combines Wikipedia's
     # "as of after 7 days following the day of the official publication"
    -# with www.rg.ru's "Date of first official publication: September 6, 2011" to get
    -# September 13, 2011 as the cutover date (unusually, a Tuesday, as Tobias Conradi notes).
    +# with www.rg.ru's "Date of first official publication: September 6, 2011" to
    +# get September 13, 2011 as the cutover date (unusually, a Tuesday, as Tobias
    +# Conradi notes).
     #
     # None of the sources indicates a time of day for changing clocks.
     #
     # Go with 2011-09-13 0:00s.
     
    +# From Alexander Krivenyshev (2014-07-01):
    +# According to the Russian news (ITAR-TASS News Agency)
    +# http://en.itar-tass.com/russia/738562
    +# the State Duma has approved ... the draft bill on returning to
    +# winter time standard and return Russia 11 time zones.  The new
    +# regulations will come into effect on October 26, 2014 at 02:00 ...
    +# http://asozd2.duma.gov.ru/main.nsf/%28Spravka%29?OpenAgent&RN=431985-6&02
    +# Here is a link where we put together table (based on approved Bill N
    +# 431985-6) with proposed 11 Russian time zones and corresponding
    +# areas/cities/administrative centers in the Russian Federation (in English):
    +# http://www.worldtimezone.com/dst_news/dst_news_russia65.html
    +#
    +# From Alexander Krivenyshev (2014-07-22):
    +# Putin signed the Federal Law 431985-6 ... (in Russian)
    +# http://itar-tass.com/obschestvo/1333711
    +# http://www.pravo.gov.ru:8080/page.aspx?111660
    +# http://www.kremlin.ru/acts/46279
    +# From October 26, 2014 the new Russian time zone map will looks like this:
    +# 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,
    @@ -2193,9 +2225,9 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
     #
     # For Grozny, Chechnya, we have the following story from
     # John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
    -# News--often false--is spread by word of mouth.  A rumor that it was
    +# News - often false - is spread by word of mouth.  A rumor that it was
     # time to move the clocks back put this whole city out of sync with
    -# the rest of Russia for two weeks--even soldiers stationed here began
    +# the rest of Russia for two weeks - even soldiers stationed here began
     # enforcing curfew at the wrong time.
     #
     # From Gwillim Law (2001-06-05):
    @@ -2206,107 +2238,265 @@ Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
     # since September 1997....  Although the Kuril Islands are
     # administratively part of Sakhalin oblast', they appear to have
     # remained on UTC+11 along with Magadan.
    -#
    +
    +# From Tim Parenti (2014-07-06):
    +# The comments detailing the coverage of each Russian zone are meant to assist
    +# with maintenance only and represent our best guesses as to which regions
    +# are covered by each zone.  They are not meant to be taken as an authoritative
    +# listing.  The region codes listed come from
    +# http://en.wikipedia.org/w/?title=Federal_subjects_of_Russia&oldid=611810498
    +# and are used for convenience only; no guarantees are made regarding their
    +# future stability.  ISO 3166-2:RU codes are also listed for first-level
    +# divisions where available.
    +
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -#
    -# Kaliningradskaya oblast'.
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Europe/Kaliningrad covers...
    +# 39	RU-KGD	Kaliningrad Oblast
    +
     Zone Europe/Kaliningrad	 1:22:00 -	LMT	1893 Apr
     			 1:00	C-Eur	CE%sT	1945
     			 2:00	Poland	CE%sT	1946
    -			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    -			 2:00	Russia	EE%sT	2011 Mar 27 2:00s
    -			 3:00	-	FET # Further-eastern European Time
    +			 3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
    +			 2:00	Russia	EE%sT	2011 Mar 27  2:00s
    +			 3:00	-	FET	2014 Oct 26  2:00s
    +			 2:00	-	EET
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Europe/Moscow covers...
    +# 01	RU-AD	Adygea, Republic of
    +# 05	RU-DA	Dagestan, Republic of
    +# 06	RU-IN	Ingushetia, Republic of
    +# 07	RU-KB	Kabardino-Balkar Republic
    +# 08	RU-KL	Kalmykia, Republic of
    +# 09	RU-KC	Karachay-Cherkess Republic
    +# 10	RU-KR	Karelia, Republic of
    +# 11	RU-KO	Komi Republic
    +# 12	RU-ME	Mari El Republic
    +# 13	RU-MO	Mordovia, Republic of
    +# 15	RU-SE	North Ossetia-Alania, Republic of
    +# 16	RU-TA	Tatarstan, Republic of
    +# 20	RU-CE	Chechen Republic
    +# 21	RU-CU	Chuvash Republic
    +# 23	RU-KDA	Krasnodar Krai
    +# 26	RU-STA	Stavropol Krai
    +# 29	RU-ARK	Arkhangelsk Oblast
    +# 31	RU-BEL	Belgorod Oblast
    +# 32	RU-BRY	Bryansk Oblast
    +# 33	RU-VLA	Vladimir Oblast
    +# 35	RU-VLG	Vologda Oblast
    +# 36	RU-VOR	Voronezh Oblast
    +# 37	RU-IVA	Ivanovo Oblast
    +# 40	RU-KLU	Kaluga Oblast
    +# 44	RU-KOS	Kostroma Oblast
    +# 46	RU-KRS	Kursk Oblast
    +# 47	RU-LEN	Leningrad Oblast
    +# 48	RU-LIP	Lipetsk Oblast
    +# 50	RU-MOS	Moscow Oblast
    +# 51	RU-MUR	Murmansk Oblast
    +# 52	RU-NIZ	Nizhny Novgorod Oblast
    +# 53	RU-NGR	Novgorod Oblast
    +# 57	RU-ORL	Oryol Oblast
    +# 58	RU-PNZ	Penza Oblast
    +# 60	RU-PSK	Pskov Oblast
    +# 61	RU-ROS	Rostov Oblast
    +# 62	RU-RYA	Ryazan Oblast
    +# 67	RU-SMO	Smolensk Oblast
    +# 68	RU-TAM	Tambov Oblast
    +# 69	RU-TVE	Tver Oblast
    +# 71	RU-TUL	Tula Oblast
    +# 73	RU-ULY	Ulyanovsk Oblast
    +# 76	RU-YAR	Yaroslavl Oblast
    +# 77	RU-MOW	Moscow
    +# 78	RU-SPE	Saint Petersburg
    +# 83	RU-NEN	Nenets Autonomous Okrug
    +
    +# From Vladimir Karpinsky (2014-07-08):
    +# LMT in Moscow (before Jul 3, 1916) is 2:30:17, that was defined by Moscow
    +# Observatory (coordinates: 55 deg. 45'29.70", 37 deg. 34'05.30")....
    +# LMT in Moscow since Jul 3, 1916 is 2:31:01 as a result of new standard.
    +# (The info is from the book by Byalokoz ... p. 18.)
    +# The time in St. Petersburg as capital of Russia was defined by
    +# Pulkov observatory, near St. Petersburg.  In 1916 LMT Moscow
    +# was synchronized with LMT St. Petersburg (+30 minutes), (Pulkov observatory
    +# coordinates: 59 deg. 46'18.70", 30 deg. 19'40.70") so 30 deg. 19'40.70" >
    +# 2h01m18.7s = 2:01:19.  LMT Moscow = LMT St.Petersburg + 30m 2:01:19 + 0:30 =
    +# 2:31:19 ...
     #
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Respublika Adygeya, Arkhangel'skaya oblast',
    -# Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
    -# Vologodskaya oblast', Voronezhskaya oblast',
    -# Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
    -# Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
    -# Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
    -# Respublika Kareliya, Respublika Komi,
    -# Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
    -# Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
    -# Respublika Mordoviya, Moskva, Moskovskaya oblast',
    -# Murmanskaya oblast', Nenetskij avtonomnyj okrug,
    -# Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
    -# Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
    -# Ryazanskaya oblast', Sankt-Peterburg,
    -# Respublika Severnaya Osetiya, Smolenskaya oblast',
    -# Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
    -# Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
    -# Chechenskaya Respublika, Chuvashskaya oblast',
    -# Yaroslavskaya oblast'
    -Zone Europe/Moscow	 2:30:20 -	LMT	1880
    -			 2:30	-	MMT	1916 Jul  3 # Moscow Mean Time
    -			 2:30:48 Russia	%s	1919 Jul  1 2:00
    +# From Paul Eggert (2014-07-08):
    +# Milne does not list Moscow, but suggests that its time might be listed in
    +# Résumés mensuels et annuels des observations météorologiques (1895).
    +# Presumably this is OCLC 85825704, a journal published with parallel text in
    +# Russian and French.  This source has not been located; go with Karpinsky.
    +
    +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
    +			 3:00	Russia	%s	1921 Oct
     			 3:00	Russia	MSK/MSD	1922 Oct
     			 2:00	-	EET	1930 Jun 21
    -			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    -			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
    -			 3:00	Russia	MSK/MSD	2011 Mar 27 2:00s
    -			 4:00	-	MSK
    +			 3:00	Russia	MSK/MSD	1991 Mar 31  2:00s
    +			 2:00	Russia	EE%sT	1992 Jan 19  2:00s
    +			 3:00	Russia	MSK/MSD	2011 Mar 27  2:00s
    +			 4:00	-	MSK	2014 Oct 26  2:00s
    +			 3:00	-	MSK
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Europe/Simferopol covers...
    +# **	****	Crimea, Republic of
    +# **	****	Sevastopol
    +
    +Zone Europe/Simferopol	 2:16:24 -	LMT	1880
    +			 2:16	-	SMT	1924 May  2 # Simferopol Mean T
    +			 2:00	-	EET	1930 Jun 21
    +			 3:00	-	MSK	1941 Nov
    +			 1:00	C-Eur	CE%sT	1944 Apr 13
    +			 3:00	Russia	MSK/MSD	1990
    +			 3:00	-	MSK	1990 Jul  1  2:00
    +			 2:00	-	EET	1992
    +# Central Crimea used Moscow time 1994/1997.
     #
    -# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
    -# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
    -# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
    -# others?  But we have no data.
    +# From Paul Eggert (2006-03-22):
    +# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
    +# from Kiev to Moscow time sometime after the January 1994 elections.
    +# Shanks (1999) says "date of change uncertain", but implies that it happened
    +# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
    +# 1994-09-25 03:00, but that can't be right.  For now, guess it
    +# changed in May.
    +			 2:00	E-Eur	EE%sT	1994 May
    +# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
    +			 3:00	E-Eur	MSK/MSD	1996 Mar 31  3:00s
    +			 3:00	1:00	MSD	1996 Oct 27  3:00s
    +# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
    +# Assume it happened in March by not changing the clocks.
    +			 3:00	Russia	MSK/MSD	1997
    +			 3:00	-	MSK	1997 Mar lastSun  1:00u
    +# From Alexander Krivenyshev (2014-03-17):
    +# time change at 2:00 (2am) on March 30, 2014
    +# http://vz.ru/news/2014/3/17/677464.html
    +# From Paul Eggert (2014-03-30):
    +# Simferopol and Sevastopol reportedly changed their central town clocks
    +# late the previous day, but this appears to have been ceremonial
    +# and the discrepancies are small enough to not worry about.
    +			 2:00	EU	EE%sT	2014 Mar 30  2:00
    +			 4:00	-	MSK	2014 Oct 26  2:00s
    +			 3:00	-	MSK
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Europe/Volgograd covers...
    +# 30	RU-AST	Astrakhan Oblast
    +# 34	RU-VGG	Volgograd Oblast
    +# 43	RU-KIR	Kirov Oblast
    +# 64	RU-SAR	Saratov Oblast
    +
    +# From Paul Eggert (2006-05-09):
    +# Shanks & Pottenger say Kirov is still at +0400 but Wikipedia says +0300.
    +# Perhaps it switched after the others?  But we have no data.
    +
     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	1989 Mar 26 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	VOL%sT	2011 Mar 27 2:00s
    -			 4:00	-	VOLT
    -#
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Samarskaya oblast', Udmyrtskaya respublika
    -Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
    +			 4:00	Russia	VOL%sT	1989 Mar 26  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	2011 Mar 27  2:00s
    +			 4:00	-	MSK	2014 Oct 26  2:00s
    +			 3:00	-	MSK
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Europe/Samara covers...
    +# 18	RU-UD	Udmurt Republic
    +# 63	RU-SAM	Samara Oblast
    +
    +# Byalokoz 1919 says Samara was 3:20:20.
    +
    +Zone Europe/Samara	 3:20:20 -	LMT	1919 Jul  1  2:00
     			 3:00	-	SAMT	1930 Jun 21
     			 4:00	-	SAMT	1935 Jan 27
    -			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
    -			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
    -			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
    -			 3:00	-	KUYT	1991 Oct 20 3:00
    -			 4:00	Russia	SAM%sT	2010 Mar 28 2:00s # Samara Time
    -			 3:00	Russia	SAM%sT	2011 Mar 27 2:00s
    +			 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	-	KUYT	1991 Oct 20  3:00
    +			 4:00	Russia	SAM%sT	2010 Mar 28  2:00s # Samara Time
    +			 3:00	Russia	SAM%sT	2011 Mar 27  2:00s
     			 4:00	-	SAMT
     
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Asia/Yekaterinburg covers...
    +# 02	RU-BA	Bashkortostan, Republic of
    +# 90	RU-PER	Perm Krai
    +# 45	RU-KGN	Kurgan Oblast
    +# 56	RU-ORE	Orenburg Oblast
    +# 66	RU-SVE	Sverdlovsk Oblast
    +# 72	RU-TYU	Tyumen Oblast
    +# 74	RU-CHE	Chelyabinsk Oblast
    +# 86	RU-KHM	Khanty-Mansi Autonomous Okrug - Yugra
    +# 89	RU-YAN	Yamalo-Nenets Autonomous Okrug
     #
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
    -# Kurganskaya oblast', Orenburgskaya oblast', Permskaya oblast',
    -# Sverdlovskaya oblast', Tyumenskaya oblast',
    -# Khanty-Manskijskij avtonomnyj okrug, Chelyabinskaya oblast',
    -# Yamalo-Nenetskij avtonomnyj okrug.
    -Zone Asia/Yekaterinburg	 4:02:24 -	LMT	1919 Jul 15 4:00
    +# Note: Effective 2005-12-01, (59) Perm Oblast and (81) Komi-Permyak
    +# Autonomous Okrug merged to form (90, RU-PER) Perm Krai.
    +
    +# Milne says Yekaterinburg was 4:02:32.9; round to nearest.
    +# Byalokoz 1919 says its provincial time was based on Perm, at 3:45:05.
    +# Assume it switched on 1916-07-03, the time of the new standard.
    +# The 1919 and 1930 transitions are from Shanks.
    +
    +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	# Yekaterinburg Time
    -#
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Respublika Altaj, Altajskij kraj, Omskaya oblast'.
    -Zone Asia/Omsk		 4:53:36 -	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
    -#
    +			 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
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Asia/Omsk covers...
    +# 04	RU-AL	Altai Republic
    +# 22	RU-ALT	Altai Krai
    +# 55	RU-OMS	Omsk Oblast
    +
    +# 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
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Novosibirsk covers...
    +# 54	RU-NVS	Novosibirsk Oblast
    +# 70	RU-TOM	Tomsk Oblast
    +
     # From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
     # not clear when it switched from +7 to +6.
    -# Novosibirskaya oblast', Tomskaya oblast'.
    -Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
    +
    +Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14  6:00
     			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
    -			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
    -			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
    +			 7:00	Russia	NOV%sT	1991 Mar 31  2:00s
    +			 6:00	Russia	NOV%sT	1992 Jan 19  2:00s
     			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
    -			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
    -			 7:00	-	NOVT
    +			 6:00	Russia	NOV%sT	2011 Mar 27  2:00s
    +			 7:00	-	NOVT	2014 Oct 26  2:00s
    +			 6:00	-	NOVT
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Novokuznetsk covers...
    +# 42	RU-KEM	Kemerovo Oblast
     
     # From Alexander Krivenyshev (2009-10-13):
     # Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
    @@ -2319,14 +2509,10 @@ Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
     # time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
     #
     # Russian Government web site (Russian language)
    -# 
     # http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
    -# 
     # or Russian-English translation by WorldTimeZone.com with reference
     # map to local region and new Russia Time Zone map after March 28, 2010
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_russia03.html
    -# 
     #
     # Thus, when Russia will switch to DST on the night of March 28, 2010
     # Kemerovo region (Kemerovo oblast') will not change the clock.
    @@ -2334,152 +2520,319 @@ Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
     # As a result, Kemerovo oblast' will be in the same time zone as
     # Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
     
    +# From Tim Parenti (2014-07-02), per Alexander Krivenyshev (2014-07-02):
    +# The Kemerovo region will remain at UTC+7 through the 2014-10-26 change, thus
    +# realigning itself with KRAT.
    +
     Zone Asia/Novokuznetsk	 5:48:48 -	NMT	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	2010 Mar 28 2:00s
    -			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
    -			 7:00	-	NOVT # Novosibirsk/Novokuznetsk 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	2010 Mar 28  2:00s
    +			 6:00	Russia	NOV%sT	2011 Mar 27  2:00s # Novosibirsk
    +			 7:00	-	NOVT	2014 Oct 26  2:00s
    +			 7:00	-	KRAT	# Krasnoyarsk Time
     
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Asia/Krasnoyarsk covers...
    +# 17	RU-TY	Tuva Republic
    +# 19	RU-KK	Khakassia, Republic of
    +# 24	RU-KYA	Krasnoyarsk Krai
     #
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Krasnoyarskij kraj,
    -# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
    -# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
    -Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
    +# Note: Effective 2007-01-01, (88) Evenk Autonomous Okrug and (84) Taymyr
    +# Autonomous Okrug were merged into (24, RU-KYA) Krasnoyarsk Krai.
    +
    +# 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
    +			 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
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Asia/Irkutsk covers...
    +# 03	RU-BU	Buryatia, Republic of
    +# 38	RU-IRK	Irkutsk Oblast
     #
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Respublika Buryatiya, Irkutskaya oblast',
    -# Ust'-Ordynskij Buryatskij avtonomnyj okrug.
    -Zone Asia/Irkutsk	 6:57:20 -	LMT	1880
    -			 6:57:20 -	IMT	1920 Jan 25 # Irkutsk Mean Time
    +# Note: Effective 2008-01-01, (85) Ust-Orda Buryat Autonomous Okrug was
    +# merged into (38, RU-IRK) Irkutsk Oblast.
    +
    +# Milne 1899 says Irkutsk was 6:57:15.
    +# Byalokoz 1919 says Irkutsk was 6:57:05.
    +# Go with Byalokoz.
    +
    +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
    +			 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
    +
    +
    +# From Tim Parenti (2014-07-06):
    +# Asia/Chita covers...
    +# 92	RU-ZAB	Zabaykalsky Krai
     #
    -# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    -# Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
    -# [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
    +# Note: Effective 2008-03-01, (75) Chita Oblast and (80) Agin-Buryat
    +# Autonomous Okrug merged to form (92, RU-ZAB) Zabaykalsky Krai.
     
    -# From Oscar van Vlijmen (2009-11-29):
    -# ...some regions of [Russia] were merged with others since 2005...
    -# Some names were changed, no big deal, except for one instance: a new name.
    -# YAK/YAKST: UTC+9 Zabajkal'skij kraj.
    -
    -# From Oscar van Vlijmen (2009-11-29):
    -# The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
    -# Verkhnevilyujskij, Vilyujskij, Gornyj,
    -# Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
    -# Namskij, Nyurbinskij, Olenyokskij, Olyokminskij,
    -# Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
    -# Churapchinskij, Eveno-Bytantajskij Natsional'nij.
    -
    -Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
    +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
    -#
    -# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    -# Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
    -# [parts of] Respublika Sakha (Yakutiya).
    +			 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
     
    -# From Oscar van Vlijmen (2009-11-29):
    -# The Sakha districts are: Bulunskij, Verkhoyanskij, ... Ust'-Yanskij.
    -Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
    +# Asia/Yakutsk covers...
    +# 28	RU-AMU	Amur Oblast
    +#
    +# ...and parts of (14, RU-SA) Sakha (Yakutia) Republic:
    +# 14-02	****	Aldansky District
    +# 14-04	****	Amginsky District
    +# 14-05	****	Anabarsky District
    +# 14-06	****	Bulunsky District
    +# 14-07	****	Verkhnevilyuysky District
    +# 14-10	****	Vilyuysky District
    +# 14-11	****	Gorny District
    +# 14-12	****	Zhigansky District
    +# 14-13	****	Kobyaysky District
    +# 14-14	****	Lensky District
    +# 14-15	****	Megino-Kangalassky District
    +# 14-16	****	Mirninsky District
    +# 14-18	****	Namsky District
    +# 14-19	****	Neryungrinsky District
    +# 14-21	****	Nyurbinsky District
    +# 14-23	****	Olenyoksky District
    +# 14-24	****	Olyokminsky District
    +# 14-26	****	Suntarsky District
    +# 14-27	****	Tattinsky District
    +# 14-29	****	Ust-Aldansky District
    +# 14-32	****	Khangalassky District
    +# 14-33	****	Churapchinsky District
    +# 14-34	****	Eveno-Bytantaysky National District
    +
    +# From Tim Parenti (2014-07-03):
    +# Our commentary seems to have lost mention of (14-19) Neryungrinsky District.
    +# Since the surrounding districts of Sakha are all YAKT, assume this is, too.
    +# Also assume its history has been the same as the rest of Asia/Yakutsk.
    +
    +# 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
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
    +# Asia/Vladivostok covers...
    +# 25	RU-PRI	Primorsky Krai
    +# 27	RU-KHA	Khabarovsk Krai
    +# 79	RU-YEV	Jewish Autonomous Oblast
    +#
    +# ...and parts of (14, RU-SA) Sakha (Yakutia) Republic:
    +# 14-09	****	Verkhoyansky District
    +# 14-31	****	Ust-Yansky District
    +
    +# Milne 1899 says Vladivostok was 8:47:33.5.
    +# Byalokoz 1919 says Vladivostok was 8:47:31.
    +# 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%sST	1992 Jan 19 2:00s
    -			10:00	Russia	VLA%sT	2011 Mar 27 2:00s
    -			11:00	-	VLAT
    +			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
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Khandyga covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
    +# 14-28	****	Tomponsky District
    +# 14-30	****	Ust-Maysky District
     
     # From Arthur David Olson (2012-05-09):
     # Tomponskij and Ust'-Majskij switched from Vladivostok time to Yakutsk time
     # in 2011.
    -#
    +
     # From Paul Eggert (2012-11-25):
     # Shanks and Pottenger (2003) has Khandyga on Yakutsk time.
     # Make a wild guess that it switched to Vladivostok time in 2004.
     # 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	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
    +			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
     
    -#
    -# Sakhalinskaya oblast'.
    -# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Sakhalin covers...
    +# 65	RU-SAK	Sakhalin Oblast
    +# ...with the exception of:
    +# 65-11	****	Severo-Kurilsky District (North Kuril Islands)
    +
    +# 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	-	CJT	1938
    +			 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
    -#
    -# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    -# Magadanskaya oblast', Respublika Sakha (Yakutiya).
    -# Probably also: Kuril Islands.
    +			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
    +
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
    +# Asia/Magadan covers...
    +# 49	RU-MAG	Magadan Oblast
    +
    +# From Tim Parenti (2014-07-06), per Alexander Krivenyshev (2014-07-02):
    +# Magadan Oblast is moving from UTC+12 to UTC+10 on 2014-10-26; however,
    +# several districts of Sakha Republic as well as Severo-Kurilsky District of
    +# the Sakhalin Oblast (also known as the North Kuril Islands), represented
    +# until now by Asia/Magadan, will instead move to UTC+11.  These regions will
    +# need their own zone.
     
    -# From Oscar van Vlijmen (2009-11-29):
    -# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
    -# Nizhnekolymskij, ... Srednekolymskij.
     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
    +			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
    +
    +
    +# From Tim Parenti (2014-07-06):
    +# Asia/Srednekolymsk covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
    +# 14-01	****	Abyysky District
    +# 14-03	****	Allaikhovsky District
    +# 14-08	****	Verkhnekolymsky District
    +# 14-17	****	Momsky District
    +# 14-20	****	Nizhnekolymsky District
    +# 14-25	****	Srednekolymsky District
    +#
    +# ...and parts of (65, RU-SAK) Sakhalin Oblast:
    +# 65-11	****	Severo-Kurilsky District (North Kuril Islands)
    +
    +# From Tim Parenti (2014-07-02):
    +# Oymyakonsky District of Sakha Republic (represented by Ust-Nera), along with
    +# most of Sakhalin Oblast (represented by Sakhalin) will be moving to UTC+10 on
    +# 2014-10-26 to stay aligned with VLAT/SAKT; however, Severo-Kurilsky District
    +# of the Sakhalin Oblast (also known as the North Kuril Islands, represented by
    +# Severo-Kurilsk) will remain on UTC+11.
    +
    +# From Tim Parenti (2014-07-06):
    +# Assume North Kuril Islands have history like Magadan before 2011-03-27.
    +# There is a decent chance this is wrong, in which case a new zone
    +# Asia/Severo-Kurilsk would become necessary.
    +#
    +# Srednekolymsk and Zyryanka are the most populous places amongst these
    +# districts, but have very similar populations.  In fact, Wikipedia currently
    +# lists them both as having 3528 people, exactly 1668 males and 1860 females
    +# each!  (Yikes!)
    +# http://en.wikipedia.org/w/?title=Srednekolymsky_District&oldid=603435276
    +# http://en.wikipedia.org/w/?title=Verkhnekolymsky_District&oldid=594378493
    +# Assume this is a mistake, albeit an amusing one.
    +#
    +# Looking at censuses, the populations of the two municipalities seem to have
    +# fluctuated recently.  Zyryanka was more populous than Srednekolymsk in the
    +# 1989 and 2002 censuses, but Srednekolymsk was more populous in the most
    +# recent (2010) census, 3525 to 3170.  (See pages 195 and 197 of
    +# http://www.gks.ru/free_doc/new_site/perepis2010/croc/Documents/Vol1/pub-01-05.pdf
    +# 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
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Ust-Nera covers parts of (14, RU-SA) Sakha (Yakutia) Republic:
    +# 14-22	****	Oymyakonsky District
     
     # From Arthur David Olson (2012-05-09):
    -# Ojmyakonskij and the Kuril Islands switched from
    +# Ojmyakonskij [and the Kuril Islands] switched from
     # Magadan time to Vladivostok time in 2011.
    +#
    +# From Tim Parenti (2014-07-06), per Alexander Krivenyshev (2014-07-02):
    +# It's unlikely that any of the Kuril Islands were involved in such a switch,
    +# as the South and Middle Kurils have been on UTC+11 (SAKT) with the rest of
    +# Sakhalin Oblast since at least 2011-09, and the North Kurils have been on
    +# 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
    +			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
     
    -# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    -# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
    +
    +# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
    +# Asia/Kamchatka covers...
    +# 91	RU-KAM	Kamchatka Krai
     #
    -# The Zone name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
    +# Note: Effective 2007-07-01, (41) Kamchatka Oblast and (82) Koryak
    +# Autonomous Okrug merged to form (91, RU-KAM) Kamchatka Krai.
    +
    +# 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	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
    -#
    -# Chukotskij avtonomnyj okrug
    +
    +
    +# From Tim Parenti (2014-07-03):
    +# Asia/Anadyr covers...
    +# 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
    +			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
     
    +
     # San Marino
     # See Europe/Rome.
     
    @@ -2488,11 +2841,11 @@ Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
     Zone	Europe/Belgrade	1:22:00	-	LMT	1884
     			1:00	-	CET	1941 Apr 18 23:00
     			1:00	C-Eur	CE%sT	1945
    -			1:00	-	CET	1945 May 8 2:00s
    +			1:00	-	CET	1945 May  8  2:00s
     			1:00	1:00	CEST	1945 Sep 16  2:00s
    -# Metod Kozelj reports that the legal date of
    +# Metod Koželj reports that the legal date of
     # transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
    -# Shanks & Pottenger don't give as much detail, so go with Kozelj.
    +# Shanks & Pottenger don't give as much detail, so go with Koželj.
     			1:00	-	CET	1982 Nov 27
     			1:00	EU	CE%sT
     Link Europe/Belgrade Europe/Ljubljana	# Slovenia
    @@ -2568,13 +2921,13 @@ Zone	Africa/Ceuta	-0:21:16 -	LMT	1901
     			 0:00	1:00	WEST	1918 Oct  7 23:00
     			 0:00	-	WET	1924
     			 0:00	Spain	WE%sT	1929
    -			 0:00 SpainAfrica WE%sT 1984 Mar 16
    +			 0:00 SpainAfrica WE%sT	1984 Mar 16
     			 1:00	-	CET	1986
     			 1:00	EU	CE%sT
     Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
    -			-1:00	-	CANT	1946 Sep 30 1:00 # Canaries Time
    -			 0:00	-	WET	1980 Apr  6 0:00s
    -			 0:00	1:00	WEST	1980 Sep 28 0:00s
    +			-1:00	-	CANT	1946 Sep 30  1:00 # Canaries T
    +			 0:00	-	WET	1980 Apr  6  0:00s
    +			 0:00	1:00	WEST	1980 Sep 28  0:00s
     			 0:00	EU	WE%sT
     # IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
     # Ignore this for now, as the Canaries are part of the EU.
    @@ -2583,7 +2936,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
     
     # From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
     #
    -# The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
    +# The law "Svensk författningssamling 1878, no 14" about standard time in 1879:
     # From the beginning of 1879 (that is 01-01 00:00) the time for all
     # places in the country is "the mean solar time for the meridian at
     # three degrees, or twelve minutes of time, to the west of the
    @@ -2594,7 +2947,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
     # national standard time as 01:00:14 ahead of GMT....
     #
     # About the beginning of CET in Sweden. The lawtext ("Svensk
    -# forfattningssamling 1899, no 44") states, that "from the beginning
    +# författningssamling 1899, no 44") states, that "from the beginning
     # of 1900... ... the same as the mean solar time for the meridian at
     # the distance of one hour of time from the meridian of the English
     # observatory at Greenwich, or at 12 minutes 14 seconds to the west
    @@ -2602,7 +2955,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
     # 1899-06-16.  In short: At 1900-01-01 00:00:00 the new standard time
     # in Sweden is 01:00:00 ahead of GMT.
     #
    -# 1916: The lawtext ("Svensk forfattningssamling 1916, no 124") states
    +# 1916: The lawtext ("Svensk författningssamling 1916, no 124") states
     # that "1916-05-15 is considered to begin one hour earlier". It is
     # pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00....
     # Further the law says, that "1916-09-30 is considered to end one hour later".
    @@ -2612,7 +2965,7 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
     # not available on the site (to my knowledge they are only available
     # in Swedish):  (type
     # "sommartid" without the quotes in the field "Fritext" and then click
    -# the Sok-button).
    +# the Sök-button).
     #
     # (2001-05-13):
     #
    @@ -2627,9 +2980,9 @@ Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
    -			1:00:14	-	SET	1900 Jan  1	# Swedish Time
    +			1:00:14	-	SET	1900 Jan  1 # Swedish Time
     			1:00	-	CET	1916 May 14 23:00
    -			1:00	1:00	CEST	1916 Oct  1 01:00
    +			1:00	1:00	CEST	1916 Oct  1  1:00
     			1:00	-	CET	1980
     			1:00	EU	CE%sT
     
    @@ -2637,7 +2990,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
     # From Howse:
     # By the end of the 18th century clocks and watches became commonplace
     # and their performance improved enormously.  Communities began to keep
    -# mean time in preference to apparent time -- Geneva from 1780 ....
    +# mean time in preference to apparent time - Geneva from 1780 ....
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     # From Whitman (who writes "Midnight?"):
     # Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
    @@ -2653,7 +3006,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
     # to be wrong. This is now verified.
     #
     # I have found copies of the original ruling by the Swiss Federal
    -# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
    +# government, in 'Eidgenössische Gesetzessammlung 1941 and 1942' (Swiss
     # federal law collection)...
     #
     # DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
    @@ -2672,7 +3025,7 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
     # night as an absolute novelty, because this was the first time that such
     # a thing had happened in Switzerland.
     #
    -# I have also checked 1916, because one book source (Gabriel, Traite de
    +# I have also checked 1916, because one book source (Gabriel, Traité de
     # l'heure dans le monde) claims that Switzerland had DST in 1916. This is
     # false, no official document could be found. Probably Gabriel got misled
     # by references to Germany, which introduced DST in 1916 for the first time.
    @@ -2686,19 +3039,19 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
     # One further detail for Switzerland, which is probably out of scope for
     # most users of tzdata: The [Europe/Zurich zone] ...
     # describes all of Switzerland correctly, with the exception of
    -# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
    +# the Canton de Genève (Geneva, Genf). Between 1848 and 1894 Geneva did not
     # follow Bern Mean Time but kept its own local mean time.
     # To represent this, an extra zone would be needed.
     #
     # From Alois Treindl (2013-09-11):
     # The Federal regulations say
     # http://www.admin.ch/opc/de/classified-compilation/20071096/index.html
    -# ... the meridian for Bern mean time ... is 7 degrees 26'22.50".
    +# ... the meridian for Bern mean time ... is 7 degrees 26' 22.50".
     # Expressed in time, it is 0h29m45.5s.
     
     # From Pierre-Yves Berger (2013-09-11):
    -# the "Circulaire du conseil federal" (December 11 1893)
    -#  ...
    +# the "Circulaire du conseil fédéral" (December 11 1893)
    +# http://www.amtsdruckschriften.bar.admin.ch/viewOrigDoc.do?id=10071353
     # clearly states that the [1894-06-01] change should be done at midnight
     # but if no one is present after 11 at night, could be postponed until one
     # hour before the beginning of service.
    @@ -2709,14 +3062,14 @@ Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
     # We can find no reliable source for Shanks's assertion that all of Switzerland
     # except Geneva switched to Bern Mean Time at 00:00 on 1848-09-12.  This book:
     #
    -#	Jakob Messerli. Gleichmassig, punktlich, schnell: Zeiteinteilung und
    +#	Jakob Messerli. Gleichmässig, pünktlich, schnell. Zeiteinteilung und
     #	Zeitgebrauch in der Schweiz im 19. Jahrhundert. Chronos, Zurich 1995,
     #	ISBN 3-905311-68-2, OCLC 717570797.
     #
     # suggests that the transition was more gradual, and that the Swiss did not
     # agree about civil time during the transition.  The timekeeping it gives the
     # most detail for is postal and telegraph time: here, federal legislation (the
    -# "Bundesgesetz uber die Erstellung von elektrischen Telegraphen") passed on
    +# "Bundesgesetz über die Erstellung von elektrischen Telegraphen") passed on
     # 1851-11-23, and an official implementation notice was published 1853-07-16
     # (Bundesblatt 1853, Bd. II, S. 859).  On p 72 Messerli writes that in
     # practice since July 1853 Bernese time was used in "all postal and telegraph
    @@ -2730,7 +3083,7 @@ Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
     Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
    -			0:29:46	-	BMT	1894 Jun # Bern Mean Time
    +			0:29:46	-	BMT	1894 Jun    # Bern Mean Time
     			1:00	Swiss	CE%sT	1981
     			1:00	EU	CE%sT
     
    @@ -2738,7 +3091,7 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
     
     # From Amar Devegowda (2007-01-03):
     # The time zone rules for Istanbul, Turkey have not been changed for years now.
    -# ... The latest rules are available at -
    +# ... The latest rules are available at:
     # http://www.timeanddate.com/worldclock/timezone.html?n=107
     # From Steffen Thorsen (2007-01-03):
     # I have been able to find press records back to 1996 which all say that
    @@ -2763,8 +3116,7 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
     # (on a non-government server though) describing dates between 2002 and 2006:
     # http://www.alomaliye.com/bkk_2002_3769.htm
     
    -# From Gökdeniz Karadağ (2011-03-10):
    -#
    +# From Gökdeniz Karadağ (2011-03-10):
     # According to the articles linked below, Turkey will change into summer
     # time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
     # This change is due to a nationwide exam on 27th.
    @@ -2777,9 +3129,16 @@ Zone	Europe/Zurich	0:34:08 -	LMT	1853 Jul 16 # See above comment.
     # Turkish Local election....
     # http://www.sabah.com.tr/Ekonomi/2014/02/12/yaz-saatinde-onemli-degisiklik
     # ... so Turkey will move clocks forward one hour on March 31 at 3:00 a.m.
    -# From Paul Eggert (2014-02-17):
    -# Here is an English-language source:
    -# http://www.worldbulletin.net/turkey/129016/turkey-switches-to-daylight-saving-time-march-31
    +# From Randal L. Schwartz (2014-04-15):
    +# Having landed on a flight from the states to Istanbul (via AMS) on March 31,
    +# I can tell you that NOBODY (even the airlines) respected this timezone DST
    +# change delay.  Maybe the word just didn't get out in time.
    +# From Paul Eggert (2014-06-15):
    +# The press reported massive confusion, as election officials obeyed the rule
    +# change but cell phones (and airline baggage systems) did not.  See:
    +# Kostidis M. Eventful elections in Turkey. Balkan News Agency
    +# http://www.balkaneu.com/eventful-elections-turkey/ 2014-03-30.
    +# I guess the best we can do is document the official time.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
    @@ -2846,10 +3205,10 @@ Zone	Europe/Istanbul	1:55:52 -	LMT	1880
     			2:00	Turkey	EE%sT	1978 Oct 15
     			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
     			2:00	Turkey	EE%sT	2007
    -			2:00	EU	EE%sT	2011 Mar 27 1:00u
    -			2:00	-	EET	2011 Mar 28 1:00u
    -			2:00	EU	EE%sT	2014 Mar 30 1:00u
    -			2:00	-	EET	2014 Mar 31 1:00u
    +			2:00	EU	EE%sT	2011 Mar 27  1:00u
    +			2:00	-	EET	2011 Mar 28  1:00u
    +			2:00	EU	EE%sT	2014 Mar 30  1:00u
    +			2:00	-	EET	2014 Mar 31  1:00u
     			2:00	EU	EE%sT
     Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
     
    @@ -2870,7 +3229,7 @@ Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
     # Bill number 8330 of MP from the Party of Regions Oleg Nadoshi got
     # approval from 266 deputies.
     #
    -# Ukraine abolishes transter back to the winter time (in Russian)
    +# Ukraine abolishes transfer back to the winter time (in Russian)
     # http://news.mail.ru/politics/6861560/
     #
     # The Ukrainians will no longer change the clock (in Russian)
    @@ -2931,12 +3290,12 @@ Zone Europe/Kiev	2:02:04 -	LMT	1880
     			2:00	-	EET	1930 Jun 21
     			3:00	-	MSK	1941 Sep 20
     			1:00	C-Eur	CE%sT	1943 Nov  6
    -			3:00	Russia	MSK/MSD	1990 Jul  1 2:00
    -			2:00	1:00	EEST	1991 Sep 29 3:00
    +			3:00	Russia	MSK/MSD	1990 Jul  1  2:00
    +			2:00	1:00	EEST	1991 Sep 29  3:00
     			2:00	E-Eur	EE%sT	1995
     			2:00	EU	EE%sT
     # Ruthenia used CET 1990/1991.
    -# "Uzhhorod" is the transliteration of the Ukrainian name, but
    +# "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but
     # "Uzhgorod" is more common in English.
     Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
     			1:00	-	CET	1940
    @@ -2944,8 +3303,8 @@ Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
     			1:00	1:00	CEST	1944 Oct 26
     			1:00	-	CET	1945 Jun 29
     			3:00	Russia	MSK/MSD	1990
    -			3:00	-	MSK	1990 Jul  1 2:00
    -			1:00	-	CET	1991 Mar 31 3:00
    +			3:00	-	MSK	1990 Jul  1  2:00
    +			1:00	-	CET	1991 Mar 31  3:00
     			2:00	-	EET	1992
     			2:00	E-Eur	EE%sT	1995
     			2:00	EU	EE%sT
    @@ -2959,42 +3318,9 @@ Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
     			2:00	-	EET	1930 Jun 21
     			3:00	-	MSK	1941 Aug 25
     			1:00	C-Eur	CE%sT	1943 Oct 25
    -			3:00	Russia	MSK/MSD	1991 Mar 31 2:00
    +			3:00	Russia	MSK/MSD	1991 Mar 31  2:00
     			2:00	E-Eur	EE%sT	1995
     			2:00	EU	EE%sT
    -# Central Crimea used Moscow time 1994/1997.
    -Zone Europe/Simferopol	2:16:24 -	LMT	1880
    -			2:16	-	SMT	1924 May  2 # Simferopol Mean T
    -			2:00	-	EET	1930 Jun 21
    -			3:00	-	MSK	1941 Nov
    -			1:00	C-Eur	CE%sT	1944 Apr 13
    -			3:00	Russia	MSK/MSD	1990
    -			3:00	-	MSK	1990 Jul  1 2:00
    -			2:00	-	EET	1992
    -# From Paul Eggert (2006-03-22):
    -# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
    -# from Kiev to Moscow time sometime after the January 1994 elections.
    -# Shanks (1999) says "date of change uncertain", but implies that it happened
    -# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
    -# 1994-09-25 03:00, but that can't be right.  For now, guess it
    -# changed in May.
    -			2:00	E-Eur	EE%sT	1994 May
    -# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
    -			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
    -			3:00	1:00	MSD	1996 Oct 27 3:00s
    -# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
    -# Assume it happened in March by not changing the clocks.
    -			3:00	Russia	MSK/MSD	1997
    -			3:00	-	MSK	1997 Mar lastSun 1:00u
    -# From Alexander Krivenyshev (2014-03-17):
    -# time change at 2:00 (2am) on March 30, 2014
    -# http://vz.ru/news/2014/3/17/677464.html
    -# From Paul Eggert (2014-03-30):
    -# Simferopol and Sevastopol reportedly changed their central town clocks
    -# late the previous day, but this appears to have been ceremonial
    -# and the discrepancies are small enough to not worry about.
    -			2:00	EU	EE%sT	2014 Mar 30 2:00
    -			4:00	-	MSK
     
     # Vatican City
     # See Europe/Rome.
    @@ -3018,7 +3344,7 @@ Zone Europe/Simferopol	2:16:24 -	LMT	1880
     # ...
     #
     # ...the European time rules are...standardized since 1981, when
    -# most European coun[tr]ies started DST.  Before that year, only
    +# most European countries started DST.  Before that year, only
     # a few countries (UK, France, Italy) had DST, each according
     # to own national rules.  In 1981, however, DST started on
     # 'Apr firstSun', and not on 'Mar lastSun' as in the following
    @@ -3026,7 +3352,7 @@ Zone Europe/Simferopol	2:16:24 -	LMT	1880
     # But also since 1981 there are some more national exceptions
     # than listed in 'europe': Switzerland, for example, joined DST
     # one year later, Denmark ended DST on 'Oct 1' instead of 'Sep
    -# lastSun' in 1981---I don't know how they handle now.
    +# lastSun' in 1981 - I don't know how they handle now.
     #
     # Finally, DST ist always from 'Apr 1' to 'Oct 1' in the
     # Soviet Union (as far as I know).
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/factory b/jdk/test/sun/util/calendar/zi/tzdata/factory
    index 813d99a1f1f..0a6041db07e 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/factory
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/factory
    @@ -21,7 +21,6 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
    index 28fb64b647e..63eadcbd0c5 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
    @@ -26,21 +26,21 @@
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     #
    -# From Paul Eggert (2013-05-27):
    +# From Paul Eggert (2014-07-18):
    +# This file contains a table of two-letter country codes.  Columns are
    +# separated by a single tab.  Lines beginning with '#' are comments.
    +# Although all text currently uses ASCII encoding, this is planned to
    +# change to UTF-8 soon.  The columns of the table are as follows:
     #
    -# This file contains a table with the following columns:
     # 1.  ISO 3166-1 alpha-2 country code, current as of
    -#     ISO 3166-1 Newsletter VI-15 (2013-05-10).  See: Updates on ISO 3166
    +#     ISO 3166-1 Newsletter VI-16 (2013-07-11).  See: Updates on ISO 3166
     #   http://www.iso.org/iso/home/standards/country_codes/updates_on_iso_3166.htm
     # 2.  The usual English name for the coded region,
     #     chosen so that alphabetic sorting of subsets produces helpful lists.
     #     This is not the same as the English name in the ISO 3166 tables.
     #
    -# Columns are separated by a single tab.
     # The table is sorted by country code.
     #
    -# Lines beginning with `#' are comments.
    -#
     # This table is intended as an aid for users, to help them select time
     # zone data appropriate for their practical needs.  It is not intended
     # to take or endorse any position on legal or territorial claims.
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/leapseconds b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
    index b423135b942..d38abd6a4bd 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
    @@ -21,7 +21,7 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# Allowance for leapseconds added to each timezone file.
    +# Allowance for leap seconds added to each time zone file.
     
     # This file is in the public domain.
     
    @@ -31,7 +31,7 @@
     # you should be able to pick up leap-seconds.list from a secondary NIST server.
     # For more about leap-seconds.list, please see
     # The NTP Timescale and Leap Seconds
    -# .
    +# http://www.eecis.udel.edu/~mills/leap.html
     
     # The International Earth Rotation Service periodically uses leap seconds
     # to keep UTC to within 0.9 s of UT1
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
    index dc0c2e92cff..0dc714aa92d 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
    @@ -21,15 +21,15 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
     # also includes Central America and the Caribbean
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
     # From Paul Eggert (1999-03-22):
     # A reliable and entertaining source about time zones is
    @@ -78,13 +78,13 @@
     #	to push people into bed earlier, and get them up earlier, to make
     #	them healthy, wealthy and wise in spite of themselves.
     #
    -#	-- Robertson Davies, The diary of Samuel Marchbanks,
    +#	 -- Robertson Davies, The diary of Samuel Marchbanks,
     #	   Clarke, Irwin (1947), XIX, Sunday
     #
     # For more about the first ten years of DST in the United States, see
    -# Robert Garland's 
    -# Ten years of daylight saving from the Pittsburgh standpoint
    -# (Carnegie Library of Pittsburgh, 1927).
    +# Robert Garland, Ten years of daylight saving from the Pittsburgh standpoint
    +# (Carnegie Library of Pittsburgh, 1927).
    +# http://www.clpgh.org/exhibit/dst.html
     #
     # Shanks says that DST was called "War Time" in the US in 1918 and 1919.
     # However, DST was imposed by the Standard Time Act of 1918, which
    @@ -103,11 +103,11 @@
     # From Arthur David Olson (2000-09-25):
     # Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
     # In the introduction, Oboler spoke of "Eastern Peace Time."
    -# An AltaVista search turned up
    -# :
    +# An AltaVista search turned up:
    +# http://rowayton.org/rhs/hstaug45.html
     # "When the time is announced over the radio now, it is 'Eastern Peace
     # Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
    -#  (August 1945) by way of confirmation.
    +# (August 1945) by way of confirmation.
     
     # From Joseph Gallant citing
     # George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
    @@ -205,7 +205,7 @@ Zone	PST8PDT		 -8:00	US	P%sT
     # USA  ALASKA STD    9 H  BEHIND UTC    MOST OF ALASKA     (AKST)
     # USA  ALASKA STD    8 H  BEHIND UTC    APR 3 - OCT 30 (AKDT)
     # USA  ALEUTIAN     10 H  BEHIND UTC    ISLANDS WEST OF 170W
    -# USA  - " -         9 H  BEHIND UTC    APR 3 - OCT 30
    +# USA    "           9 H  BEHIND UTC    APR 3 - OCT 30
     # USA  HAWAII       10 H  BEHIND UTC
     # USA  BERING       11 H  BEHIND UTC    SAMOA, MIDWAY
     
    @@ -258,19 +258,19 @@ Zone	PST8PDT		 -8:00	US	P%sT
     # The following was signed into law on 2005-08-08.
     #
     # H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
    -#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
    +#   (a) Amendment.--Section 3(a) of the Uniform Time Act of 1966 (15
     #   U.S.C. 260a(a)) is amended--
    -#     (1) by striking 'first Sunday of April' and inserting 'second
    -#     Sunday of March'; and
    -#     (2) by striking 'last Sunday of October' and inserting 'first
    +#     (1) by striking "first Sunday of April" and inserting "second
    +#     Sunday of March"; and
    +#     (2) by striking "last Sunday of October" and inserting "first
     #     Sunday of November'.
    -#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
    +#   (b) Effective Date.--Subsection (a) shall take effect 1 year after the
     #   date of enactment of this Act or March 1, 2007, whichever is later.
    -#   (c) Report to Congress- Not later than 9 months after the effective
    +#   (c) Report to Congress.--Not later than 9 months after the effective
     #   date stated in subsection (b), the Secretary shall report to Congress
     #   on the impact of this section on energy consumption in the United
     #   States.
    -#   (d) Right to Revert- Congress retains the right to revert the
    +#   (d) Right to Revert.--Congress retains the right to revert the
     #   Daylight Saving Time back to the 2005 time schedules once the
     #   Department study is complete.
     
    @@ -292,7 +292,7 @@ Zone	PST8PDT		 -8:00	US	P%sT
     
     # From Paul Eggert (2005-08-26):
     # According to today's Huntsville Times
    -# 
    +# http://www.al.com/news/huntsvilletimes/index.ssf?/base/news/1125047783228320.xml&coll=1
     # a few towns on Alabama's "eastern border with Georgia, such as Phenix City
     # in Russell County, Lanett in Chambers County and some towns in Lee County,
     # set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
    @@ -347,15 +347,15 @@ Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
     			-6:00	US	C%sT	1920
    -			-6:00	Chicago	C%sT	1936 Mar  1 2:00
    -			-5:00	-	EST	1936 Nov 15 2:00
    +			-6:00	Chicago	C%sT	1936 Mar  1  2:00
    +			-5:00	-	EST	1936 Nov 15  2:00
     			-6:00	Chicago	C%sT	1942
     			-6:00	US	C%sT	1946
     			-6:00	Chicago	C%sT	1967
     			-6:00	US	C%sT
     # Oliver County, ND switched from mountain to central time on 1992-10-25.
     Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
    -			-7:00	US	M%sT	1992 Oct 25 02:00
    +			-7:00	US	M%sT	1992 Oct 25  2:00
     			-6:00	US	C%sT
     # Morton County, ND, switched from mountain to central time on
     # 2003-10-26, except for the area around Mandan which was already central time.
    @@ -364,29 +364,26 @@ Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
     # Jones, Mellette, and Todd Counties in South Dakota;
     # but in practice these other counties were already observing central time.
     # See .
    -Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
    -			-7:00	US	M%sT	2003 Oct 26 02:00
    +Zone America/North_Dakota/New_Salem -6:45:39 - LMT	1883 Nov 18 12:14:21
    +			-7:00	US	M%sT	2003 Oct 26  2:00
     			-6:00	US	C%sT
     
     # From Josh Findley (2011-01-21):
     # ...it appears that Mercer County, North Dakota, changed from the
     # mountain time zone to the central time zone at the last transition from
     # daylight-saving to standard time (on Nov. 7, 2010):
    -# 
     # http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm
    -# 
    -# 
     # http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html
    -# 
     
     # From Andy Lipscomb (2011-01-24):
     # ...according to the Census Bureau, the largest city is Beulah (although
     # it's commonly referred to as Beulah-Hazen, with Hazen being the next
     # largest city in Mercer County).  Google Maps places Beulah's city hall
    -# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07".
    +# at 47 degrees 15' 51" N, 101 degrees 46' 40" W, which yields an offset
    +# of 6h47'07".
     
    -Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53
    -			-7:00	US	M%sT	2010 Nov  7 2:00
    +Zone America/North_Dakota/Beulah -6:47:07 - LMT	1883 Nov 18 12:12:53
    +			-7:00	US	M%sT	2010 Nov  7  2:00
     			-6:00	US	C%sT
     
     # US mountain time, represented by Denver
    @@ -448,15 +445,18 @@ Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
     # was destroyed in 1805 by a Yakutat-kon war party.)  However, there
     # were nearby inhabitants in some cases and for our purposes perhaps
     # it's best to simply use the official transition.
    -#
     
    -# From Steve Ferguson (2011-01-31):
    -# The author lives in Alaska and many of the references listed are only
    -# available to Alaskan residents.
    +# From Paul Eggert (2014-07-18):
    +# One opinion of the early-1980s turmoil in Alaska over time zones and
    +# daylight saving time appeared as graffiti on a Juneau airport wall:
    +# "Welcome to Juneau.  Please turn your watch back to the 19th century."
    +# See: Turner W. Alaska's four time zones now two. NY Times 1983-11-01.
    +# http://www.nytimes.com/1983/11/01/us/alaska-s-four-time-zones-now-two.html
     #
    -# 
    -# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
    -# 
    +# Steve Ferguson (2011-01-31) referred to the following source:
    +# Norris F. Keeping time in Alaska: national directives, local response.
    +# Alaska History 2001;16(1-2).
    +# http://alaskahistoricalsociety.org/discover-alaska/glimpses-of-the-past/keeping-time-in-alaska/
     
     # From Arthur David Olson (2011-02-01):
     # Here's database-relevant material from the 2001 "Alaska History" article:
    @@ -482,12 +482,10 @@ Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
     # From Arthur David Olson (2011-02-09):
     # I just spoke by phone with a staff member at the Metlakatla Indian
     # Community office (using contact information available at
    -# 
     # http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
    -# ).
     # It's shortly after 1:00 here on the east coast of the United States;
     # the staffer said it was shortly after 10:00 there. When I asked whether
    -# that meant they were on Pacific time, they said no--they were on their
    +# that meant they were on Pacific time, they said no - they were on their
     # own time. I asked about daylight saving; they said it wasn't used. I
     # did not inquire about practices in the past.
     
    @@ -501,9 +499,9 @@ Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
     			 -8:00	-	PST	1942
     			 -8:00	US	P%sT	1946
     			 -8:00	-	PST	1969
    -			 -8:00	US	P%sT	1980 Apr 27 2:00
    -			 -9:00	US	Y%sT	1980 Oct 26 2:00
    -			 -8:00	US	P%sT	1983 Oct 30 2:00
    +			 -8:00	US	P%sT	1980 Apr 27  2:00
    +			 -9:00	US	Y%sT	1980 Oct 26  2:00
    +			 -8:00	US	P%sT	1983 Oct 30  2:00
     			 -9:00	US	Y%sT	1983 Nov 30
     			 -9:00	US	AK%sT
     Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
    @@ -511,7 +509,7 @@ Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
     			 -8:00	-	PST	1942
     			 -8:00	US	P%sT	1946
     			 -8:00	-	PST	1969
    -			 -8:00	US	P%sT	1983 Oct 30 2:00
    +			 -8:00	US	P%sT	1983 Oct 30  2:00
     			 -9:00	US	Y%sT	1983 Nov 30
     			 -9:00	US	AK%sT
     Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
    @@ -519,8 +517,8 @@ Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
     			 -8:00	-	PST	1942
     			 -8:00	US	P%sT	1946
     			 -8:00	-	PST	1969
    -			 -8:00	US	P%sT	1983 Oct 30 2:00
    -			 -8:00	-	MeST
    +			 -8:00	US	P%sT	1983 Oct 30  2:00
    +			 -8:00	-	PST
     Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
     			 -9:18:55 -	LMT	1900 Aug 20 12:00
     			 -9:00	-	YST	1942
    @@ -535,7 +533,7 @@ Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
     			-10:00	US	CAT/CAPT 1946 # Peace
     			-10:00	-	CAT	1967 Apr
     			-10:00	-	AHST	1969
    -			-10:00	US	AH%sT	1983 Oct 30 2:00
    +			-10:00	US	AH%sT	1983 Oct 30  2:00
     			 -9:00	US	Y%sT	1983 Nov 30
     			 -9:00	US	AK%sT
     Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
    @@ -544,7 +542,7 @@ Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
     			-11:00	US	N%sT	1946
     			-11:00	-	NST	1967 Apr
     			-11:00	-	BST	1969
    -			-11:00	US	B%sT	1983 Oct 30 2:00
    +			-11:00	US	B%sT	1983 Oct 30  2:00
     			 -9:00	US	Y%sT	1983 Nov 30
     			 -9:00	US	AK%sT
     Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
    @@ -553,7 +551,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
     			-11:00	US	N%sT	1946
     			-11:00	-	NST	1967 Apr
     			-11:00	-	BST	1969
    -			-11:00	US	B%sT	1983 Oct 30 2:00
    +			-11:00	US	B%sT	1983 Oct 30  2:00
     			-10:00	US	AH%sT	1983 Nov 30
     			-10:00	US	HA%sT
     # The following switches don't quite make our 1970 cutoff.
    @@ -571,7 +569,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
     #  Minutes of the Unalaska City Council Meeting, January 10, 1967:
     #  "Except for St. Paul and Akutan, Unalaska is the only important
     #  location not on Alaska Standard Time.  The following resolution was
    -#  made by William Robinson and seconded by Henry Swanson:  Be it
    +#  made by William Robinson and seconded by Henry Swanson: Be it
     #  resolved that the City of Unalaska hereby goes to Alaska Standard
     #  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
     #  January 14, Alaska Standard Time.)  This resolution was passed with
    @@ -583,9 +581,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
     # "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
     # of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09,
     # the article is available at
    -# 
     # http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf
    -# 
     # and indicates that standard time was adopted effective noon, January
     # 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
     # saving for the period between the last Sunday of each April and the
    @@ -606,7 +602,7 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
     # year, the standard time of this Territory shall be advanced one
     # hour...This Act shall take effect upon its approval. Approved this 26th
     # day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of
    -# Hawaii." Page 172:  "Act 163...Act 90 of the Session Laws of 1933 is
    +# Hawaii." Page 172: "Act 163...Act 90 of the Session Laws of 1933 is
     # hereby repealed...This Act shall take effect upon its approval, upon
     # which date the standard time of this Territory shall be restored to
     # that existing immediately prior to the taking effect of said Act 90.
    @@ -616,14 +612,14 @@ Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
     # Note that 1933-05-21 was a Sunday.
     # We're left to guess the time of day when Act 163 was approved; guess noon.
     
    -Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
    -			-10:30	-	HST	1933 Apr 30 2:00 #Laws 1933
    -			-10:30	1:00	HDT	1933 May 21 12:00 #Laws 1933+12
    -			-10:30	-	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
    -			-10:30	1:00	HDT	1945 Sep 30 2:00 #Schmitt&Cox+2
    -			-10:30	-	HST	1947 Jun  8 2:00 #Schmitt&Cox+2
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00
    +			-10:30	-	HST	1933 Apr 30  2:00
    +			-10:30	1:00	HDT	1933 May 21 12:00
    +			-10:30	-	HST	1942 Feb  9  2:00
    +			-10:30	1:00	HDT	1945 Sep 30  2:00
    +			-10:30	-	HST	1947 Jun  8  2:00
     			-10:00	-	HST
    -
     Link Pacific/Honolulu Pacific/Johnston
     
     # Now we turn to US areas that have diverged from the consensus since 1970.
    @@ -633,9 +629,9 @@ Link Pacific/Honolulu Pacific/Johnston
     # From Paul Eggert (2002-10-20):
     #
     # The information in the rest of this paragraph is derived from the
    -# 
    -# Daylight Saving Time web page (2002-01-23) maintained by the
    -# Arizona State Library, Archives and Public Records.
    +# Daylight Saving Time web page
    +#  (2002-01-23)
    +# maintained by the Arizona State Library, Archives and Public Records.
     # Between 1944-01-01 and 1944-04-01 the State of Arizona used standard
     # time, but by federal law railroads, airlines, bus lines, military
     # personnel, and some engaged in interstate commerce continued to
    @@ -649,10 +645,11 @@ Link Pacific/Honolulu Pacific/Johnston
     # Shanks says the 1944 experiment came to an end on 1944-03-17.
     # Go with the Arizona State Library instead.
     
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
    -			-7:00	US	M%sT	1944 Jan  1 00:01
    -			-7:00	-	MST	1944 Apr  1 00:01
    -			-7:00	US	M%sT	1944 Oct  1 00:01
    +			-7:00	US	M%sT	1944 Jan  1  0:01
    +			-7:00	-	MST	1944 Apr  1  0:01
    +			-7:00	US	M%sT	1944 Oct  1  0:01
     			-7:00	-	MST	1967
     			-7:00	US	M%sT	1968 Mar 21
     			-7:00	-	MST
    @@ -676,24 +673,22 @@ Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
     #
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
    -			-8:00	US	P%sT	1923 May 13 2:00
    +			-8:00	US	P%sT	1923 May 13  2:00
     			-7:00	US	M%sT	1974
    -			-7:00	-	MST	1974 Feb  3 2:00
    +			-7:00	-	MST	1974 Feb  3  2:00
     			-7:00	US	M%sT
     
     # Indiana
     #
     # For a map of Indiana's time zone regions, see:
    -# 
    -# What time is it in Indiana?
    -#  (2006-03-01)
    +# http://en.wikipedia.org/wiki/Time_in_Indiana
     #
     # From Paul Eggert (2007-08-17):
     # Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
     # with the following exceptions:
     #
     # - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
    -#   Vandenburgh, and Warrick counties have been like America/Chicago.
    +#   Vanderburgh, and Warrick counties have been like America/Chicago.
     #
     # - Dearborn and Ohio counties have been like America/New_York.
     #
    @@ -712,22 +707,16 @@ Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
     # that they would be ambiguous if we left them at the 'America' level.
     # So we reluctantly put them all in a subdirectory 'America/Indiana'.
     
    -# From Paul Eggert (2005-08-16):
    -# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
    -
    -# From Nathan Stratton Treadway (2006-03-30):
    -# http://www.dot.gov/affairs/dot0406.htm [3705 B]
    -# From Deborah Goldsmith (2006-01-18):
    -# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
    -# From Paul Eggert (2006-01-20):
    -# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
    +# From Paul Eggert (2014-06-26):
    +# https://www.federalregister.gov/articles/2006/01/20/06-563/standard-time-zone-boundary-in-the-state-of-indiana
    +# says "DOT is relocating the time zone boundary in Indiana to move Starke,
     # Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
     # Eastern Time Zone to the Central Time Zone.... The effective date of
    -# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
    +# this rule is 2 a.m. EST Sunday, April 2, 2006, which is the
     # changeover date from standard time to Daylight Saving Time."
    -# Strictly speaking, this means the affected counties will change their
    -# clocks twice that night, but this obviously is in error.  The intent
    -# is that 01:59:59 EST be followed by 02:00:00 CDT.
    +# Strictly speaking, this meant the affected counties changed their
    +# clocks twice that night, but this obviously was in error.  The intent
    +# was that 01:59:59 EST be followed by 02:00:00 CDT.
     
     # From Gwillim Law (2007-02-10):
     # The Associated Press has been reporting that Pulaski County, Indiana is
    @@ -739,13 +728,13 @@ Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
     Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
     Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
    +Zone America/Indiana/Indianapolis -5:44:38 - LMT	1883 Nov 18 12:15:22
     			-6:00	US	C%sT	1920
     			-6:00 Indianapolis C%sT	1942
     			-6:00	US	C%sT	1946
    -			-6:00 Indianapolis C%sT	1955 Apr 24 2:00
    -			-5:00	-	EST	1957 Sep 29 2:00
    -			-6:00	-	CST	1958 Apr 27 2:00
    +			-6:00 Indianapolis C%sT	1955 Apr 24  2:00
    +			-5:00	-	EST	1957 Sep 29  2:00
    +			-6:00	-	CST	1958 Apr 27  2:00
     			-5:00	-	EST	1969
     			-5:00	US	E%sT	1971
     			-5:00	-	EST	2006
    @@ -761,10 +750,10 @@ Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
     			-6:00	US	C%sT	1951
    -			-6:00	Marengo	C%sT	1961 Apr 30 2:00
    +			-6:00	Marengo	C%sT	1961 Apr 30  2:00
     			-5:00	-	EST	1969
    -			-5:00	US	E%sT	1974 Jan  6 2:00
    -			-6:00	1:00	CDT	1974 Oct 27 2:00
    +			-5:00	US	E%sT	1974 Jan  6  2:00
    +			-6:00	1:00	CDT	1974 Oct 27  2:00
     			-5:00	US	E%sT	1976
     			-5:00	-	EST	2006
     			-5:00	US	E%sT
    @@ -785,11 +774,11 @@ Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
     			-6:00	US	C%sT	1946
    -			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
    +			-6:00 Vincennes	C%sT	1964 Apr 26  2:00
     			-5:00	-	EST	1969
     			-5:00	US	E%sT	1971
    -			-5:00	-	EST	2006 Apr  2 2:00
    -			-6:00	US	C%sT	2007 Nov  4 2:00
    +			-5:00	-	EST	2006 Apr  2  2:00
    +			-6:00	US	C%sT	2007 Nov  4  2:00
     			-5:00	US	E%sT
     #
     # Perry County, Indiana, switched from eastern to central time in April 2006.
    @@ -806,10 +795,10 @@ Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
     			-6:00	US	C%sT	1946
    -			-6:00 Perry	C%sT	1964 Apr 26 2:00
    +			-6:00 Perry	C%sT	1964 Apr 26  2:00
     			-5:00	-	EST	1969
     			-5:00	US	E%sT	1971
    -			-5:00	-	EST	2006 Apr  2 2:00
    +			-5:00	-	EST	2006 Apr  2  2:00
     			-6:00	US	C%sT
     #
     # Pike County, Indiana moved from central to eastern time in 1977,
    @@ -822,11 +811,11 @@ Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
     			-6:00	US	C%sT	1955
    -			-6:00	Pike	C%sT	1965 Apr 25 2:00
    -			-5:00	-	EST	1966 Oct 30 2:00
    -			-6:00	US	C%sT	1977 Oct 30 2:00
    -			-5:00	-	EST	2006 Apr  2 2:00
    -			-6:00	US	C%sT	2007 Nov  4 2:00
    +			-6:00	Pike	C%sT	1965 Apr 25  2:00
    +			-5:00	-	EST	1966 Oct 30  2:00
    +			-6:00	US	C%sT	1977 Oct 30  2:00
    +			-5:00	-	EST	2006 Apr  2  2:00
    +			-6:00	US	C%sT	2007 Nov  4  2:00
     			-5:00	US	E%sT
     #
     # Starke County, Indiana moved from central to eastern time in 1991,
    @@ -844,10 +833,10 @@ Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
     			-6:00	US	C%sT	1947
    -			-6:00	Starke	C%sT	1962 Apr 29 2:00
    -			-5:00	-	EST	1963 Oct 27 2:00
    -			-6:00	US	C%sT	1991 Oct 27 2:00
    -			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	Starke	C%sT	1962 Apr 29  2:00
    +			-5:00	-	EST	1963 Oct 27  2:00
    +			-6:00	US	C%sT	1991 Oct 27  2:00
    +			-5:00	-	EST	2006 Apr  2  2:00
     			-6:00	US	C%sT
     #
     # Pulaski County, Indiana, switched from eastern to central time in
    @@ -860,17 +849,17 @@ Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
     			-6:00	US	C%sT	1946
    -			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
    +			-6:00	Pulaski	C%sT	1961 Apr 30  2:00
     			-5:00	-	EST	1969
     			-5:00	US	E%sT	1971
    -			-5:00	-	EST	2006 Apr  2 2:00
    -			-6:00	US	C%sT	2007 Mar 11 2:00
    +			-5:00	-	EST	2006 Apr  2  2:00
    +			-6:00	US	C%sT	2007 Mar 11  2:00
     			-5:00	US	E%sT
     #
     # Switzerland County, Indiana, did not observe DST from 1973 through 2005.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
    -			-6:00	US	C%sT	1954 Apr 25 2:00
    +			-6:00	US	C%sT	1954 Apr 25  2:00
     			-5:00	-	EST	1969
     			-5:00	US	E%sT	1973
     			-5:00	-	EST	2006
    @@ -891,18 +880,17 @@ Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
     			-6:00	US	C%sT	1921
     			-6:00 Louisville C%sT	1942
     			-6:00	US	C%sT	1946
    -			-6:00 Louisville C%sT	1961 Jul 23 2:00
    +			-6:00 Louisville C%sT	1961 Jul 23  2:00
     			-5:00	-	EST	1968
    -			-5:00	US	E%sT	1974 Jan  6 2:00
    -			-6:00	1:00	CDT	1974 Oct 27 2:00
    +			-5:00	US	E%sT	1974 Jan  6  2:00
    +			-6:00	1:00	CDT	1974 Oct 27  2:00
     			-5:00	US	E%sT
     #
     # Wayne County, Kentucky
     #
    -# From
    -# 
    -# Lake Cumberland LIFE
    -#  (1999-01-29) via WKYM-101.7:
    +# From Lake Cumberland LIFE
    +# http://www.lake-cumberland.com/life/archive/news990129time.shtml
    +# (1999-01-29) via WKYM-101.7:
     # Clinton County has joined Wayne County in asking the DoT to change from
     # the Central to the Eastern time zone....  The Wayne County government made
     # the same request in December.  And while Russell County officials have not
    @@ -919,9 +907,8 @@ Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
     #
     # From Paul Eggert (2001-07-16):
     # The final rule was published in the
    -# 
    -# Federal Register 65, 160 (2000-08-17), page 50154-50158.
    -# 
    +# Federal Register 65, 160 (2000-08-17), pp 50154-50158.
    +# http://frwebgate.access.gpo.gov/cgi-bin/getdoc.cgi?dbname=2000_register&docid=fr17au00-22
     #
     Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
     			-6:00	US	C%sT	1946
    @@ -946,9 +933,8 @@ Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
     # See America/North_Dakota/Center for the Oliver County, ND change.
     # West Wendover, NV officially switched from Pacific to mountain time on
     # 1999-10-31.  See the
    -# 
    -# Federal Register 64, 203 (1999-10-21), page 56705-56707.
    -# 
    +# Federal Register 64, 203 (1999-10-21), pp 56705-56707.
    +# http://frwebgate.access.gpo.gov/cgi-bin/getdoc.cgi?dbname=1999_register&docid=fr21oc99-15
     # However, the Federal Register says that West Wendover already operated
     # on mountain time, and the rule merely made this official;
     # hence a separate tz entry is not needed.
    @@ -986,12 +972,12 @@ Rule	Detroit	1967	only	-	Jun	14	2:00	1:00	D
     Rule	Detroit	1967	only	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Detroit	-5:32:11 -	LMT	1905
    -			-6:00	-	CST	1915 May 15 2:00
    +			-6:00	-	CST	1915 May 15  2:00
     			-5:00	-	EST	1942
     			-5:00	US	E%sT	1946
     			-5:00	Detroit	E%sT	1973
     			-5:00	US	E%sT	1975
    -			-5:00	-	EST	1975 Apr 27 2:00
    +			-5:00	-	EST	1975 Apr 27  2:00
     			-5:00	US	E%sT
     #
     # Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
    @@ -1004,8 +990,8 @@ Rule Menominee	1966	only	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     			-6:00	US	C%sT	1946
    -			-6:00 Menominee	C%sT	1969 Apr 27 2:00
    -			-5:00	-	EST	1973 Apr 29 2:00
    +			-6:00 Menominee	C%sT	1969 Apr 27  2:00
    +			-5:00	-	EST	1973 Apr 29  2:00
     			-6:00	US	C%sT
     
     # Navassa
    @@ -1042,9 +1028,9 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     #	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
     #	which I found in the UCLA library.
     #
    -#	
     #	William Willett, The Waste of Daylight, 19th edition
    -#	 (1914-03)
    +#	
    +#	[PDF] (1914-03)
     #
     #	Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
     #	.
    @@ -1053,11 +1039,11 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     
     # Canada
     
    -# From Alain LaBont (1994-11-14):
    +# From Alain LaBonté (1994-11-14):
     # I post here the time zone abbreviations standardized in Canada
     # for both English and French in the CAN/CSA-Z234.4-89 standard....
     #
    -#	UTC	Standard time	Daylight savings time
    +#	UTC	Standard time	Daylight saving time
     #	offset	French	English	French	English
     #	-2:30	-	-	HAT	NDT
     #	-3	-	-	HAA	ADT
    @@ -1070,7 +1056,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     #	-9	HNY	YST	-	-
     #
     #	HN: Heure Normale	ST: Standard Time
    -#	HA: Heure Avance	DT: Daylight saving Time
    +#	HA: Heure Avancée	DT: Daylight saving Time
     #
     #	A: de l'Atlantique	Atlantic
     #	C: du Centre		Central
    @@ -1085,7 +1071,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     # From Paul Eggert (1994-11-22):
     # Alas, this sort of thing must be handled by localization software.
     
    -# Unless otherwise specified, the data for Canada are all from Shanks
    +# Unless otherwise specified, the data entries for Canada are all from Shanks
     # & Pottenger.
     
     # From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
    @@ -1134,15 +1120,15 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     
     # From Paul Eggert (2006-04-25):
     # H. David Matthews and Mary Vincent's map
    -# 
     # "It's about TIME", _Canadian Geographic_ (September-October 1998)
    -#  contains detailed boundaries for regions observing nonstandard
    +# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
    +# contains detailed boundaries for regions observing nonstandard
     # time and daylight saving time arrangements in Canada circa 1998.
     #
    -# INMS, the Institute for National Measurement Standards in Ottawa, has 
    +# INMS, the Institute for National Measurement Standards in Ottawa, has
     # information about standard and daylight saving time zones in Canada.
    -#  (updated periodically).
    +# http://inms-ienm.nrc-cnrc.gc.ca/en/time_services/daylight_saving_e.php
    +# (updated periodically).
     # Its unofficial information is often taken from Matthews and Vincent.
     
     # From Paul Eggert (2006-06-27):
    @@ -1151,9 +1137,7 @@ Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
     
     # From Chris Walton (2011-12-01)
     # In the first of Tammy Hardwick's articles
    -# 
     # http://www.ilovecreston.com/?p=articles&t=spec&ar=260
    -# 
     # she quotes the Friday November 1/1918 edition of the Creston Review.
     # The quote includes these two statements:
     # 'Sunday the CPR went back to the old system of time...'
    @@ -1221,9 +1205,7 @@ Rule	StJohns	1960	1986	-	Oct	lastSun	2:00	0	S
     # Time to Standard Time and from Standard Time to Daylight Savings Time
     # now occurs at 2:00AM.
     # ...
    -# 
     # http://www.assembly.nl.ca/legislation/sr/annualstatutes/2011/1106.chp.htm
    -# 
     # ...
     # MICHAEL PELLEY  |  Manager of Enterprise Architecture - Solution Delivery
     # Office of the Chief Information Officer
    @@ -1259,7 +1241,7 @@ Zone America/Goose_Bay	-4:01:40 -	LMT	1884 # Happy Valley-Goose Bay
     			-3:30	-	NST	1936
     			-3:30	StJohns	N%sT	1942 May 11
     			-3:30	Canada	N%sT	1946
    -			-3:30	StJohns	N%sT	1966 Mar 15 2:00
    +			-3:30	StJohns	N%sT	1966 Mar 15  2:00
     			-4:00	StJohns	A%sT	2011 Nov
     			-4:00	Canada	A%sT
     
    @@ -1320,7 +1302,7 @@ Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
     Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
     			-4:00	Halifax	A%sT	1918
     			-4:00	Canada	A%sT	1919
    -			-4:00	Halifax	A%sT	1942 Feb  9 2:00s
    +			-4:00	Halifax	A%sT	1942 Feb  9  2:00s
     			-4:00	Canada	A%sT	1946
     			-4:00	Halifax	A%sT	1974
     			-4:00	Canada	A%sT
    @@ -1379,7 +1361,7 @@ Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
     # meridian is supposed to observe AST, but residents as far east as
     # Natashquan use EST/EDT, and residents east of Natashquan use AST.
     # The Quebec department of justice writes in
    -# "The situation in Minganie and Basse-Cote-Nord"
    +# "The situation in Minganie and Basse-Côte-Nord"
     # http://www.justice.gouv.qc.ca/english/publications/generale/temps-minganie-a.htm
     # that the coastal strip from just east of Natashquan to Blanc-Sablon
     # observes Atlantic standard time all year round.
    @@ -1387,7 +1369,6 @@ Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
     # says this common practice was codified into law as of 2007.
     # For lack of better info, guess this practice began around 1970, contra to
     # Shanks & Pottenger who have this region observing AST/ADT.
    -# for post-1970 data America/Puerto_Rico.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
    @@ -1401,18 +1382,10 @@ Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
     Rule	Mont	1924	only	-	May	17	2:00	1:00	D
     Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
     Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
    -# The 1927-to-1937 rules can be expressed more simply as
    -# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
    -# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
    -# The rules below avoid use of 24:00
    -# (which pre-1998 versions of zic cannot handle).
    -Rule	Mont	1927	only	-	May	1	0:00	1:00	D
    -Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
    -Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
    -Rule	Mont	1932	only	-	May	1	0:00	1:00	D
    -Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
    -Rule	Mont	1933	only	-	Oct	1	0:00	0	S
    -Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
    +Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
    +Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
    +Rule	Mont	1938	1940	-	Apr	lastSun	0:00	1:00	D
    +Rule	Mont	1938	1939	-	Sep	lastSun	0:00	0	S
     Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
     Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
     Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
    @@ -1426,7 +1399,7 @@ Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
     Zone America/Montreal	-4:54:16 -	LMT	1884
     			-5:00	Mont	E%sT	1918
     			-5:00	Canada	E%sT	1919
    -			-5:00	Mont	E%sT	1942 Feb  9 2:00s
    +			-5:00	Mont	E%sT	1942 Feb  9  2:00s
     			-5:00	Canada	E%sT	1946
     			-5:00	Mont	E%sT	1974
     			-5:00	Canada	E%sT
    @@ -1448,7 +1421,7 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
     # have already done so.  In Orillia DST was to run until Saturday,
     # 1912-08-31 (no time mentioned), but it was met with considerable
     # hostility from certain segments of the public, and was revoked after
    -# only two weeks -- I copied it as Saturday, 1912-07-07, 22:00, but
    +# only two weeks - I copied it as Saturday, 1912-07-07, 22:00, but
     # presumably that should be -07-06.  (1912-06-19, -07-12; also letters
     # earlier in June).
     #
    @@ -1458,10 +1431,8 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
     # Mark Brader writes that an article in the 1997-10-14 Toronto Star
     # says that Atikokan, Ontario currently does not observe DST,
     # but will vote on 11-10 whether to use EST/EDT.
    -# He also writes that the
    -# 
    -# Ontario Time Act (1990, Chapter T.9)
    -# 
    +# He also writes that the Ontario Time Act (1990, Chapter T.9)
    +# http://www.gov.on.ca/MBS/english/publications/statregs/conttext.html
     # says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
     # Officially Atikokan is therefore on CST/CDT, and most likely this report
     # concerns a non-official time observed as a matter of local practice.
    @@ -1540,9 +1511,7 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
     # The Journal of The Royal Astronomical Society of Canada,
     # volume 26, number 2 (February 1932) and, as of 2010-07-17,
     # was available at
    -# 
     # http://adsabs.harvard.edu/full/1932JRASC..26...49S
    -# 
     #
     # It includes the text below (starting on page 57):
     #
    @@ -1553,26 +1522,26 @@ Zone America/Montreal	-4:54:16 -	LMT	1884
     # ing in 1930. The information for the province of Quebec is definite,
     # for the other provinces only approximate:
     #
    -# 	Province	Daylight saving time used
    +#	Province	Daylight saving time used
     # Prince Edward Island	Not used.
     # Nova Scotia		In Halifax only.
     # New Brunswick		In St. John only.
     # Quebec		In the following places:
    -# 			Montreal	Lachine
    -# 			Quebec		Mont-Royal
    -# 			Levis		Iberville
    -# 			St. Lambert	Cap de la Madeleine
    -# 			Verdun		Loretteville
    -# 			Westmount	Richmond
    -# 			Outremont	St. Jerome
    -# 			Longueuil	Greenfield Park
    -# 			Arvida		Waterloo
    -# 			Chambly-Canton	Beaulieu
    -# 			Melbourne	La Tuque
    -# 			St. Theophile	Buckingham
    +#			Montreal	Lachine
    +#			Quebec		Mont-Royal
    +#			Lévis		Iberville
    +#			St. Lambert	Cap de la Madelèine
    +#			Verdun		Loretteville
    +#			Westmount	Richmond
    +#			Outremont	St. Jérôme
    +#			Longueuil	Greenfield Park
    +#			Arvida		Waterloo
    +#			Chambly-Canton	Beaulieu
    +#			Melbourne	La Tuque
    +#			St. Théophile	Buckingham
     # Ontario		Used generally in the cities and towns along
    -# 			the southerly part of the province. Not
    -# 			used in the northwesterlhy part.
    +#			the southerly part of the province. Not
    +#			used in the northwesterly part.
     # Manitoba		Not used.
     # Saskatchewan		In Regina only.
     # Alberta		Not used.
    @@ -1641,7 +1610,7 @@ Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Toronto	-5:17:32 -	LMT	1895
     			-5:00	Canada	E%sT	1919
    -			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
    +			-5:00	Toronto	E%sT	1942 Feb  9  2:00s
     			-5:00	Canada	E%sT	1946
     			-5:00	Toronto	E%sT	1974
     			-5:00	Canada	E%sT
    @@ -1654,16 +1623,16 @@ Zone America/Thunder_Bay -5:57:00 -	LMT	1895
     			-5:00	Canada	E%sT
     Zone America/Nipigon	-5:53:04 -	LMT	1895
     			-5:00	Canada	E%sT	1940 Sep 29
    -			-5:00	1:00	EDT	1942 Feb  9 2:00s
    +			-5:00	1:00	EDT	1942 Feb  9  2:00s
     			-5:00	Canada	E%sT
     Zone America/Rainy_River -6:18:16 -	LMT	1895
     			-6:00	Canada	C%sT	1940 Sep 29
    -			-6:00	1:00	CDT	1942 Feb  9 2:00s
    +			-6:00	1:00	CDT	1942 Feb  9  2:00s
     			-6:00	Canada	C%sT
     Zone America/Atikokan	-6:06:28 -	LMT	1895
     			-6:00	Canada	C%sT	1940 Sep 29
    -			-6:00	1:00	CDT	1942 Feb  9 2:00s
    -			-6:00	Canada	C%sT	1945 Sep 30 2:00
    +			-6:00	1:00	CDT	1942 Feb  9  2:00s
    +			-6:00	Canada	C%sT	1945 Sep 30  2:00
     			-5:00	-	EST
     
     
    @@ -1676,7 +1645,7 @@ Zone America/Atikokan	-6:06:28 -	LMT	1895
     # the first Sunday of April of each year and two o'clock Central
     # Standard Time in the morning of the last Sunday of October next
     # following, one hour in advance of Central Standard Time."...
    -# I believe that the English legislation [of the old time act] had =
    +# I believe that the English legislation [of the old time act] had
     # been assented to (March 22, 1967)....
     # Also, as far as I can tell, there was no order-in-council varying
     # the time of Daylight Saving Time for 2005 and so the provisions of
    @@ -1799,12 +1768,12 @@ Rule	Swift	1959	only	-	Oct	lastSun	2:00	0	S
     Rule	Swift	1960	1961	-	Sep	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Regina	-6:58:36 -	LMT	1905 Sep
    -			-7:00	Regina	M%sT	1960 Apr lastSun 2:00
    +			-7:00	Regina	M%sT	1960 Apr lastSun  2:00
     			-6:00	-	CST
     Zone America/Swift_Current -7:11:20 -	LMT	1905 Sep
    -			-7:00	Canada	M%sT	1946 Apr lastSun 2:00
    +			-7:00	Canada	M%sT	1946 Apr lastSun  2:00
     			-7:00	Regina	M%sT	1950
    -			-7:00	Swift	M%sT	1972 Apr lastSun 2:00
    +			-7:00	Swift	M%sT	1972 Apr lastSun  2:00
     			-6:00	-	CST
     
     
    @@ -1854,9 +1823,7 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
     # Earlier this year I stumbled across a detailed article about the time
     # keeping history of Creston; it was written by Tammy Hardwick who is the
     # manager of the Creston & District Museum. The article was written in May 2009.
    -# 
     # http://www.ilovecreston.com/?p=articles&t=spec&ar=260
    -# 
     # According to the article, Creston has not changed its clocks since June 1918.
     # i.e. Creston has been stuck on UTC-7 for 93 years.
     # Dawson Creek, on the other hand, changed its clocks as recently as April 1972.
    @@ -1864,18 +1831,16 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
     # Unfortunately the exact date for the time change in June 1918 remains
     # unknown and will be difficult to ascertain.  I e-mailed Tammy a few months
     # ago to ask if Sunday June 2 was a reasonable guess.  She said it was just
    -# as plausible as any other date (in June).  She also said that after writing the
    -# article she had discovered another time change in 1916; this is the subject
    -# of another article which she wrote in October 2010.
    -# 
    +# as plausible as any other date (in June).  She also said that after writing
    +# the article she had discovered another time change in 1916; this is the
    +# subject of another article which she wrote in October 2010.
     # http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56
    -# 
     
     # Here is a summary of the three clock change events in Creston's history:
     # 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7)
     # Exact date unknown
     # 2. Oct 1916: switch to Pacific Standard Time (GMT-8)
    -# Exact date in October unknown;  Sunday October 1 is a reasonable guess.
    +# Exact date in October unknown; Sunday October 1 is a reasonable guess.
     # 3. June 1918: switch to Pacific Daylight Time (GMT-7)
     # Exact date in June unknown; Sunday June 2 is a reasonable guess.
     # note#1:
    @@ -1888,9 +1853,7 @@ Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
     # There is no guarantee that Creston will remain on Mountain Standard Time
     # (UTC-7) forever.
     # The subject was debated at least once this year by the town Council.
    -# 
     # http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html
    -# 
     
     # During a period WWII, summer time (Daylight saying) was mandatory in Canada.
     # In Creston, that was handled by shifting the area to PST (-8:00) then applying
    @@ -1917,7 +1880,7 @@ Zone America/Vancouver	-8:12:28 -	LMT	1884
     			-8:00	Canada	P%sT
     Zone America/Dawson_Creek -8:00:56 -	LMT	1884
     			-8:00	Canada	P%sT	1947
    -			-8:00	Vanc	P%sT	1972 Aug 30 2:00
    +			-8:00	Vanc	P%sT	1972 Aug 30  2:00
     			-7:00	-	MST
     Zone America/Creston	-7:46:04 -	LMT	1884
     			-7:00	-	MST	1916 Oct 1
    @@ -1944,18 +1907,17 @@ Zone America/Creston	-7:46:04 -	LMT	1884
     
     # From Rives McDow (1999-09-04):
     # Nunavut ... moved ... to incorporate the whole territory into one time zone.
    -# 
     # Nunavut moves to single time zone Oct. 31
    -# 
    +# http://www.nunatsiaq.com/nunavut/nvt90903_13.html
     #
     # From Antoine Leca (1999-09-06):
     # We then need to create a new timezone for the Kitikmeot region of Nunavut
     # to differentiate it from the Yellowknife region.
     
     # From Paul Eggert (1999-09-20):
    -# 
     # Basic Facts: The New Territory
    -#  (1999) reports that Pangnirtung operates on eastern time,
    +# http://www.nunavut.com/basicfacts/english/basicfacts_1territory.html
    +# (1999) reports that Pangnirtung operates on eastern time,
     # and that Coral Harbour does not observe DST.  We don't know when
     # Pangnirtung switched to eastern time; we'll guess 1995.
     
    @@ -1983,8 +1945,8 @@ Zone America/Creston	-7:46:04 -	LMT	1884
     # the current state of affairs.
     
     # From Michaela Rodrigue, writing in the
    -# 
    -# Nunatsiaq News (1999-11-19):
    +# Nunatsiaq News (1999-11-19):
    +# http://www.nunatsiaq.com/archives/nunavut991130/nvt91119_17.html
     # Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
     # central - or Nunavut time - for government offices, and eastern time
     # for municipal offices and schools....  Igloolik [was similar but then]
    @@ -2002,10 +1964,8 @@ Zone America/Creston	-7:46:04 -	LMT	1884
     # Central Time and Southampton Island [in the Central zone] is not
     # required to use daylight savings.
     
    -# From
    -# 
    -# Nunavut now has two time zones
    -#  (2000-11-10):
    +# From 
    +# Nunavut now has two time zones (2000-11-10):
     # The Nunavut government would allow its employees in Kugluktuk and
     # Cambridge Bay to operate on central time year-round, putting them
     # one hour behind the rest of Nunavut for six months during the winter.
    @@ -2096,9 +2056,7 @@ Zone America/Creston	-7:46:04 -	LMT	1884
     # used to be the mayor of Resolute Bay and he apparently owns half the
     # businesses including "South Camp Inn." This website has some info on
     # Aziz:
    -# 
     # http://www.uphere.ca/node/493
    -# 
     #
     # I sent Aziz an e-mail asking when Resolute Bay had stopped using
     # Eastern Standard Time.
    @@ -2136,47 +2094,47 @@ Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     # aka Panniqtuuq
     Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
    -			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
    -			-5:00	Canada	E%sT	1999 Oct 31 2:00
    -			-6:00	Canada	C%sT	2000 Oct 29 2:00
    +			-4:00	NT_YK	A%sT	1995 Apr Sun>=1  2:00
    +			-5:00	Canada	E%sT	1999 Oct 31  2:00
    +			-6:00	Canada	C%sT	2000 Oct 29  2:00
     			-5:00	Canada	E%sT
     # formerly Frobisher Bay
     Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
    -			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
    -			-6:00	Canada	C%sT	2000 Oct 29 2:00
    +			-5:00	NT_YK	E%sT	1999 Oct 31  2:00
    +			-6:00	Canada	C%sT	2000 Oct 29  2:00
     			-5:00	Canada	E%sT
     # aka Qausuittuq
     Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
    -			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
    -			-5:00	-	EST	2001 Apr  1 3:00
    -			-6:00	Canada	C%sT	2006 Oct 29 2:00
    -			-5:00	-	EST	2007 Mar 11 3:00
    +			-6:00	NT_YK	C%sT	2000 Oct 29  2:00
    +			-5:00	-	EST	2001 Apr  1  3:00
    +			-6:00	Canada	C%sT	2006 Oct 29  2:00
    +			-5:00	-	EST	2007 Mar 11  3:00
     			-6:00	Canada	C%sT
     # aka Kangiqiniq
     Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
    -			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
    -			-5:00	-	EST	2001 Apr  1 3:00
    +			-6:00	NT_YK	C%sT	2000 Oct 29  2:00
    +			-5:00	-	EST	2001 Apr  1  3:00
     			-6:00	Canada	C%sT
     # aka Iqaluktuuttiaq
     Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
    -			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
    -			-6:00	Canada	C%sT	2000 Oct 29 2:00
    -			-5:00	-	EST	2000 Nov  5 0:00
    -			-6:00	-	CST	2001 Apr  1 3:00
    +			-7:00	NT_YK	M%sT	1999 Oct 31  2:00
    +			-6:00	Canada	C%sT	2000 Oct 29  2:00
    +			-5:00	-	EST	2000 Nov  5  0:00
    +			-6:00	-	CST	2001 Apr  1  3:00
     			-7:00	Canada	M%sT
     Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
     			-7:00	NT_YK	M%sT	1980
     			-7:00	Canada	M%sT
     Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
    -			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
    +			-8:00	NT_YK	P%sT	1979 Apr lastSun  2:00
     			-7:00	NT_YK	M%sT	1980
     			-7:00	Canada	M%sT
     Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
    -			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
    +			-9:00	NT_YK	Y%sT	1966 Jul  1  2:00
     			-8:00	NT_YK	P%sT	1980
     			-8:00	Canada	P%sT
     Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
    -			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
    +			-9:00	NT_YK	Y%sT	1973 Oct 28  0:00
     			-8:00	NT_YK	P%sT	1980
     			-8:00	Canada	P%sT
     
    @@ -2188,9 +2146,8 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # From Paul Eggert (2001-03-05):
     # The Investigation and Analysis Service of the
     # Mexican Library of Congress (MLoC) has published a
    -# 
     # history of Mexican local time (in Spanish)
    -# .
    +# http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/
     #
     # Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
     # (In all cases we go with the MLoC.)
    @@ -2235,9 +2192,8 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # -------------- End Forwarded Message --------------
     # From Paul Eggert (1996-06-12):
     # For an English translation of the decree, see
    -# 
     # "Diario Oficial: Time Zone Changeover" (1996-01-04).
    -# 
    +# http://mexico-travel.com/extra/timezone_eng.html
     
     # From Rives McDow (1998-10-08):
     # The State of Quintana Roo has reverted back to central STD and DST times
    @@ -2249,7 +2205,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # savings time so as to stay on the same time zone as the southern part of
     # Arizona year round.
     
    -# From Jesper Norgaard, translating
    +# From Jesper Nørgaard, translating
     #  (2001-01-17):
     # In Oaxaca, the 55.000 teachers from the Section 22 of the National
     # Syndicate of Education Workers, refuse to apply daylight saving each
    @@ -2262,7 +2218,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
     # that Summer Time will be reduced from seven to five months, starting
     # this year....
    -# 
    +# http://www.publico.com.mx/scripts/texto3.asp?action=pagina&pag=21&pos=p&secc=naci&date=01/17/2001
     # [translated], says "summer time will ... take effect on the first Sunday
     # in May, and end on the last Sunday of September.
     
    @@ -2270,23 +2226,22 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # The 2001-01-24 traditional Washington Post contained the page one
     # story "Timely Issue Divides Mexicans."...
     # http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
    -# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
    +# ... Mexico City Mayor López Obrador "...is threatening to keep
     # Mexico City and its 20 million residents on a different time than
    -# the rest of the country..." In particular, Lopez Obrador would abolish
    +# the rest of the country..." In particular, López Obrador would abolish
     # observation of Daylight Saving Time.
     
    -# 
     # Official statute published by the Energy Department
    -#  (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
    -# and Sonora with no DST.  This was reported by Jesper Norgaard (2001-02-03).
    +# http://www.conae.gob.mx/ahorro/decretohorver2001.html#decre
    +# (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
    +# and Sonora with no DST.  This was reported by Jesper Nørgaard (2001-02-03).
     
     # From Paul Eggert (2001-03-03):
     #
    -# 
    +# http://www.latimes.com/news/nation/20010303/t000018766.html
     # James F. Smith writes in today's LA Times
    -# 
     # * Sonora will continue to observe standard time.
    -# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
    +# * Last week Mexico City's mayor Andrés Manuel López Obrador decreed that
     #   the Federal District will not adopt DST.
     # * 4 of 16 district leaders announced they'll ignore the decree.
     # * The decree does not affect federal-controlled facilities including
    @@ -2294,7 +2249,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     #
     # For now we'll assume that the Federal District will bow to federal rules.
     
    -# From Jesper Norgaard (2001-04-01):
    +# From Jesper Nørgaard (2001-04-01):
     # I found some references to the Mexican application of daylight
     # saving, which modifies what I had already sent you, stating earlier
     # that a number of northern Mexican states would go on daylight
    @@ -2303,7 +2258,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # saving all year) will follow the original decree of president
     # Vicente Fox, starting daylight saving May 6, 2001 and ending
     # September 30, 2001.
    -# References: "Diario de Monterrey" 
    +# References: "Diario de Monterrey" 
     # Palabra  (2001-03-31)
     
     # From Reuters (2001-09-04):
    @@ -2315,7 +2270,7 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # standard time. "This is so residents of the Federal District are not
     # subject to unexpected time changes," a statement from the court said.
     
    -# From Jesper Norgaard Welen (2002-03-12):
    +# From Jesper Nørgaard Welen (2002-03-12):
     # ... consulting my local grocery store(!) and my coworkers, they all insisted
     # that a new decision had been made to reinstate US style DST in Mexico....
     # http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
    @@ -2329,48 +2284,36 @@ Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
     # > the United States.
     # Now this has passed both the Congress and the Senate, so starting from
     # 2010, some border regions will be the same:
    -# 
     # http://www.signonsandiego.com/news/2009/dec/28/clocks-will-match-both-sides-border/
    -# 
    -# 
     # http://www.elmananarey.com/diario/noticia/nacional/noticias/empatan_horario_de_frontera_con_eu/621939
    -# 
     # (Spanish)
     #
     # Could not find the new law text, but the proposed law text changes are here:
    -# 
     # http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/20091210-V.pdf
    -# 
     # (Gaceta Parlamentaria)
     #
     # There is also a list of the votes here:
    -# 
     # http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/V2-101209.html
    -# 
     #
     # Our page:
    -# 
     # http://www.timeanddate.com/news/time/north-mexico-dst-change.html
    -# 
     
     # From Arthur David Olson (2010-01-20):
     # The page
    -# 
     # http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010
    -# 
     # includes this text:
     # En los municipios fronterizos de Tijuana y Mexicali en Baja California;
    -# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
    -# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
    -# Tamaulipas, la aplicación de este horario estacional surtirá efecto
    -# desde las dos horas del segundo domingo de marzo y concluirá a las dos
    +# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
    +# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
    +# Tamaulipas, la aplicación de este horario estacional surtirá efecto
    +# desde las dos horas del segundo domingo de marzo y concluirá a las dos
     # horas del primer domingo de noviembre.
     # En los municipios fronterizos que se encuentren ubicados en la franja
    -# fronteriza norte en el territorio comprendido entre la línea
    -# internacional y la línea paralela ubicada a una distancia de veinte
    -# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
    -# interior del país, la aplicación de este horario estacional surtirá
    -# efecto desde las dos horas del segundo domingo de marzo y concluirá a
    +# fronteriza norte en el territorio comprendido entre la línea
    +# internacional y la línea paralela ubicada a una distancia de veinte
    +# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
    +# interior del país, la aplicación de este horario estacional surtirá
    +# efecto desde las dos horas del segundo domingo de marzo y concluirá a
     # las dos horas del primer domingo de noviembre.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    @@ -2389,39 +2332,39 @@ Rule	Mexico	2001	only	-	Sep	lastSun	2:00	0	S
     Rule	Mexico	2002	max	-	Apr	Sun>=1	2:00	1:00	D
     Rule	Mexico	2002	max	-	Oct	lastSun	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -# Quintana Roo
    +# Quintana Roo; represented by Cancún
     Zone America/Cancun	-5:47:04 -	LMT	1922 Jan  1  0:12:56
     			-6:00	-	CST	1981 Dec 23
     			-5:00	Mexico	E%sT	1998 Aug  2  2:00
     			-6:00	Mexico	C%sT
    -# Campeche, Yucatan
    +# Campeche, Yucatán; represented by Mérida
     Zone America/Merida	-5:58:28 -	LMT	1922 Jan  1  0:01:32
     			-6:00	-	CST	1981 Dec 23
     			-5:00	-	EST	1982 Dec  2
     			-6:00	Mexico	C%sT
    -# Coahuila, Durango, Nuevo Leon, Tamaulipas (near US border)
    +# Coahuila, Durango, Nuevo León, Tamaulipas (near US border)
     Zone America/Matamoros	-6:40:00 -	LMT	1921 Dec 31 23:20:00
     			-6:00	-	CST	1988
     			-6:00	US	C%sT	1989
     			-6:00	Mexico	C%sT	2010
     			-6:00	US	C%sT
    -# Coahuila, Durango, Nuevo Leon, Tamaulipas (away from US border)
    +# Coahuila, Durango, Nuevo León, Tamaulipas (away from US border)
     Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
     			-6:00	-	CST	1988
     			-6:00	US	C%sT	1989
     			-6:00	Mexico	C%sT
     # Central Mexico
    -Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1 0:23:24
    +Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1  0:23:24
     			-7:00	-	MST	1927 Jun 10 23:00
     			-6:00	-	CST	1930 Nov 15
     			-7:00	-	MST	1931 May  1 23:00
     			-6:00	-	CST	1931 Oct
     			-7:00	-	MST	1932 Apr  1
    -			-6:00	Mexico	C%sT	2001 Sep 30 02:00
    +			-6:00	Mexico	C%sT	2001 Sep 30  2:00
     			-6:00	-	CST	2002 Feb 20
     			-6:00	Mexico	C%sT
     # Chihuahua (near US border)
    -Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
    +Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan  1  0:02:20
     			-7:00	-	MST	1927 Jun 10 23:00
     			-6:00	-	CST	1930 Nov 15
     			-7:00	-	MST	1931 May  1 23:00
    @@ -2429,7 +2372,7 @@ Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
     			-7:00	-	MST	1932 Apr  1
     			-6:00	-	CST	1996
     			-6:00	Mexico	C%sT	1998
    -			-6:00	-	CST	1998 Apr Sun>=1 3:00
    +			-6:00	-	CST	1998 Apr Sun>=1  3:00
     			-7:00	Mexico	M%sT	2010
     			-7:00	US	M%sT
     # Chihuahua (away from US border)
    @@ -2441,7 +2384,7 @@ Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
     			-7:00	-	MST	1932 Apr  1
     			-6:00	-	CST	1996
     			-6:00	Mexico	C%sT	1998
    -			-6:00	-	CST	1998 Apr Sun>=1 3:00
    +			-6:00	-	CST	1998 Apr Sun>=1  3:00
     			-7:00	Mexico	M%sT
     # Sonora
     Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
    @@ -2457,42 +2400,33 @@ Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
     			-7:00	-	MST
     
     # From Alexander Krivenyshev (2010-04-21):
    -# According to news, Bahía de Banderas (Mexican state of Nayarit)
    +# According to news, Bahía de Banderas (Mexican state of Nayarit)
     # changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
     # share the same time zone as nearby city Puerto Vallarta, Jalisco).
     #
     # (Spanish)
    -# Bahía de Banderas homologa su horario al del centro del
    -# país, a partir de este domingo
    -# 
    +# Bahía de Banderas homologa su horario al del centro del
    +# país, a partir de este domingo
     # http://www.nayarit.gob.mx/notes.asp?id=20748
    -# 
     #
    -# Bahía de Banderas homologa su horario con el del Centro del
    -# País
    -# 
    -# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
    -# 
    +# Bahía de Banderas homologa su horario con el del Centro del
    +# País
    +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50
     #
     # (English)
    -# Puerto Vallarta and Bahía de Banderas: One Time Zone
    -# 
    +# Puerto Vallarta and Bahía de Banderas: One Time Zone
     # http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
    -# 
    -#
    -# or
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
    -# 
     #
     # "Mexico's Senate approved the amendments to the Mexican Schedule System that
    -# will allow Bahía de Banderas and Puerto Vallarta to share the same time
    +# will allow Bahía de Banderas and Puerto Vallarta to share the same time
     # zone ..."
     # Baja California Sur, Nayarit, Sinaloa
     
     # From Arthur David Olson (2010-05-01):
     # Use "Bahia_Banderas" to keep the name to fourteen characters.
     
    +# Mazatlán
     Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
     			-7:00	-	MST	1927 Jun 10 23:00
     			-6:00	-	CST	1930 Nov 15
    @@ -2504,6 +2438,7 @@ Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
     			-8:00	-	PST	1970
     			-7:00	Mexico	M%sT
     
    +# Bahía de Banderas
     Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
     			-7:00	-	MST	1927 Jun 10 23:00
     			-6:00	-	CST	1930 Nov 15
    @@ -2513,7 +2448,7 @@ Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
     			-6:00	-	CST	1942 Apr 24
     			-7:00	-	MST	1949 Jan 14
     			-8:00	-	PST	1970
    -			-7:00	Mexico	M%sT	2010 Apr 4 2:00
    +			-7:00	Mexico	M%sT	2010 Apr  4  2:00
     			-6:00	Mexico	C%sT
     
     # Baja California (near US border)
    @@ -2560,7 +2495,7 @@ Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
     # America/Tijuana only in that it did not observe DST from 1976
     # through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
     # Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
    -# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
    +# that the 1987 OAG says "Only Ensenada, Mexicali, San Felipe and
     # Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
     # DST-observance was a town-by-town matter back then.  This concerns
     # data after 1970 so most likely there should be at least one Zone
    @@ -2573,7 +2508,7 @@ Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
     ###############################################################################
     
     # Anguilla
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # Antigua and Barbuda
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    @@ -2609,8 +2544,8 @@ Rule	Barb	1978	1980	-	Apr	Sun>=15	2:00	1:00	D
     Rule	Barb	1979	only	-	Sep	30	2:00	0	S
     Rule	Barb	1980	only	-	Sep	25	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Barbados	-3:58:29 -	LMT	1924		# Bridgetown
    -			-3:58:29 -	BMT	1932	  # Bridgetown Mean Time
    +Zone America/Barbados	-3:58:29 -	LMT	1924 # Bridgetown
    +			-3:58:29 -	BMT	1932 # Bridgetown Mean Time
     			-4:00	Barb	A%sT
     
     # Belize
    @@ -2640,20 +2575,20 @@ Zone	America/Belize	-5:52:48 -	LMT	1912 Apr
     # http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Atlantic/Bermuda	-4:19:18 -	LMT	1930 Jan  1 2:00    # Hamilton
    -			-4:00	-	AST	1974 Apr 28 2:00
    +Zone Atlantic/Bermuda	-4:19:18 -	LMT	1930 Jan  1  2:00 # Hamilton
    +			-4:00	-	AST	1974 Apr 28  2:00
     			-4:00	Canada	A%sT	1976
     			-4:00	US	A%sT
     
     # Cayman Is
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	America/Cayman	-5:25:32 -	LMT	1890		# Georgetown
    -			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
    +Zone	America/Cayman	-5:25:32 -	LMT	1890     # Georgetown
    +			-5:07:11 -	KMT	1912 Feb # Kingston Mean Time
     			-5:00	-	EST
     
     # Costa Rica
     
    -# Milne gives -5:36:13.3 as San Jose mean time; round to nearest.
    +# Milne gives -5:36:13.3 as San José mean time; round to nearest.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
    @@ -2663,10 +2598,10 @@ Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
     # go with Shanks & Pottenger.
     Rule	CR	1991	only	-	Jul	 1	0:00	0	S
     Rule	CR	1992	only	-	Mar	15	0:00	0	S
    -# There are too many San Joses elsewhere, so we'll use 'Costa Rica'.
    +# There are too many San Josés elsewhere, so we'll use 'Costa Rica'.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
    -			-5:36:13 -	SJMT	1921 Jan 15 # San Jose Mean Time
    +Zone America/Costa_Rica	-5:36:13 -	LMT	1890        # San José
    +			-5:36:13 -	SJMT	1921 Jan 15 # San José Mean Time
     			-6:00	CR	C%sT
     # Coco
     # no information; probably like America/Costa_Rica
    @@ -2685,8 +2620,8 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # During the game, play-by-play announcer Jim Hunter noted that
     # "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
     # Time today."  (The "two hour" remark referred to losing one hour of
    -# sleep on 1999-03-28--when the announcers were in Cuba as it switched
    -# to DST--and one more hour on 1999-04-04--when the announcers will have
    +# sleep on 1999-03-28 - when the announcers were in Cuba as it switched
    +# to DST - and one more hour on 1999-04-04 - when the announcers will have
     # returned to Baltimore, which switches on that date.)
     
     # From Steffen Thorsen (2013-11-11):
    @@ -2708,16 +2643,16 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # adjustment in Cuba.  We will stay in daylight saving time:
     # http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
     
    -# From Jesper Norgaard Welen (2006-10-21):
    +# From Jesper Nørgaard Welen (2006-10-21):
     # An article in GRANMA INTERNACIONAL claims that Cuba will end
     # the 3 years of permanent DST next weekend, see
     # http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
     # "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
    -# watches should be set back one hour -- going back to 00:00 hours -- returning
    +# watches should be set back one hour - going back to 00:00 hours - returning
     # to the normal schedule....
     
     # From Paul Eggert (2007-03-02):
    -# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
    +# , dated yesterday,
     # says Cuban clocks will advance at midnight on March 10.
     # For lack of better information, assume Cuba will use US rules,
     # except that it switches at midnight standard time as usual.
    @@ -2731,10 +2666,10 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
     # http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
     #
    -# From Alex Kryvenishev (2007-10-25):
    +# From Alex Krivenyshev (2007-10-25):
     # Here is also article from Granma (Cuba):
     #
    -# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
    +# Regirá el Horario Normal desde el próximo domingo 28 de octubre
     # http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
     #
     # http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
    @@ -2742,23 +2677,18 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # From Arthur David Olson (2008-03-09):
     # I'm in Maryland which is now observing United States Eastern Daylight
     # Time. At 9:44 local time I used RealPlayer to listen to
    -# 
     # http://media.enet.cu/radioreloj
    -# , a Cuban information station, and heard
    +# a Cuban information station, and heard
     # the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
     # indicating that Cuba is still on standard time.
     
     # From Steffen Thorsen (2008-03-12):
     # It seems that Cuba will start DST on Sunday, 2007-03-16...
     # It was announced yesterday, according to this source (in Spanish):
    -# 
     # http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
    -# 
     #
     # Some more background information is posted here:
    -# 
     # http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
    -# 
     #
     # The article also says that Cuba has been observing DST since 1963,
     # while Shanks (and tzdata) has 1965 as the first date (except in the
    @@ -2768,18 +2698,14 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # change some historic records as well.
     #
     # One example:
    -# 
     # http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
    -# 
     
    -# From Jesper Norgaard Welen (2008-03-13):
    +# From Jesper Nørgaard Welen (2008-03-13):
     # The Cuban time change has just been confirmed on the most authoritative
     # web site, the Granma.  Please check out
    -# 
     # http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
    -# 
     #
    -# Basically as expected after Steffen Thorsens information, the change
    +# Basically as expected after Steffen Thorsen's information, the change
     # will take place midnight between Saturday and Sunday.
     
     # From Arthur David Olson (2008-03-12):
    @@ -2790,18 +2716,14 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
     # not on midnight March 14 / March 15 as previously thought.
     #
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
     # (in Spanish)
    -# 
     
     # From Arthur David Olson (2009-03-09)
     # I listened over the Internet to
    -# 
     # http://media.enet.cu/readioreloj
    -# 
     # this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
    -# the time was announced as "diez cinco"--the same time as here, indicating
    +# the time was announced as "diez cinco" - the same time as here, indicating
     # that has indeed switched to DST. Assume second Sunday from 2009 forward.
     
     # From Steffen Thorsen (2011-03-08):
    @@ -2810,42 +2732,30 @@ Zone America/Costa_Rica	-5:36:13 -	LMT	1890		# San Jose
     # changed at all).
     #
     # Source:
    -# 
     # http://granma.co.cu/2011/03/08/nacional/artic01.html
    -# 
     #
     # Our info:
    -# 
     # http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
    -# 
     #
     # From Steffen Thorsen (2011-10-30)
     # Cuba will end DST two weeks later this year. Instead of going back
     # tonight, it has been delayed to 2011-11-13 at 01:00.
     #
     # One source (Spanish)
    -# 
     # http://www.radioangulo.cu/noticias/cuba/17105-cuba-restablecera-el-horario-del-meridiano-de-greenwich.html
    -# 
     #
     # Our page:
    -# 
     # http://www.timeanddate.com/news/time/cuba-time-changes-2011.html
    -# 
     #
     # From Steffen Thorsen (2012-03-01)
     # According to Radio Reloj, Cuba will start DST on Midnight between March
     # 31 and April 1.
     #
     # Radio Reloj has the following info (Spanish):
    -# 
     # http://www.radioreloj.cu/index.php/noticias-radio-reloj/71-miscelaneas/7529-cuba-aplicara-el-horario-de-verano-desde-el-1-de-abril
    -# 
     #
     # Our info on it:
    -# 
     # http://www.timeanddate.com/news/time/cuba-starts-dst-2012.html
    -# 
     
     # From Steffen Thorsen (2012-11-03):
     # Radio Reloj and many other sources report that Cuba is changing back
    @@ -2901,7 +2811,7 @@ Zone	America/Havana	-5:29:28 -	LMT	1890
     			-5:00	Cuba	C%sT
     
     # Dominica
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # Dominican Republic
     
    @@ -2934,8 +2844,8 @@ Rule	DR	1972	1974	-	Jan	21	0:00	0	S
     Zone America/Santo_Domingo -4:39:36 -	LMT	1890
     			-4:40	-	SDMT	1933 Apr  1 12:00 # S. Dom. MT
     			-5:00	DR	E%sT	1974 Oct 27
    -			-4:00	-	AST	2000 Oct 29 02:00
    -			-5:00	US	E%sT	2000 Dec  3 01:00
    +			-4:00	-	AST	2000 Oct 29  2:00
    +			-5:00	US	E%sT	2000 Dec  3  1:00
     			-4:00	-	AST
     
     # El Salvador
    @@ -2946,20 +2856,20 @@ Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
     # There are too many San Salvadors elsewhere, so use America/El_Salvador
     # instead of America/San_Salvador.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
    +Zone America/El_Salvador -5:56:48 -	LMT	1921 # San Salvador
     			-6:00	Salv	C%sT
     
     # Grenada
     # Guadeloupe
    -# St Barthelemy
    +# St Barthélemy
     # St Martin (French part)
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # Guatemala
     #
     # From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
     # Diario Co Latino, at
    -# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
    +# ,
     # says in an article dated 2006-04-19 that the Guatemalan government had
     # decided on that date to advance official time by 60 minutes, to lessen the
     # impact of the elevated cost of oil....  Daylight saving time will last from
    @@ -2967,7 +2877,7 @@ Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
     # From Paul Eggert (2006-06-22):
     # The Ministry of Energy and Mines, press release CP-15/2006
     # (2006-04-19), says DST ends at 24:00.  See
    -# .
    +# http://www.sieca.org.gt/Sitio_publico/Energeticos/Doc/Medidas/Cambio_Horario_Nac_190406.pdf
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
     Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
    @@ -2984,11 +2894,10 @@ Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
     
     # Haiti
     # From Gwillim Law (2005-04-15):
    -# Risto O. Nykanen wrote me that Haiti is now on DST.
    -# I searched for confirmation, and I found a
    -#  press release
    +# Risto O. Nykänen wrote me that Haiti is now on DST.
    +# I searched for confirmation, and I found a press release
     # on the Web page of the Haitian Consulate in Chicago (2005-03-31),
    -# .  Translated from French, it says:
    +# .  Translated from French, it says:
     #
     #  "The Prime Minister's Communication Office notifies the public in general
     #   and the press in particular that, following a decision of the Interior
    @@ -3065,14 +2974,14 @@ Zone America/Port-au-Prince -4:49:20 -	LMT	1890
     #  that Manuel Zelaya, the president
     # of Honduras, refused to back down on this.
     
    -# From Jesper Norgaard Welen (2006-08-08):
    +# From Jesper Nørgaard Welen (2006-08-08):
     # It seems that Honduras has returned from DST to standard time this Monday at
     # 00:00 hours (prolonging Sunday to 25 hours duration).
     # http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
     
     # From Paul Eggert (2006-08-08):
    -# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
    -# .
    +# Also see Diario El Heraldo, The country returns to standard time (2006-08-08).
    +# http://www.elheraldo.hn/nota.php?nid=54941&sec=12
     # It mentions executive decree 18-2006.
     
     # From Steffen Thorsen (2006-08-17):
    @@ -3100,22 +3009,22 @@ Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
     # unspecified official document, and says "This time is used throughout the
     # island".  Go with Milne.  Round to the nearest second as required by zic.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	America/Jamaica	-5:07:11 -	LMT	1890		# Kingston
    +Zone	America/Jamaica	-5:07:11 -	LMT	1890        # Kingston
     			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
    -			-5:00	-	EST	1974 Apr 28 2:00
    +			-5:00	-	EST	1974 Apr 28  2:00
     			-5:00	US	E%sT	1984
     			-5:00	-	EST
     
     # Martinique
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
    -			-4:04:20 -	FFMT	1911 May     # Fort-de-France MT
    +Zone America/Martinique	-4:04:20 -      LMT	1890        # Fort-de-France
    +			-4:04:20 -	FFMT	1911 May    # Fort-de-France MT
     			-4:00	-	AST	1980 Apr  6
     			-4:00	1:00	ADT	1980 Sep 28
     			-4:00	-	AST
     
     # Montserrat
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # Nicaragua
     #
    @@ -3138,27 +3047,27 @@ Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
     # From Gwillim Law (2005-04-21):
     # The Associated Press story on the time change, which can be found at
     # http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
    -# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
    +# and elsewhere, says (fifth paragraph, translated from Spanish): "The last
     # time that a change of clocks was applied to save energy was in the year 2000
    -# during the Arnoldo Aleman administration."...
    +# during the Arnoldo Alemán administration."...
     # The northamerica file says that Nicaragua has been on UTC-6 continuously
     # since December 1998.  I wasn't able to find any details of Nicaraguan time
     # changes in 2000.  Perhaps a note could be added to the northamerica file, to
     # the effect that we have indirect evidence that DST was observed in 2000.
     #
    -# From Jesper Norgaard Welen (2005-11-02):
    +# From Jesper Nørgaard Welen (2005-11-02):
     # Nicaragua left DST the 2005-10-02 at 00:00 (local time).
     # http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
     # (2005-09-26)
     #
    -# From Jesper Norgaard Welen (2006-05-05):
    +# From Jesper Nørgaard Welen (2006-05-05):
     # http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
     # (my informal translation)
    -# By order of the president of the republic, Enrique Bolanos, Nicaragua
    +# By order of the president of the republic, Enrique Bolaños, Nicaragua
     # advanced by sixty minutes their official time, yesterday at 2 in the
    -# morning, and will stay that way until 30.th. of september.
    +# morning, and will stay that way until 30th of September.
     #
    -# From Jesper Norgaard Welen (2006-09-30):
    +# From Jesper Nørgaard Welen (2006-09-30):
     # http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
     # My informal translation runs:
     # The natural sun time is restored in all the national territory, in that the
    @@ -3176,7 +3085,7 @@ Zone	America/Managua	-5:45:08 -	LMT	1890
     			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
     			-6:00	-	CST	1973 May
     			-5:00	-	EST	1975 Feb 16
    -			-6:00	Nic	C%sT	1992 Jan  1 4:00
    +			-6:00	Nic	C%sT	1992 Jan  1  4:00
     			-5:00	-	EST	1992 Sep 24
     			-6:00	-	CST	1993
     			-5:00	-	EST	1997
    @@ -3185,36 +3094,36 @@ Zone	America/Managua	-5:45:08 -	LMT	1890
     # Panama
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	America/Panama	-5:18:08 -	LMT	1890
    -			-5:19:36 -	CMT	1908 Apr 22   # Colon Mean Time
    +			-5:19:36 -	CMT	1908 Apr 22 # Colón Mean Time
     			-5:00	-	EST
     
     # Puerto Rico
     # There are too many San Juans elsewhere, so we'll use 'Puerto_Rico'.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
    +Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00 # San Juan
     			-4:00	-	AST	1942 May  3
     			-4:00	US	A%sT	1946
     			-4:00	-	AST
     
     # St Kitts-Nevis
     # St Lucia
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # St Pierre and Miquelon
     # There are too many St Pierres elsewhere, so we'll use 'Miquelon'.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
    +Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15 # St Pierre
     			-4:00	-	AST	1980 May
     			-3:00	-	PMST	1987 # Pierre & Miquelon Time
     			-3:00	Canada	PM%sT
     
     # St Vincent and the Grenadines
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
     
     # Turks and Caicos
     #
     # From Chris Dunn in
    -# 
    +# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=415007
     # (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
     # daylight saving dates for time changes have been adjusted to match
     # the recent U.S. change of dates.
    @@ -3227,21 +3136,23 @@ Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
     # Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
     # indicating that the normal ET rules are followed.
     #
    -# From Paul Eggert (2006-05-01):
    -# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
    -# says they switch at midnight.  Go with Shanks & Pottenger.
    +# From Paul Eggert (2014-08-19):
    +# The 2014-08-13 Cabinet meeting decided to stay on UTC-4 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 on 2014-11-02 at 02:00.
     #
    -# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
    -Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
    -Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
    -Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
    -Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Grand_Turk	-4:44:32 -	LMT	1890
    -			-5:07:11 -	KMT	1912 Feb    # Kingston Mean Time
    -			-5:00	TC	E%sT
    +			-5:07:11 -	KMT	1912 Feb # Kingston Mean Time
    +			-5:00	-	EST	1979
    +			-5:00	US	E%sT	2014 Nov  2  2:00
    +			-4:00	-	AST
     
     # British Virgin Is
     # Virgin Is
    -# See 'southamerica'.
    +# See America/Port_of_Spain.
    +
    +
    +# Local Variables:
    +# coding: utf-8
    +# End:
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/pacificnew b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
    index 09000c3457a..9b9257a45fe 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
    @@ -21,7 +21,6 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/southamerica b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
    index 02bf3bb6332..398ec0e4f06 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/southamerica
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
    @@ -21,13 +21,13 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    -# This data is by no means authoritative; if you think you know better,
    +# This file is by no means authoritative; if you think you know better,
     # go ahead and edit the file (and please send any changes to
    -# tz@iana.org for general use in the future).
    +# tz@iana.org for general use in the future).  For more, please see
    +# the file CONTRIBUTING in the tz distribution.
     
     # From Paul Eggert (2006-03-22):
     # A good source for time zone historical data outside the U.S. is
    @@ -35,8 +35,8 @@
     # San Diego: ACS Publications, Inc. (2003).
     #
     # For data circa 1899, a common source is:
    -# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
    -# .
    +# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94.
    +# http://www.jstor.org/stable/1774359
     #
     # Gwillim Law writes that a good source
     # for recent time zone data is the International Air Transport
    @@ -53,24 +53,24 @@
     #	I suggest the use of _Summer time_ instead of the more cumbersome
     #	_daylight-saving time_.  _Summer time_ seems to be in general use
     #	in Europe and South America.
    -#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
    +#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
     #	H L Mencken, _The American Language: Supplement I_ (1960), p 466
     #
     # Earlier editions of these tables also used the North American style
     # for time zones in Brazil, but this was incorrect, as Brazilians say
    -# "summer time".  Reinaldo Goulart, a Sao Paulo businessman active in
    +# "summer time".  Reinaldo Goulart, a São Paulo businessman active in
     # the railroad sector, writes (1999-07-06):
     #	The subject of time zones is currently a matter of discussion/debate in
    -#	Brazil.  Let's say that "the Brasilia time" is considered the
    -#	"official time" because Brasilia is the capital city.
    -#	The other three time zones are called "Brasilia time "minus one" or
    +#	Brazil.  Let's say that "the Brasília time" is considered the
    +#	"official time" because Brasília is the capital city.
    +#	The other three time zones are called "Brasília time "minus one" or
     #	"plus one" or "plus two".  As far as I know there is no such
     #	name/designation as "Eastern Time" or "Central Time".
     # So I invented the following (English-language) abbreviations for now.
     # Corrections are welcome!
     #		std	dst
     #	-2:00	FNT	FNST	Fernando de Noronha
    -#	-3:00	BRT	BRST	Brasilia
    +#	-3:00	BRT	BRST	Brasília
     #	-4:00	AMT	AMST	Amazon
     #	-5:00	ACT	ACST	Acre
     
    @@ -84,7 +84,7 @@
     # Argentina: first Sunday in October to first Sunday in April since 1976.
     # Double Summer time from 1969 to 1974.  Switches at midnight.
     
    -# From U. S. Naval Observatory (1988-01-199):
    +# From U. S. Naval Observatory (1988-01-19):
     # ARGENTINA           3 H BEHIND   UTC
     
     # From Hernan G. Otero (1995-06-26):
    @@ -118,7 +118,7 @@ Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
     # From Hernan G. Otero (1995-06-26):
     # These corrections were contributed by InterSoft Argentina S.A.,
     # obtaining the data from the:
    -# Talleres de Hidrografia Naval Argentina
    +# Talleres de Hidrografía Naval Argentina
     # (Argentine Naval Hydrography Institute)
     Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
     Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
    @@ -140,13 +140,13 @@ Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
     Rule	Arg	2000	only	-	Mar	3	0:00	0	-
     #
     # From Peter Gradelski via Steffen Thorsen (2000-03-01):
    -# We just checked with our Sao Paulo office and they say the government of
    +# We just checked with our São Paulo office and they say the government of
     # Argentina decided not to become one of the countries that go on or off DST.
     # So Buenos Aires should be -3 hours from GMT at all times.
     #
    -# From Fabian L. Arce Jofre (2000-04-04):
    +# From Fabián L. Arce Jofré (2000-04-04):
     # The law that claimed DST for Argentina was derogated by President Fernando
    -# de la Rua on March 2, 2000, because it would make people spend more energy
    +# de la Rúa on March 2, 2000, because it would make people spend more energy
     # in the winter time, rather than less.  The change took effect on March 3.
     #
     # From Mariano Absatz (2001-06-06):
    @@ -179,15 +179,13 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
     # that Argentina will use DST next year as well, from October to
     # March, although exact rules are not given.
     #
    -# From Jesper Norgaard Welen (2007-12-26)
    +# From Jesper Nørgaard Welen (2007-12-26)
     # The last hurdle of Argentina DST is over, the proposal was approved in
    -# the lower chamber too (Deputados) with a vote 192 for and 2 against.
    +# the lower chamber too (Diputados) with a vote 192 for and 2 against.
     # By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
     # the original scanned proposal, where the dates and the zero hours are
     # clear and unambiguous...This is the article about final approval:
    -# 
     # http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
    -# 
     #
     # From Paul Eggert (2007-12-22):
     # For dates after mid-2008, the following rules are my guesses and
    @@ -197,13 +195,8 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
     # As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
     # Argentina will start DST on Sunday October 19, 2008.
     #
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
    -# 
    -# OR
    -# 
     # http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
    -# 
     
     # From Rodrigo Severo (2008-10-06):
     # Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
    @@ -212,48 +205,39 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
     # Hi, there is a problem with timezone-data-2008e and maybe with
     # timezone-data-2008f
     # Argentinian law [Number] 25.155 is no longer valid.
    -# 
     # http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
    -# 
     # The new one is law [Number] 26.350
    -# 
     # http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
    -# 
     # So there is no summer time in Argentina for now.
     
     # From Mariano Absatz (2008-10-20):
    -# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
    -# From 2008-10-19 until 2009-03-15
    -# 
    +# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST
    +# in Argentina from 2008-10-19 until 2009-03-15.
     # http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
    -# 
     #
    -# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
    -# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
    -# and Tierra del Fuego
    -# 
    +
    +# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer
    +# 2008/2009: Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La
    +# Pampa, Neuquén, Rio Negro, Chubut, Santa Cruz and Tierra del Fuego
     # http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
    -# 
     #
    -# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
    -# it will not apply DST either (even when it was not included in Decree 1705/2008)
    -# 
    +# Press release 235 dated Saturday October 18th, from the Government of the
    +# Province of Jujuy saying it will not apply DST either (even when it was not
    +# included in Decree 1705/2008).
     # http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
    -# 
     
     # From fullinet (2009-10-18):
     # As announced in
    -# 
     # http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
    -# 
    -# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
    +# (an official .gob.ar) under title: "Sin Cambio de Hora"
    +# (English: "No hour change").
     #
    -# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
    -# oficial, decision que estaba en estudio para su implementacion el
    -# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
    -# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
    -# la modificacion del huso horario, ya que 2009 nos encuentra con
    -# crecimiento en la produccion y distribucion energetica."
    +# "Por el momento, el Gobierno Nacional resolvió no modificar la hora
    +# oficial, decisión que estaba en estudio para su implementación el
    +# domingo 18 de octubre. Desde el Ministerio de Planificación se anunció
    +# que la Argentina hoy, en estas condiciones meteorológicas, no necesita
    +# la modificación del huso horario, ya que 2009 nos encuentra con
    +# crecimiento en la producción y distribución energética."
     
     Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
     Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
    @@ -267,10 +251,10 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # It's Law No. 7,210.  This change is due to a public power emergency, so for
     # now we'll assume it's for this year only.
     #
    -# From Paul Eggert (2006-03-22):
    -# 
    -# Hora de verano para la Republica Argentina (2003-06-08)
    -#  says that standard time in Argentina from 1894-10-31
    +# From Paul Eggert (2014-08-09):
    +# Hora de verano para la República Argentina
    +# http://buenasiembra.com.ar/esoterismo/astrologia/hora-de-verano-de-la-republica-argentina-27.html
    +# says that standard time in Argentina from 1894-10-31
     # to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
     # over Shanks & Pottenger.
     #
    @@ -285,10 +269,10 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # time in October 17th.
     #
     # Catamarca, Chubut, La Rioja, San Juan, San Luis, Santa Cruz,
    -# Tierra del Fuego, Tucuman.
    +# Tierra del Fuego, Tucumán.
     #
     # From Mariano Absatz (2004-06-14):
    -# ... this weekend, the Province of Tucuman decided it'd go back to UTC-03:00
    +# ... this weekend, the Province of Tucumán decided it'd go back to UTC-03:00
     # yesterday midnight (that is, at 24:00 Saturday 12th), since the people's
     # annoyance with the change is much higher than the power savings obtained....
     #
    @@ -323,49 +307,38 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # Here are articles that Argentina Province San Luis is planning to end DST
     # as earlier as upcoming Monday January 21, 2008 or February 2008:
     #
    -# Provincia argentina retrasa reloj y marca diferencia con resto del pais
    +# Provincia argentina retrasa reloj y marca diferencia con resto del país
     # (Argentine Province delayed clock and mark difference with the rest of the
     # country)
    -# 
     # http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
    -# 
     #
     # Es inminente que en San Luis atrasen una hora los relojes
     # (It is imminent in San Luis clocks one hour delay)
    -# 
    -# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
    -# 
    -#
    -# 
    +# http://www.lagaceta.com.ar/nota/253414/Economia/Es-inminente-que-en-San-Luis-atrasen-una-hora-los-relojes.html
     # http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
    -# 
     
    -# From Jesper Norgaard Welen (2008-01-18):
    +# From Jesper Nørgaard Welen (2008-01-18):
     # The page of the San Luis provincial government
    -# 
     # http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
    -# 
     # confirms what Alex Krivenyshev has earlier sent to the tz
     # emailing list about that San Luis plans to return to standard
     # time much earlier than the rest of the country. It also
     # confirms that upon request the provinces San Juan and Mendoza
     # refused to follow San Luis in this change.
     #
    -# The change is supposed to take place Monday the 21.st at 0:00
    +# The change is supposed to take place Monday the 21st at 0:00
     # hours. As far as I understand it if this goes ahead, we need
     # a new timezone for San Luis (although there are also documented
     # independent changes in the southamerica file of San Luis in
     # 1990 and 1991 which has not been confirmed).
     
    -# From Jesper Norgaard Welen (2008-01-25):
    +# From Jesper Nørgaard Welen (2008-01-25):
     # Unfortunately the below page has become defunct, about the San Luis
     # time change. Perhaps because it now is part of a group of pages "Most
     # important pages of 2008."
     #
     # You can use
    -# 
     # http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
    -# 
     # instead it seems. Or use "Buscador" from the main page of the San Luis
     # government, and fill in "huso" and click OK, and you will get 3 pages
     # from which the first one is identical to the above.
    @@ -385,9 +358,9 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # back in 2004, when these provinces changed to UTC-4 for a few days, I
     # mailed them personally and never got an answer).
     
    -# From Paul Eggert (2008-06-30):
    -# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
    -# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
    +# From Paul Eggert (2014-08-12):
    +# Unless otherwise specified, data entries are from Shanks & Pottenger through
    +# 1992, from the IATA otherwise.  As noted below, Shanks & Pottenger say that
     # America/Cordoba split into 6 subregions during 1991/1992, one of which
     # was America/San_Luis, but we haven't verified this yet so for now we'll
     # keep America/Cordoba a single region rather than splitting it into the
    @@ -399,14 +372,9 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # to utc-04:00 until the second Saturday in October...
     #
     # The press release is at
    -# 
     # http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
    -# 
    -# (I couldn't find the decree, but
    -# 
    -# www.sanluis.gov.ar
    -# 
    -# is the official page for the Province Government).
    +# (I couldn't find the decree, but www.sanluis.gov.ar
    +# is the official page for the Province Government.)
     #
     # There's also a note in only one of the major national papers ...
     # http://www.lanacion.com.ar/nota.asp?nota_id=1107912
    @@ -423,9 +391,7 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # ...the Province of San Luis is a case in itself.
     #
     # The Law at
    -# 
     # is ambiguous because establishes a calendar from the 2nd Sunday in
     # October at 0:00 thru the 2nd Saturday in March at 24:00 and the
     # complement of that starting on the 2nd Sunday of March at 0:00 and
    @@ -454,19 +420,15 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # ...
     
     # From Alexander Krivenyshev (2010-04-09):
    -# According to news reports from El Diario de la Republica Province San
    +# According to news reports from El Diario de la República Province San
     # Luis, Argentina (standard time UTC-04) will keep Daylight Saving Time
    -# after April 11, 2010--will continue to have same time as rest of
    +# after April 11, 2010 - will continue to have same time as rest of
     # Argentina (UTC-3) (no DST).
     #
    -# Confirmaron la prórroga del huso horario de verano (Spanish)
    -# 
    +# Confirmaron la prórroga del huso horario de verano (Spanish)
     # http://www.eldiariodelarepublica.com/index.php?option=com_content&task=view&id=29383&Itemid=9
    -# 
     # or (some English translation):
    -# 
     # http://www.worldtimezone.com/dst_news/dst_news_argentina08.html
    -# 
     
     # From Mariano Absatz (2010-04-12):
     # yes...I can confirm this...and given that San Luis keeps calling
    @@ -478,7 +440,7 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # Perhaps San Luis operates on the legal fiction that it is at UTC-4
     # with perpetual summer time, but ordinary usage typically seems to
     # just say it's at UTC-3; 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
     # offsets, only tm_isdst and the time zone abbreviations.  One minor
    @@ -486,20 +448,20 @@ Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
     # setting for time stamps past 2038.
     
     # From Paul Eggert (2013-02-21):
    -# Milne says Cordoba time was -4:16:48.2.  Round to the nearest second.
    +# Milne says Córdoba time was -4:16:48.2.  Round to the nearest second.
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     #
     # Buenos Aires (BA), Capital Federal (CF),
    -Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
    -			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +Zone America/Argentina/Buenos_Aires -3:53:48 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
     			-4:00	-	ART	1930 Dec
     			-4:00	Arg	AR%sT	1969 Oct  5
     			-3:00	Arg	AR%sT	1999 Oct  3
     			-4:00	Arg	AR%sT	2000 Mar  3
     			-3:00	Arg	AR%sT
     #
    -# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
    +# Córdoba (CB), Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN),
     # Chaco (CC), Formosa (FM), Santiago del Estero (SE)
     #
     # Shanks & Pottenger also make the following claims, which we haven't verified:
    @@ -519,7 +481,7 @@ Zone America/Argentina/Cordoba -4:16:48 - LMT	1894 Oct 31
     			-4:00	Arg	AR%sT	2000 Mar  3
     			-3:00	Arg	AR%sT
     #
    -# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
    +# Salta (SA), La Pampa (LP), Neuquén (NQ), Rio Negro (RN)
     Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
     			-4:16:48 -	CMT	1920 May
     			-4:00	-	ART	1930 Dec
    @@ -531,7 +493,7 @@ Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
     			-3:00	Arg	AR%sT	2008 Oct 18
     			-3:00	-	ART
     #
    -# Tucuman (TM)
    +# Tucumán (TM)
     Zone America/Argentina/Tucuman -4:20:52 - LMT	1894 Oct 31
     			-4:16:48 -	CMT	1920 May
     			-4:00	-	ART	1930 Dec
    @@ -642,8 +604,8 @@ Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
     			-3:00	-	ART
     #
     # Santa Cruz (SC)
    -Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
    -			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
     			-4:00	-	ART	1930 Dec
     			-4:00	Arg	AR%sT	1969 Oct  5
     			-3:00	Arg	AR%sT	1999 Oct  3
    @@ -653,9 +615,9 @@ Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
     			-3:00	Arg	AR%sT	2008 Oct 18
     			-3:00	-	ART
     #
    -# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
    -Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
    -			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +# Tierra del Fuego, Antártida e Islas del Atlántico Sur (TF)
    +Zone America/Argentina/Ushuaia -4:33:12 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May    # Córdoba Mean Time
     			-4:00	-	ART	1930 Dec
     			-4:00	Arg	AR%sT	1969 Oct  5
     			-3:00	Arg	AR%sT	1999 Oct  3
    @@ -686,13 +648,13 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     
     # From IATA SSIM (1996-02):
     # _Only_ the following states in BR1 observe DST: Rio Grande do Sul (RS),
    -# Santa Catarina (SC), Parana (PR), Sao Paulo (SP), Rio de Janeiro (RJ),
    -# Espirito Santo (ES), Minas Gerais (MG), Bahia (BA), Goias (GO),
    +# Santa Catarina (SC), Paraná (PR), São Paulo (SP), Rio de Janeiro (RJ),
    +# Espírito Santo (ES), Minas Gerais (MG), Bahia (BA), Goiás (GO),
     # Distrito Federal (DF), Tocantins (TO), Sergipe [SE] and Alagoas [AL].
     # [The last three states are new to this issue of the IATA SSIM.]
     
     # From Gwillim Law (1996-10-07):
    -# Geography, history (Tocantins was part of Goias until 1989), and other
    +# Geography, history (Tocantins was part of Goiás until 1989), and other
     # sources of time zone information lead me to believe that AL, SE, and TO were
     # always in BR1, and so the only change was whether or not they observed DST....
     # The earliest issue of the SSIM I have is 2/91.  Each issue from then until
    @@ -706,16 +668,14 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     # However, some conclusions can be drawn from another IATA manual: the Airline
     # Coding Directory, which lists close to 400 airports in Brazil.  For each
     # airport it gives a time zone which is coded to the SSIM.  From that
    -# information, I'm led to conclude that the states of Amapa (AP), Ceara (CE),
    -# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
    -# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
    +# information, I'm led to conclude that the states of Amapá (AP), Ceará (CE),
    +# Maranhão (MA), Paraíba (PR), Pernambuco (PE), Piauí (PI), and Rio Grande do
    +# Norte (RN), and the eastern part of Pará (PA) are all in BR1 without DST.
     
     # From Marcos Tadeu (1998-09-27):
    -# 
    -# Brazilian official page
    -# 
    +# Brazilian official page 
     
    -# From Jesper Norgaard (2000-11-03):
    +# From Jesper Nørgaard (2000-11-03):
     # [For an official list of which regions in Brazil use which time zones, see:]
     # http://pcdsh01.on.br/Fusbr.htm
     # http://pcdsh01.on.br/Fusbrhv.htm
    @@ -748,13 +708,13 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     
     # From Paul Schulze (2008-06-24):
     # ...by law number 11.662 of April 24, 2008 (published in the "Diario
    -# Oficial da Uniao"...) in Brazil there are changes in the timezones,
    +# Oficial da União"...) in Brazil there are changes in the timezones,
     # effective today (00:00am at June 24, 2008) as follows:
     #
    -# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
    +# a) The timezone UTC+5 is extinguished, with all the Acre state and the
     # part of the Amazonas state that had this timezone now being put to the
     # timezone UTC+4
    -# b) The whole Para state now is put at timezone UTC+3, instead of just
    +# b) The whole Pará state now is put at timezone UTC+3, instead of just
     # part of it, as was before.
     #
     # This change follows a proposal of senator Tiao Viana of Acre state, that
    @@ -767,13 +727,11 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     
     # From Rodrigo Severo (2008-06-24):
     # Just correcting the URL:
    -# 
     # https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=do&secao=1&pagina=1&data=25/04/2008
    -# 
     #
     # As a result of the above Decree I believe the America/Rio_Branco
     # timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
    -# be created to represent the...west side of the Para State. I
    +# be created to represent the...west side of the Pará State. I
     # suggest this new timezone be called Santarem as the most
     # important/populated city in the affected area.
     #
    @@ -782,19 +740,16 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     
     # From Alex Krivenyshev (2008-06-24):
     # This is a quick reference page for New and Old Brazil Time Zones map.
    -# 
     # http://www.worldtimezone.com/brazil-time-new-old.php
    -# 
     #
    -# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
    -# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
    -# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
    +# - 4 time zones replaced by 3 time zones - eliminating time zone UTC-05
    +# (state Acre and the part of the Amazonas will be UTC/GMT-04) - western
    +# part of Par state is moving to one timezone UTC-03 (from UTC-04).
     
     # From Paul Eggert (2002-10-10):
     # The official decrees referenced below are mostly taken from
    -# 
    -# Decretos sobre o Horario de Verao no Brasil
    -# .
    +# Decretos sobre o Horário de Verão no Brasil.
    +# http://pcdsh01.on.br/DecHV.html
     
     # From Steffen Thorsen (2008-08-29):
     # As announced by the government and many newspapers in Brazil late
    @@ -806,25 +761,17 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     # It has not yet been posted to http://pcdsh01.on.br/DecHV.html
     #
     # An official page about it:
    -# 
     # http://www.mme.gov.br/site/news/detail.do?newsId=16722
    -# 
     # Note that this link does not always work directly, but must be accessed
     # by going to
    -# 
     # http://www.mme.gov.br/first
    -# 
     #
     # One example link that works directly:
    -# 
     # http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
     # (Portuguese)
    -# 
     #
     # We have a written a short article about it as well:
    -# 
     # http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
    -# 
     #
     # From Alexander Krivenyshev (2011-10-04):
     # State Bahia will return to Daylight savings time this year after 8 years off.
    @@ -832,17 +779,12 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     # television station in Salvador.
     
     # In Portuguese:
    -# 
     # http://g1.globo.com/bahia/noticia/2011/10/governador-jaques-wagner-confirma-horario-de-verao-na-bahia.html
    -#  and
    -# 
     # http://noticias.terra.com.br/brasil/noticias/0,,OI5390887-EI8139,00-Bahia+volta+a+ter+horario+de+verao+apos+oito+anos.html
    -# 
     
     # From Guilherme Bernardes Rodrigues (2011-10-07):
     # There is news in the media, however there is still no decree about it.
    -# I just send a e-mail to Zulmira Brandao at
    -# http://pcdsh01.on.br/ the
    +# I just send a e-mail to Zulmira Brandao at http://pcdsh01.on.br/ the
     # official agency about time in Brazil, and she confirmed that the old rule is
     # still in force.
     
    @@ -854,9 +796,7 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     #
     # DECRETO No- 7.584, DE 13 DE OUTUBRO DE 2011
     # Link :
    -# 
     # http://www.in.gov.br/visualiza/index.jsp?data=13/10/2011&jornal=1000&pagina=6&totalArquivos=6
    -# 
     
     # From Kelley Cook (2012-10-16):
     # The governor of state of Bahia in Brazil announced on Thursday that
    @@ -884,42 +824,42 @@ Zone	America/La_Paz	-4:32:36 -	LMT	1890
     # For now, assume western Amazonas will change as well.
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    -# Decree 20,466 (1931-10-01)
    -# Decree 21,896 (1932-01-10)
    +# Decree 20,466  (1931-10-01)
    +# Decree 21,896  (1932-01-10)
     Rule	Brazil	1931	only	-	Oct	 3	11:00	1:00	S
     Rule	Brazil	1932	1933	-	Apr	 1	 0:00	0	-
     Rule	Brazil	1932	only	-	Oct	 3	 0:00	1:00	S
    -# Decree 23,195 (1933-10-10)
    +# Decree 23,195  (1933-10-10)
     # revoked DST.
    -# Decree 27,496 (1949-11-24)
    -# Decree 27,998 (1950-04-13)
    +# Decree 27,496  (1949-11-24)
    +# Decree 27,998  (1950-04-13)
     Rule	Brazil	1949	1952	-	Dec	 1	 0:00	1:00	S
     Rule	Brazil	1950	only	-	Apr	16	 1:00	0	-
     Rule	Brazil	1951	1952	-	Apr	 1	 0:00	0	-
    -# Decree 32,308 (1953-02-24)
    +# Decree 32,308  (1953-02-24)
     Rule	Brazil	1953	only	-	Mar	 1	 0:00	0	-
    -# Decree 34,724 (1953-11-30)
    +# Decree 34,724  (1953-11-30)
     # revoked DST.
    -# Decree 52,700 (1963-10-18)
    +# Decree 52,700  (1963-10-18)
     # established DST from 1963-10-23 00:00 to 1964-02-29 00:00
     # in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
    -# Decree 53,071 (1963-12-03)
    +# Decree 53,071  (1963-12-03)
     # extended the above decree to all of the national territory on 12-09.
     Rule	Brazil	1963	only	-	Dec	 9	 0:00	1:00	S
    -# Decree 53,604 (1964-02-25)
    +# Decree 53,604  (1964-02-25)
     # extended summer time by one day to 1964-03-01 00:00 (start of school).
     Rule	Brazil	1964	only	-	Mar	 1	 0:00	0	-
    -# Decree 55,639 (1965-01-27)
    +# Decree 55,639  (1965-01-27)
     Rule	Brazil	1965	only	-	Jan	31	 0:00	1:00	S
     Rule	Brazil	1965	only	-	Mar	31	 0:00	0	-
    -# Decree 57,303 (1965-11-22)
    +# Decree 57,303  (1965-11-22)
     Rule	Brazil	1965	only	-	Dec	 1	 0:00	1:00	S
    -# Decree 57,843 (1966-02-18)
    +# Decree 57,843  (1966-02-18)
     Rule	Brazil	1966	1968	-	Mar	 1	 0:00	0	-
     Rule	Brazil	1966	1967	-	Nov	 1	 0:00	1:00	S
    -# Decree 63,429 (1968-10-15)
    +# Decree 63,429  (1968-10-15)
     # revoked DST.
    -# Decree 91,698 (1985-09-27)
    +# Decree 91,698  (1985-09-27)
     Rule	Brazil	1985	only	-	Nov	 2	 0:00	1:00	S
     # Decree 92,310 (1986-01-21)
     # Decree 92,463 (1986-03-13)
    @@ -927,42 +867,42 @@ Rule	Brazil	1986	only	-	Mar	15	 0:00	0	-
     # Decree 93,316 (1986-10-01)
     Rule	Brazil	1986	only	-	Oct	25	 0:00	1:00	S
     Rule	Brazil	1987	only	-	Feb	14	 0:00	0	-
    -# Decree 94,922 (1987-09-22)
    +# Decree 94,922  (1987-09-22)
     Rule	Brazil	1987	only	-	Oct	25	 0:00	1:00	S
     Rule	Brazil	1988	only	-	Feb	 7	 0:00	0	-
    -# Decree 96,676 (1988-09-12)
    +# Decree 96,676  (1988-09-12)
     # except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
     Rule	Brazil	1988	only	-	Oct	16	 0:00	1:00	S
     Rule	Brazil	1989	only	-	Jan	29	 0:00	0	-
    -# Decree 98,077 (1989-08-21)
    +# Decree 98,077  (1989-08-21)
     # with the same exceptions
     Rule	Brazil	1989	only	-	Oct	15	 0:00	1:00	S
     Rule	Brazil	1990	only	-	Feb	11	 0:00	0	-
    -# Decree 99,530 (1990-09-17)
    +# Decree 99,530  (1990-09-17)
     # adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
     # Decree 99,629 (1990-10-19) adds BA, MT.
     Rule	Brazil	1990	only	-	Oct	21	 0:00	1:00	S
     Rule	Brazil	1991	only	-	Feb	17	 0:00	0	-
    -# Unnumbered decree (1991-09-25)
    +# Unnumbered decree  (1991-09-25)
     # adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
     Rule	Brazil	1991	only	-	Oct	20	 0:00	1:00	S
     Rule	Brazil	1992	only	-	Feb	 9	 0:00	0	-
    -# Unnumbered decree (1992-10-16)
    +# Unnumbered decree  (1992-10-16)
     # adopted by same states.
     Rule	Brazil	1992	only	-	Oct	25	 0:00	1:00	S
     Rule	Brazil	1993	only	-	Jan	31	 0:00	0	-
    -# Decree 942 (1993-09-28)
    +# Decree 942  (1993-09-28)
     # adopted by same states, plus AM.
    -# Decree 1,252 (1994-09-22;
    +# Decree 1,252  (1994-09-22;
     # web page corrected 2004-01-07) adopted by same states, minus AM.
    -# Decree 1,636 (1995-09-14)
    +# Decree 1,636  (1995-09-14)
     # adopted by same states, plus MT and TO.
    -# Decree 1,674 (1995-10-13)
    +# Decree 1,674  (1995-10-13)
     # adds AL, SE.
     Rule	Brazil	1993	1995	-	Oct	Sun>=11	 0:00	1:00	S
     Rule	Brazil	1994	1995	-	Feb	Sun>=15	 0:00	0	-
     Rule	Brazil	1996	only	-	Feb	11	 0:00	0	-
    -# Decree 2,000 (1996-09-04)
    +# Decree 2,000  (1996-09-04)
     # adopted by same states, minus AL, SE.
     Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
     Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
    @@ -975,53 +915,51 @@ Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
     #
     # Decree 2,317 (1997-09-04), adopted by same states.
     Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
    -# Decree 2,495
    +# Decree 2,495 
     # (1998-02-10)
     Rule	Brazil	1998	only	-	Mar	 1	 0:00	0	-
    -# Decree 2,780 (1998-09-11)
    +# Decree 2,780  (1998-09-11)
     # adopted by the same states as before.
     Rule	Brazil	1998	only	-	Oct	11	 0:00	1:00	S
     Rule	Brazil	1999	only	-	Feb	21	 0:00	0	-
    -# Decree 3,150
    +# Decree 3,150 
     # (1999-08-23) adopted by same states.
    -# Decree 3,188 (1999-09-30)
    +# Decree 3,188  (1999-09-30)
     # adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
     Rule	Brazil	1999	only	-	Oct	 3	 0:00	1:00	S
     Rule	Brazil	2000	only	-	Feb	27	 0:00	0	-
    -# Decree 3,592 (2000-09-06)
    +# Decree 3,592  (2000-09-06)
     # adopted by the same states as before.
    -# Decree 3,630 (2000-10-13)
    +# Decree 3,630  (2000-10-13)
     # repeals DST in PE and RR, effective 2000-10-15 00:00.
    -# Decree 3,632 (2000-10-17)
    +# Decree 3,632  (2000-10-17)
     # repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
    -# Decree 3,916
    +# Decree 3,916 
     # (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
     Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
     Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
     # Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
    -# 4,399
    +# 4,399 
     Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
     # Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
    -# 4,844
    +# 4,844 
     Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
     # Decree 5,223 (2004-10-01) reestablishes DST in MT.
    -# 5,223
    +# 5,223 
     Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
    -# Decree 5,539 (2005-09-19),
    +# Decree 5,539  (2005-09-19),
     # adopted by the same states as before.
     Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
    -# Decree 5,920 (2006-10-03),
    +# Decree 5,920  (2006-10-03),
     # adopted by the same states as before.
     Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
     Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
    -# Decree 6,212 (2007-09-26),
    +# Decree 6,212  (2007-09-26),
     # adopted by the same states as before.
     Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
     # From Frederico A. C. Neves (2008-09-10):
     # According to this decree
    -# 
     # http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
    -# 
     # [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
     # 3rd Feb Sunday. There is an exception on the return date when this is
     # the Carnival Sunday then the return date will be the next Sunday...
    @@ -1056,29 +994,29 @@ Zone America/Noronha	-2:09:40 -	LMT	1914
     			-2:00	Brazil	FN%sT	2002 Oct  1
     			-2:00	-	FNT
     # Other Atlantic islands have no permanent settlement.
    -# These include Trindade and Martin Vaz (administratively part of ES),
    -# Atol das Rocas (RN), and Penedos de Sao Pedro e Sao Paulo (PE).
    +# These include Trindade and Martim Vaz (administratively part of ES),
    +# Rocas Atoll (RN), and the St Peter and St Paul Archipelago (PE).
     # Fernando de Noronha was a separate territory from 1942-09-02 to 1989-01-01;
     # it also included the Penedos.
     #
    -# Amapa (AP), east Para (PA)
    -# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
    -# The division between east and west Para is the river Xingu.
    +# Amapá (AP), east Pará (PA)
    +# East Pará includes Belém, Marabá, Serra Norte, and São Félix do Xingu.
    +# The division between east and west Pará is the river Xingu.
     # In the north a very small part from the river Javary (now Jari I guess,
    -# the border with Amapa) to the Amazon, then to the Xingu.
    +# the border with Amapá) to the Amazon, then to the Xingu.
     Zone America/Belem	-3:13:56 -	LMT	1914
     			-3:00	Brazil	BR%sT	1988 Sep 12
     			-3:00	-	BRT
     #
    -# west Para (PA)
    -# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
    +# west Pará (PA)
    +# West Pará includes Altamira, Óbidos, Prainha, Oriximiná, and Santarém.
     Zone America/Santarem	-3:38:48 -	LMT	1914
     			-4:00	Brazil	AM%sT	1988 Sep 12
    -			-4:00	-	AMT	2008 Jun 24 00:00
    +			-4:00	-	AMT	2008 Jun 24  0:00
     			-3:00	-	BRT
     #
    -# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
    -# Paraiba (PB)
    +# Maranhão (MA), Piauí (PI), Ceará (CE), Rio Grande do Norte (RN),
    +# Paraíba (PB)
     Zone America/Fortaleza	-2:34:00 -	LMT	1914
     			-3:00	Brazil	BR%sT	1990 Sep 17
     			-3:00	-	BRT	1999 Sep 30
    @@ -1125,11 +1063,11 @@ Zone America/Bahia	-2:34:04 -	LMT	1914
     			-3:00	Brazil	BR%sT	2012 Oct 21
     			-3:00	-	BRT
     #
    -# Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
    -# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
    +# Goiás (GO), Distrito Federal (DF), Minas Gerais (MG),
    +# Espírito Santo (ES), Rio de Janeiro (RJ), São Paulo (SP), Paraná (PR),
     # Santa Catarina (SC), Rio Grande do Sul (RS)
     Zone America/Sao_Paulo	-3:06:28 -	LMT	1914
    -			-3:00	Brazil	BR%sT	1963 Oct 23 00:00
    +			-3:00	Brazil	BR%sT	1963 Oct 23  0:00
     			-3:00	1:00	BRST	1964
     			-3:00	Brazil	BR%sT
     #
    @@ -1143,7 +1081,7 @@ Zone America/Cuiaba	-3:44:20 -	LMT	1914
     			-4:00	-	AMT	2004 Oct  1
     			-4:00	Brazil	AM%sT
     #
    -# Rondonia (RO)
    +# Rondônia (RO)
     Zone America/Porto_Velho -4:15:36 -	LMT	1914
     			-4:00	Brazil	AM%sT	1988 Sep 12
     			-4:00	-	AMT
    @@ -1155,7 +1093,7 @@ Zone America/Boa_Vista	-4:02:40 -	LMT	1914
     			-4:00	Brazil	AM%sT	2000 Oct 15
     			-4:00	-	AMT
     #
    -# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
    +# east Amazonas (AM): Boca do Acre, Jutaí, Manaus, Floriano Peixoto
     # The great circle line from Tabatinga to Porto Acre divides
     # east from west Amazonas.
     Zone America/Manaus	-4:00:04 -	LMT	1914
    @@ -1165,19 +1103,19 @@ Zone America/Manaus	-4:00:04 -	LMT	1914
     			-4:00	-	AMT
     #
     # west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
    -#	Eirunepe, Envira, Ipixuna
    +#	Eirunepé, Envira, Ipixuna
     Zone America/Eirunepe	-4:39:28 -	LMT	1914
     			-5:00	Brazil	AC%sT	1988 Sep 12
     			-5:00	-	ACT	1993 Sep 28
     			-5:00	Brazil	AC%sT	1994 Sep 22
    -			-5:00	-	ACT	2008 Jun 24 00:00
    +			-5:00	-	ACT	2008 Jun 24  0:00
     			-4:00	-	AMT	2013 Nov 10
     			-5:00	-	ACT
     #
     # Acre (AC)
     Zone America/Rio_Branco	-4:31:12 -	LMT	1914
     			-5:00	Brazil	AC%sT	1988 Sep 12
    -			-5:00	-	ACT	2008 Jun 24 00:00
    +			-5:00	-	ACT	2008 Jun 24  0:00
     			-4:00	-	AMT	2013 Nov 10
     			-5:00	-	ACT
     
    @@ -1198,66 +1136,54 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
     # From Oscar van Vlijmen (2006-10-08):
     # http://www.horaoficial.cl/cambio.htm
     
    -# From Jesper Norgaard Welen (2006-10-08):
    +# From Jesper Nørgaard Welen (2006-10-08):
     # I think that there are some obvious mistakes in the suggested link
     # from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
     # ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
     # (they should have been 1990-09-15 and 1990-09-16 respectively), but
     # anyhow it clears up some doubts too.
     
    -# From Paul Eggert (2006-12-27):
    -# The following data for Chile and America/Santiago are from
    +# From Paul Eggert (2014-08-12):
    +# The following data entries for Chile and America/Santiago are from
     #  (2006-09-20), transcribed by
    -# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
    +# Jesper Nørgaard Welen.  The data entries for Pacific/Easter are from Shanks
     # & Pottenger, except with DST transitions after 1932 cloned from
    -# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
    +# America/Santiago.  The pre-1980 Pacific/Easter data entries are dubious,
     # but we have no other source.
     
    -# From German Poo-Caaman~o (2008-03-03):
    +# From Germán Poo-Caamaño (2008-03-03):
     # Due to drought, Chile extends Daylight Time in three weeks.  This
     # is one-time change (Saturday 3/29 at 24:00 for America/Santiago
     # and Saturday 3/29 at 22:00 for Pacific/Easter)
     # The Supreme Decree is located at
    -# 
     # http://www.shoa.cl/servicios/supremo316.pdf
    -# 
     # and the instructions for 2008 are located in:
    -# 
     # http://www.horaoficial.cl/cambio.htm
    -# .
     
    -# From Jose Miguel Garrido (2008-03-05):
    +# From José Miguel Garrido (2008-03-05):
     # ...
     # You could see the announces of the change on
    -# 
     # http://www.shoa.cl/noticias/2008/04hora/hora.htm
    -# .
     
     # From Angel Chiang (2010-03-04):
     # Subject: DST in Chile exceptionally extended to 3 April due to earthquake
    -# 
     # http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
    -# 
     # (in Spanish, last paragraph).
     #
     # This is breaking news. There should be more information available later.
     
    -# From Arthur Daivd Olson (2010-03-06):
    +# From Arthur David Olson (2010-03-06):
     # Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
     
    -# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
    +# From Glenn Eychaner (2011-03-02):
     # It appears that the Chilean government has decided to postpone the
     # change from summer time to winter time again, by three weeks to April
     # 2nd:
    -# 
     # http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
    -# 
     #
     # This is not yet reflected in the official "cambio de hora" site, but
     # probably will be soon:
    -# 
     # http://www.horaoficial.cl/cambio.htm
    -# 
     
     # From Arthur David Olson (2011-03-02):
     # The emol.com article mentions a water shortage as the cause of the
    @@ -1265,9 +1191,7 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
     
     # From Glenn Eychaner (2011-03-28):
     # The article:
    -# 
     # http://diario.elmercurio.com/2011/03/28/_portada/_portada/noticias/7565897A-CA86-49E6-9E03-660B21A4883E.htm?id=3D{7565897A-CA86-49E6-9E03-660B21A4883E}
    -# 
     #
     # In English:
     # Chile's clocks will go back an hour this year on the 7th of May instead
    @@ -1298,7 +1222,7 @@ Zone America/Rio_Branco	-4:31:12 -	LMT	1914
     # start date is 2013-09-08 00:00....
     # http://www.gob.cl/informa/2013/02/15/gobierno-anuncia-fechas-de-cambio-de-hora-para-el-ano-2013.htm
     
    -# From Jose Miguel Garrido (2014-02-19):
    +# From José Miguel Garrido (2014-02-19):
     # Today appeared in the Diario Oficial a decree amending the time change
     # dates to 2014.
     # DST End: last Saturday of April 2014 (Sun 27 Apr 2014 03:00 UTC)
    @@ -1352,7 +1276,7 @@ Rule	Chile	2012	max	-	Sep	Sun>=2	4:00u	1:00	S
     # (1996-09) says 1998-03-08.  Ignore these.
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Santiago	-4:42:46 -	LMT	1890
    -			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
    +			-4:42:46 -	SMT	1910        # Santiago Mean Time
     			-5:00	-	CLT	1916 Jul  1 # Chile Time
     			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
     			-4:00	-	CLT	1919 Jul  1 # Chile Time
    @@ -1361,16 +1285,16 @@ Zone America/Santiago	-4:42:46 -	LMT	1890
     			-4:00	Chile	CL%sT
     Zone Pacific/Easter	-7:17:44 -	LMT	1890
     			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
    -			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
    +			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter Time
     			-6:00	Chile	EAS%sT
     #
    -# Sala y Gomez Island is like Pacific/Easter.
    -# Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
    -# San Felix, and Antarctic bases, are like America/Santiago.
    +# Salas y Gómez Island is uninhabited.
    +# Other Chilean locations, including Juan Fernández Is, Desventuradas Is,
    +# and Antarctic bases, are like America/Santiago.
     
     # Colombia
     
    -# Milne gives 4:56:16.4 for Bogota time in 1899; round to nearest.  He writes,
    +# Milne gives 4:56:16.4 for Bogotá time in 1899; round to nearest.  He writes,
     # "A variation of fifteen minutes in the public clocks of Bogota is not rare."
     
     # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    @@ -1378,37 +1302,37 @@ Rule	CO	1992	only	-	May	 3	0:00	1:00	S
     Rule	CO	1993	only	-	Apr	 4	0:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	America/Bogota	-4:56:16 -	LMT	1884 Mar 13
    -			-4:56:16 -	BMT	1914 Nov 23 # Bogota Mean Time
    +			-4:56:16 -	BMT	1914 Nov 23 # Bogotá Mean Time
     			-5:00	CO	CO%sT	# Colombia Time
     # Malpelo, Providencia, San Andres
     # no information; probably like America/Bogota
     
    -# Curacao
    +# Curaçao
     
    -# Milne gives 4:35:46.9 for Curacao mean time; round to nearest.
    +# Milne gives 4:35:46.9 for Curaçao mean time; round to nearest.
     #
     # From Paul Eggert (2006-03-22):
     # Shanks & Pottenger say that The Bottom and Philipsburg have been at
     # -4:00 since standard time was introduced on 1912-03-02; and that
     # Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
     # 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
    -# Saba Island has been like Curacao.
    +# Saba Island has been like Curaçao.
     # This all predates our 1970 cutoff, though.
     #
    -# By July 2007 Curacao and St Maarten are planned to become
    +# By July 2007 Curaçao and St Maarten are planned to become
     # associated states within the Netherlands, much like Aruba;
     # Bonaire, Saba and St Eustatius would become directly part of the
     # Netherlands as Kingdom Islands.  This won't affect their time zones
     # though, as far as we know.
     #
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	America/Curacao	-4:35:47 -	LMT	1912 Feb 12	# Willemstad
    +Zone	America/Curacao	-4:35:47 -	LMT	1912 Feb 12 # Willemstad
     			-4:30	-	ANT	1965 # Netherlands Antilles Time
     			-4:00	-	AST
     
     # From Arthur David Olson (2011-06-15):
     # use links for places with new iso3166 codes.
    -# The name "Lower Prince's Quarter" is both longer than fourteen charaters
    +# The name "Lower Prince's Quarter" is both longer than fourteen characters
     # and contains an apostrophe; use "Lower_Princes" below.
     
     Link	America/Curacao	America/Lower_Princes	# Sint Maarten
    @@ -1416,7 +1340,7 @@ Link	America/Curacao	America/Kralendijk	# Caribbean Netherlands
     
     # Ecuador
     #
    -# Milne says the Sentral and South American Telegraph Company used -5:24:15.
    +# Milne says the Central and South American Telegraph Company used -5:24:15.
     #
     # From Paul Eggert (2007-03-04):
     # Apparently Ecuador had a failed experiment with DST in 1992.
    @@ -1427,10 +1351,10 @@ Link	America/Curacao	America/Kralendijk	# Caribbean Netherlands
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Guayaquil	-5:19:20 -	LMT	1890
     			-5:14:00 -	QMT	1931 # Quito Mean Time
    -			-5:00	-	ECT	     # Ecuador Time
    +			-5:00	-	ECT	# Ecuador Time
     Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
     			-5:00	-	ECT	1986
    -			-6:00	-	GALT	     # Galapagos Time
    +			-6:00	-	GALT	# Galápagos Time
     
     # Falklands
     
    @@ -1439,7 +1363,7 @@ Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
     # the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
     
     # From Falkland Islands Government Office, London (2001-01-22)
    -# via Jesper Norgaard:
    +# via Jesper Nørgaard:
     # ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
     # April 2001 and advance one hour to summer time at 2 am on Sunday 2
     # September.  It is anticipated that the clocks will revert back at 2
    @@ -1488,9 +1412,7 @@ Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
     # daylight saving time.
     #
     # One source:
    -# 
     # http://www.falklandnews.com/public/story.cfm?get=5914&source=3
    -# 
     #
     # We have gotten this confirmed by a clerk of the legislative assembly:
     # Normally the clocks revert to Local Mean Time (UTC/GMT -4 hours) on the
    @@ -1531,10 +1453,10 @@ Rule	Falk	2001	2010	-	Apr	Sun>=15	2:00	0	-
     Rule	Falk	2001	2010	-	Sep	Sun>=1	2:00	1:00	S
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
    -			-3:51:24 -	SMT	1912 Mar 12  # Stanley Mean Time
    -			-4:00	Falk	FK%sT	1983 May     # Falkland Is Time
    +			-3:51:24 -	SMT	1912 Mar 12 # Stanley Mean Time
    +			-4:00	Falk	FK%sT	1983 May    # Falkland Is Time
     			-3:00	Falk	FK%sT	1985 Sep 15
    -			-4:00	Falk	FK%sT	2010 Sep 5 02:00
    +			-4:00	Falk	FK%sT	2010 Sep  5  2:00
     			-3:00	-	FKST
     
     # French Guiana
    @@ -1545,7 +1467,7 @@ Zone America/Cayenne	-3:29:20 -	LMT	1911 Jul
     
     # Guyana
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
    +Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar    # Georgetown
     			-3:45	-	GBGT	1966 May 26 # Br Guiana Time
     			-3:45	-	GYT	1975 Jul 31 # Guyana Time
     			-3:00	-	GYT	1991
    @@ -1555,8 +1477,8 @@ Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
     # Paraguay
     #
     # From Paul Eggert (2006-03-22):
    -# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
    -# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
    +# Shanks & Pottenger say that spring transitions are 01:00 -> 02:00,
    +# and autumn transitions are 00:00 -> 23:00.  Go with pre-1999
     # editions of Shanks, and with the IATA, who say transitions occur at 00:00.
     #
     # From Waldemar Villamayor-Venialbo (2013-09-20):
    @@ -1582,9 +1504,8 @@ Rule	Para	1996	only	-	Mar	 1	0:00	0	-
     # (10-01).
     #
     # Translated by Gwillim Law (2001-02-27) from
    -# 
    -# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
    -# :
    +# Noticias, a daily paper in Asunción, Paraguay (2000-10-01):
    +# http://www.diarionoticias.com.py/011000/nacional/naciona1.htm
     # Starting at 0:00 today, the clock will be set forward 60 minutes, in
     # fulfillment of Decree No. 7,273 of the Executive Power....  The time change
     # system has been operating for several years.  Formerly there was a separate
    @@ -1605,21 +1526,18 @@ Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
     Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
     Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
     #
    -# From Jesper Norgaard Welen (2005-01-02):
    +# From Jesper Nørgaard Welen (2005-01-02):
     # There are several sources that claim that Paraguay made
     # a timezone rule change in autumn 2004.
     # From Steffen Thorsen (2005-01-05):
     # Decree 1,867 (2004-03-05)
    -# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
    -# 
    +# From Carlos Raúl Perasso via Jesper Nørgaard Welen (2006-10-13)
    +# http://www.presidencia.gov.py/decretos/D1867.pdf
     Rule	Para	2004	2009	-	Oct	Sun>=15	0:00	1:00	S
     Rule	Para	2005	2009	-	Mar	Sun>=8	0:00	0	-
    -# From Carlos Raul Perasso (2010-02-18):
    -# By decree number 3958 issued yesterday (
    -# 
    +# From Carlos Raúl Perasso (2010-02-18):
    +# By decree number 3958 issued yesterday
     # http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
    -# 
    -# )
     # Paraguay changes its DST schedule, postponing the March rule to April and
     # modifying the October date. The decree reads:
     # ...
    @@ -1635,25 +1553,25 @@ Rule	Para	2010	2012	-	Apr	Sun>=8	0:00	0	-
     # Paraguay will end DST on 2013-03-24 00:00....
     # http://www.ande.gov.py/interna.php?id=1075
     #
    -# From Carlos Raul Perasso (2013-03-15):
    +# From Carlos Raúl Perasso (2013-03-15):
     # The change in Paraguay is now final.  Decree number 10780
     # http://www.presidencia.gov.py/uploads/pdf/presidencia-3b86ff4b691c79d4f5927ca964922ec74772ce857c02ca054a52a37b49afc7fb.pdf
    -# From Carlos Raul Perasso (2014-02-28):
    +# From Carlos Raúl Perasso (2014-02-28):
     # Decree 1264 can be found at:
     # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf
     Rule	Para	2013	max	-	Mar	Sun>=22	0:00	0	-
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Asuncion	-3:50:40 -	LMT	1890
    -			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
    -			-4:00	-	PYT	1972 Oct # Paraguay Time
    +			-3:50:40 -	AMT	1931 Oct 10 # Asunción Mean Time
    +			-4:00	-	PYT	1972 Oct    # Paraguay Time
     			-3:00	-	PYT	1974 Apr
     			-4:00	Para	PY%sT
     
     # Peru
     #
    -# 
    -# From Evelyn C. Leeper via Mark Brader (2003-10-26):
    +# From Evelyn C. Leeper via Mark Brader (2003-10-26)
    +# :
     # When we were in Peru in 1985-1986, they apparently switched over
     # sometime between December 29 and January 3 while we were on the Amazon.
     #
    @@ -1679,7 +1597,7 @@ Zone	America/Lima	-5:08:12 -	LMT	1890
     
     # South Georgia
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    -Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
    +Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890 # Grytviken
     			-2:00	-	GST	# South Georgia Time
     
     # South Sandwich Is
    @@ -1689,9 +1607,9 @@ Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Paramaribo	-3:40:40 -	LMT	1911
     			-3:40:52 -	PMT	1935     # Paramaribo Mean Time
    -			-3:40:36 -	PMT	1945 Oct # The capital moved?
    +			-3:40:36 -	PMT	1945 Oct    # The capital moved?
     			-3:30	-	NEGT	1975 Nov 20 # Dutch Guiana Time
    -			-3:30	-	SRT	1984 Oct # Suriname Time
    +			-3:30	-	SRT	1984 Oct    # Suriname Time
     			-3:00	-	SRT
     
     # Trinidad and Tobago
    @@ -1706,7 +1624,7 @@ Link America/Port_of_Spain America/Grenada
     Link America/Port_of_Spain America/Guadeloupe
     Link America/Port_of_Spain America/Marigot	# St Martin (French part)
     Link America/Port_of_Spain America/Montserrat
    -Link America/Port_of_Spain America/St_Barthelemy
    +Link America/Port_of_Spain America/St_Barthelemy # St Barthélemy
     Link America/Port_of_Spain America/St_Kitts	# St Kitts & Nevis
     Link America/Port_of_Spain America/St_Lucia
     Link America/Port_of_Spain America/St_Thomas	# Virgin Islands (US)
    @@ -1765,7 +1683,7 @@ Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
     Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
     Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
     # From Eduardo Cota (2004-09-20):
    -# The uruguayan government has decreed a change in the local time....
    +# The Uruguayan government has decreed a change in the local time....
     # http://www.presidencia.gub.uy/decretos/2004091502.htm
     Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
     # From Steffen Thorsen (2005-03-11):
    @@ -1779,14 +1697,14 @@ Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
     # 02:00 local time, official time in Uruguay will be at GMT -2.
     Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
     Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
    -# From Jesper Norgaard Welen (2006-09-06):
    +# From Jesper Nørgaard Welen (2006-09-06):
     # http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
     Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
     Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
    -			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
    -			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
    +			-3:44:44 -	MMT	1920 May  1 # Montevideo MT
    +			-3:30	Uruguay	UY%sT	1942 Dec 14 # Uruguay Time
     			-3:00	Uruguay	UY%sT
     
     # Venezuela
    @@ -1794,14 +1712,14 @@ Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
     # From John Stainforth (2007-11-28):
     # ... the change for Venezuela originally expected for 2007-12-31 has
     # been brought forward to 2007-12-09.  The official announcement was
    -# published today in the "Gaceta Oficial de la Republica Bolivariana
    -# de Venezuela, numero 38.819" (official document for all laws or
    +# published today in the "Gaceta Oficial de la República Bolivariana
    +# de Venezuela, número 38.819" (official document for all laws or
     # resolution publication)
     # http://www.globovision.com/news.php?nid=72208
     
     # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
     Zone	America/Caracas	-4:27:44 -	LMT	1890
     			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
    -			-4:30	-	VET	1965	     # Venezuela Time
    -			-4:00	-	VET	2007 Dec  9 03:00
    +			-4:30	-	VET	1965        # Venezuela Time
    +			-4:00	-	VET	2007 Dec  9  3:00
     			-4:30	-	VET
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/systemv b/jdk/test/sun/util/calendar/zi/tzdata/systemv
    index f909f9c76db..c7b9a888e88 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/systemv
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/systemv
    @@ -21,7 +21,6 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# 
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
    index 7cec627fd95..45351ca8486 100644
    --- a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
    @@ -21,39 +21,27 @@
     # or visit www.oracle.com if you need additional information or have any
     # questions.
     #
    -# TZ zone descriptions
    +# tz zone descriptions (deprecated version)
     #
     # This file is in the public domain, so clarified as of
     # 2009-05-17 by Arthur David Olson.
     #
    -# From Paul Eggert (2013-08-14):
    +# From Paul Eggert (2014-07-31):
    +# This file is intended as a backward-compatibility aid for older programs.
    +# New programs should use zone1970.tab.  This file is like zone1970.tab (see
    +# zone1970.tab's comments), but with the following additional restrictions:
     #
    -# This file contains a table where each row stands for an area that is
    -# the intersection of a region identified by a country code and of a
    -# zone where civil clocks have agreed since 1970.  The columns of the
    -# table are as follows:
    +# 1.  This file contains only ASCII characters.
    +# 2.  The first data column contains exactly one country code.
     #
    -# 1.  ISO 3166 2-character country code.  See the file 'iso3166.tab'.
    -# 2.  Latitude and longitude of the area's principal location
    -#     in ISO 6709 sign-degrees-minutes-seconds format,
    -#     either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS,
    -#     first latitude (+ is north), then longitude (+ is east).
    -# 3.  Zone name used in value of TZ environment variable.
    -#     Please see the 'Theory' file for how zone names are chosen.
    -#     If multiple zones overlap a country, each has a row in the
    -#     table, with column 1 being duplicated.
    -# 4.  Comments; present if and only if the country has multiple rows.
    -#
    -# Columns are separated by a single tab.
    -# The table is sorted first by country, then an order within the country that
    -# (1) makes some geographical sense, and
    -# (2) puts the most populous areas first, where that does not contradict (1).
    -#
    -# Lines beginning with '#' are comments.
    +# Because of (2), each row stands for an area that is the intersection
    +# of a region identified by a country code and of a zone where civil
    +# clocks have agreed since 1970; this is a narrower definition than
    +# that of zone1970.tab.
     #
     # This table is intended as an aid for users, to help them select time
    -# zone data appropriate for their practical needs.  It is not intended
    -# to take or endorse any position on legal or territorial claims.
    +# zone data entries appropriate for their practical needs.  It is not
    +# intended to take or endorse any position on legal or territorial claims.
     #
     #country-
     #code	coordinates	TZ			comments
    @@ -72,7 +60,7 @@ AQ	-6736+06253	Antarctica/Mawson	Mawson Station, Holme Bay
     AQ	-6835+07758	Antarctica/Davis	Davis Station, Vestfold Hills
     AQ	-6617+11031	Antarctica/Casey	Casey Station, Bailey Peninsula
     AQ	-7824+10654	Antarctica/Vostok	Vostok Station, Lake Vostok
    -AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Terre Adelie
    +AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Adelie Land
     AQ	-690022+0393524	Antarctica/Syowa	Syowa Station, E Ongul I
     AQ	-720041+0023206	Antarctica/Troll	Troll Station, Queen Maud Land
     AR	-3436-05827	America/Argentina/Buenos_Aires	Buenos Aires (BA, CF)
    @@ -151,7 +139,7 @@ CA	+4901-08816	America/Nipigon	Eastern Time - Ontario & Quebec - places that did
     CA	+4823-08915	America/Thunder_Bay	Eastern Time - Thunder Bay, Ontario
     CA	+6344-06828	America/Iqaluit	Eastern Time - east Nunavut - most locations
     CA	+6608-06544	America/Pangnirtung	Eastern Time - Pangnirtung, Nunavut
    -CA	+744144-0944945	America/Resolute	Central Standard Time - Resolute, Nunavut
    +CA	+744144-0944945	America/Resolute	Central Time - Resolute, Nunavut
     CA	+484531-0913718	America/Atikokan	Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut
     CA	+624900-0920459	America/Rankin_Inlet	Central Time - central Nunavut
     CA	+4953-09709	America/Winnipeg	Central Time - Manitoba & west Ontario
    @@ -176,13 +164,10 @@ CH	+4723+00832	Europe/Zurich
     CI	+0519-00402	Africa/Abidjan
     CK	-2114-15946	Pacific/Rarotonga
     CL	-3327-07040	America/Santiago	most locations
    -CL	-2709-10926	Pacific/Easter	Easter Island & Sala y Gomez
    +CL	-2709-10926	Pacific/Easter	Easter Island
     CM	+0403+00942	Africa/Douala
    -CN	+3114+12128	Asia/Shanghai	east China - Beijing, Guangdong, Shanghai, etc.
    -CN	+4545+12641	Asia/Harbin	Heilongjiang (except Mohe), Jilin
    -CN	+2934+10635	Asia/Chongqing	central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc.
    -CN	+4348+08735	Asia/Urumqi	most of Tibet & Xinjiang
    -CN	+3929+07559	Asia/Kashgar	west Tibet & Xinjiang
    +CN	+3114+12128	Asia/Shanghai	Beijing Time
    +CN	+4348+08735	Asia/Urumqi	Xinjiang Time
     CO	+0436-07405	America/Bogota
     CR	+0956-08405	America/Costa_Rica
     CU	+2308-08222	America/Havana
    @@ -364,24 +349,26 @@ RE	-2052+05528	Indian/Reunion
     RO	+4426+02606	Europe/Bucharest
     RS	+4450+02030	Europe/Belgrade
     RU	+5443+02030	Europe/Kaliningrad	Moscow-01 - Kaliningrad
    -RU	+5545+03735	Europe/Moscow	Moscow+00 - west Russia
    -RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
    -RU	+5312+05009	Europe/Samara	Moscow+00 - Samara, Udmurtia
    +RU	+554521+0373704	Europe/Moscow	Moscow+00 - west Russia
     RU	+4457+03406	Europe/Simferopol	Moscow+00 - Crimea
    +RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
    +RU	+5312+05009	Europe/Samara	Moscow+00 (Moscow+01 after 2014-10-26) - Samara, Udmurtia
     RU	+5651+06036	Asia/Yekaterinburg	Moscow+02 - Urals
     RU	+5500+07324	Asia/Omsk	Moscow+03 - west Siberia
     RU	+5502+08255	Asia/Novosibirsk	Moscow+03 - Novosibirsk
    -RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 - Novokuznetsk
    +RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 (Moscow+04 after 2014-10-26) - Kemerovo
     RU	+5601+09250	Asia/Krasnoyarsk	Moscow+04 - Yenisei River
     RU	+5216+10420	Asia/Irkutsk	Moscow+05 - Lake Baikal
    +RU	+5203+11328	Asia/Chita	Moscow+06 (Moscow+05 after 2014-10-26) - Zabaykalsky
     RU	+6200+12940	Asia/Yakutsk	Moscow+06 - Lena River
     RU	+623923+1353314	Asia/Khandyga	Moscow+06 - Tomponsky, Ust-Maysky
     RU	+4310+13156	Asia/Vladivostok	Moscow+07 - Amur River
     RU	+4658+14242	Asia/Sakhalin	Moscow+07 - Sakhalin Island
     RU	+643337+1431336	Asia/Ust-Nera	Moscow+07 - Oymyakonsky
    -RU	+5934+15048	Asia/Magadan	Moscow+08 - Magadan
    -RU	+5301+15839	Asia/Kamchatka	Moscow+08 - Kamchatka
    -RU	+6445+17729	Asia/Anadyr	Moscow+08 - Bering Sea
    +RU	+5934+15048	Asia/Magadan	Moscow+08 (Moscow+07 after 2014-10-26) - Magadan
    +RU	+6728+15343	Asia/Srednekolymsk	Moscow+08 - E Sakha, N Kuril Is
    +RU	+5301+15839	Asia/Kamchatka	Moscow+08 (Moscow+09 after 2014-10-26) - Kamchatka
    +RU	+6445+17729	Asia/Anadyr	Moscow+08 (Moscow+09 after 2014-10-26) - Bering Sea
     RW	-0157+03004	Africa/Kigali
     SA	+2438+04643	Asia/Riyadh
     SB	-0932+16012	Pacific/Guadalcanal
    @@ -448,13 +435,13 @@ US	+394421-1045903	America/Denver	Mountain Time
     US	+433649-1161209	America/Boise	Mountain Time - south Idaho & east Oregon
     US	+332654-1120424	America/Phoenix	Mountain Standard Time - Arizona (except Navajo)
     US	+340308-1181434	America/Los_Angeles	Pacific Time
    +US	+550737-1313435	America/Metlakatla	Pacific Standard Time - Annette Island, Alaska
     US	+611305-1495401	America/Anchorage	Alaska Time
     US	+581807-1342511	America/Juneau	Alaska Time - Alaska panhandle
     US	+571035-1351807	America/Sitka	Alaska Time - southeast Alaska panhandle
     US	+593249-1394338	America/Yakutat	Alaska Time - Alaska panhandle neck
     US	+643004-1652423	America/Nome	Alaska Time - west Alaska
     US	+515248-1763929	America/Adak	Aleutian Islands
    -US	+550737-1313435	America/Metlakatla	Metlakatla Time - Annette Island
     US	+211825-1575130	Pacific/Honolulu	Hawaii
     UY	-3453-05611	America/Montevideo
     UZ	+3940+06648	Asia/Samarkand	west Uzbekistan
    diff --git a/jdk/test/sun/util/resources/TimeZone/Bug6317929.java b/jdk/test/sun/util/resources/TimeZone/Bug6317929.java
    index 4b047c5e4e1..1c59896f2a9 100644
    --- a/jdk/test/sun/util/resources/TimeZone/Bug6317929.java
    +++ b/jdk/test/sun/util/resources/TimeZone/Bug6317929.java
    @@ -122,11 +122,11 @@ public class Bug6317929 {
             TimeZone Currie = TimeZone.getTimeZone("Australia/Currie");
             tzLocale = locales2Test[0];
             if (!Currie.getDisplayName(false, TimeZone.LONG, tzLocale).equals
    -           ("Eastern Standard Time (New South Wales)"))
    +           ("Australian Eastern Standard Time (New South Wales)"))
                 throw new RuntimeException("\n" + tzLocale + ": LONG, " +
                                            "non-daylight saving name for " +
                                            "Australia/Currie should be " +
    -                                       "\"Eastern Standard Time " +
    +                                       "\"Australian Eastern Standard Time " +
                                            "(New South Wales)\"");
             tzLocale = locales2Test[1];
             if (!Currie.getDisplayName(false, TimeZone.LONG, tzLocale).equals
    diff --git a/make/Main.gmk b/make/Main.gmk
    index c3c05be8393..230fec4140e 100644
    --- a/make/Main.gmk
    +++ b/make/Main.gmk
    @@ -487,17 +487,8 @@ ALL_TARGETS += default all
     # Clean targets
     #
     ################################################################################
    -
    -# If running a clean target, disable parallel execution
    -ifneq ($(findstring clean, $(MAKECMDGOALS)), )
    -  .NOTPARALLEL:
    -  # It's not recommended to run additional targets to clean on the same make
    -  # command line. Try to detect this and issue a warning.
    -  ifneq ($(filter-out clean%, $(MAKECMDGOALS)), )
    -    $(warning Mixing clean targets with normal build targets will not work well \
    -        and is not recommended.)
    -  endif
    -endif
    +# Clean targets are automatically run serially by the Makefile calling this 
    +# file.
     
     CLEAN_COMPONENTS += langtools corba hotspot jdk nashorn images \
         bootcycle-build docs docstemp test
    @@ -543,6 +534,9 @@ ifeq ($(findstring reconfigure, $(MAKECMDGOALS)), )
     	@if test "x$(IGNORE_OLD_CONFIG)" != "xtrue"; then exit 1; fi
     endif
     
    +# The reconfigure target is automatically run serially from everything else
    +# by the Makefile calling this file.
    +
     reconfigure:
             ifneq ($(CONFIGURE_COMMAND_LINE), )
     	  @$(ECHO) "Re-running configure using arguments '$(CONFIGURE_COMMAND_LINE)'"
    diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
    index 16f5418fa2c..b23cd83d8b0 100644
    --- a/make/common/MakeBase.gmk
    +++ b/make/common/MakeBase.gmk
    @@ -349,7 +349,7 @@ define SetupLogging
         # (and causing a crash on Cygwin).
         # Default shell seems to always be /bin/sh. Must override with bash to get this to work on Solaris.
         # Only use time if it's GNU time which supports format and output file.
    -    WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log /bin/bash
    +    WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log $$(BASH)
         SHELL=$$(warning $$(if $$@,Building $$@,Running shell command) $$(if $$<, (from $$<))$$(if $$?, ($$(wordlist 1, 20, $$?) $$(if $$(wordlist 21, 22, $$?), ... [in total $$(words $$?) files]) newer)))$$(WRAPPER_SHELL)
       endif
       # Never remove warning messages; this is just for completeness
    diff --git a/make/jprt.properties b/make/jprt.properties
    index c81bbf0cb7f..0b5cea8b81b 100644
    --- a/make/jprt.properties
    +++ b/make/jprt.properties
    @@ -165,6 +165,7 @@ my.make.rule.test.targets.core=						\
         ${my.test.target.set:TESTNAME=jdk_security1},			\
         ${my.test.target.set:TESTNAME=jdk_security2},			\
         ${my.test.target.set:TESTNAME=jdk_security3},			\
    +    ${my.test.target.set:TESTNAME=jdk_security4},			\
         ${my.test.target.set:TESTNAME=jdk_rmi},				\
         ${my.test.target.set:TESTNAME=jdk_text},				\
         ${my.test.target.set:TESTNAME=jdk_time},				\
    diff --git a/modules.xml b/modules.xml
    index 5a84ea92825..c961ec5628e 100644
    --- a/modules.xml
    +++ b/modules.xml
    @@ -1033,6 +1033,12 @@
         
           org.w3c.dom.ls
         
    +    
    +      org.w3c.dom.ranges
    +    
    +    
    +      org.w3c.dom.traversal
    +    
         
           org.w3c.dom.views
         
    @@ -1568,6 +1574,12 @@
         java.base
         jdk.crypto.ec
       
    +  
    +    jdk.deploy.osx
    +    java.base
    +    java.desktop
    +    java.scripting
    +  
       
         jdk.dev
         java.base
    diff --git a/nashorn/.hgignore b/nashorn/.hgignore
    index 6cfabad507b..02ec40d7e8d 100644
    --- a/nashorn/.hgignore
    +++ b/nashorn/.hgignore
    @@ -6,8 +6,7 @@ dist/*
     /nbproject/private/
     private.xml
     private.properties
    -webrev/*
    -webrev.zip
    +^webrev
     .classpath
     *.class
     *.clazz
    diff --git a/nashorn/.hgtags b/nashorn/.hgtags
    index 050ed3d919d..fc829400c18 100644
    --- a/nashorn/.hgtags
    +++ b/nashorn/.hgtags
    @@ -263,3 +263,4 @@ ed60a4e9dd35dcabb9b24e90434f5f615d988981 jdk9-b26
     221a84ef44c00335b563d92f470efaf8162b471e jdk9-b27
     00c31e5eaf26f9b238165157b9d1c617b03abcb6 jdk9-b28
     e541ebaf2ab7038333ad0c13f4decd327c26dd15 jdk9-b29
    +072dbed6c5d968a6b9e156c36cd8838b4ff86ea1 jdk9-b30
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
    index 697675a3de9..fa2b8a198bd 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
    @@ -194,12 +194,12 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
          */
         private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
             // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
    -        //
             body.accept(new NodeVisitor(new LexicalContext()) {
                 @Override
    -            public boolean enterFunctionNode(final FunctionNode nestedFn) {
    -                // Don't descend into nested functions
    -                return false;
    +            protected boolean enterDefault(final Node node) {
    +                // Don't bother visiting expressions; var is a statement, it can't be inside an expression.
    +                // This will also prevent visiting nested functions (as FunctionNode is an expression).
    +                return !(node instanceof Expression);
                 }
     
                 @Override
    @@ -443,12 +443,27 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
     
             if (lc.isFunctionBody()) {
                 block.clearSymbols();
    +            final FunctionNode fn = lc.getCurrentFunction();
    +            if (isUnparsedFunction(fn)) {
    +                // It's a skipped nested function. Just mark the symbols being used by it as being in use.
    +                for(final String name: compiler.getScriptFunctionData(fn.getId()).getExternalSymbolNames()) {
    +                    nameIsUsed(name, null);
    +                }
    +                // Don't bother descending into it, it must be empty anyway.
    +                assert block.getStatements().isEmpty();
    +                return false;
    +            }
    +
                 enterFunctionBody();
             }
     
             return true;
         }
     
    +    private boolean isUnparsedFunction(final FunctionNode fn) {
    +        return compiler.isOnDemandCompilation() && fn != lc.getOutermostFunction();
    +    }
    +
         @Override
         public boolean enterCatchNode(final CatchNode catchNode) {
             final IdentNode exception = catchNode.getException();
    @@ -492,18 +507,13 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
     
         @Override
         public boolean enterFunctionNode(final FunctionNode functionNode) {
    -        // TODO: once we have information on symbols used by nested functions, we can stop descending into nested
    -        // functions with on-demand compilation, e.g. add
    -        // if(!thisProperties.isEmpty() && env.isOnDemandCompilation()) {
    -        //    return false;
    -        // }
             start(functionNode, false);
     
             thisProperties.push(new HashSet());
     
    -        //an outermost function in our lexical context that is not a program
    -        //is possible - it is a function being compiled lazily
             if (functionNode.isDeclared()) {
    +            // Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
    +            // is not a program - it is a function being compiled on-demand.
                 final Iterator blocks = lc.getBlocks();
                 if (blocks.hasNext()) {
                     final IdentNode ident = functionNode.getIdent();
    @@ -511,6 +521,11 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
                 }
             }
     
    +        // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
    +        // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
    +        // are used in them.
    +        assert functionNode.getBody() != null;
    +
             return true;
         }
     
    @@ -533,7 +548,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
     
         /**
          * This has to run before fix assignment types, store any type specializations for
    -     * paramters, then turn then to objects for the generic version of this method
    +     * parameters, then turn them into objects for the generic version of this method.
          *
          * @param functionNode functionNode
          */
    @@ -733,14 +748,20 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
     
         @Override
         public Node leaveBlock(final Block block) {
    -        // It's not necessary to guard the marking of symbols as locals with this "if"condition for correctness, it's
    -        // just an optimization -- runtime type calculation is not used when the compilation is not an on-demand
    -        // optimistic compilation, so we can skip locals marking then.
    +        // It's not necessary to guard the marking of symbols as locals with this "if" condition for
    +        // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
    +        // is not an on-demand optimistic compilation, so we can skip locals marking then.
             if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
    -            for (final Symbol symbol: block.getSymbols()) {
    -                if (!symbol.isScope()) {
    -                    assert symbol.isVar() || symbol.isParam();
    -                    compiler.declareLocalSymbol(symbol.getName());
    +            // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
    +            // compilation, and we're skipping parsing the function bodies for nested functions, this
    +            // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
    +            // symbol in the outer function named the same as one of the parameters, though.
    +            if (lc.getFunction(block) == lc.getOutermostFunction()) {
    +                for (final Symbol symbol: block.getSymbols()) {
    +                    if (!symbol.isScope()) {
    +                        assert symbol.isVar() || symbol.isParam();
    +                        compiler.declareLocalSymbol(symbol.getName());
    +                    }
                     }
                 }
             }
    @@ -811,24 +832,45 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
     
         @Override
         public Node leaveFunctionNode(final FunctionNode functionNode) {
    -
    -        return markProgramBlock(
    +        final FunctionNode finalizedFunction;
    +        if (isUnparsedFunction(functionNode)) {
    +            finalizedFunction = functionNode;
    +        } else {
    +            finalizedFunction =
    +               markProgramBlock(
                    removeUnusedSlots(
                    createSyntheticInitializers(
                    finalizeParameters(
                            lc.applyTopFlags(functionNode))))
    -                       .setThisProperties(lc, thisProperties.pop().size())
    -                       .setState(lc, CompilationState.SYMBOLS_ASSIGNED));
    +                       .setThisProperties(lc, thisProperties.pop().size()));
    +        }
    +        return finalizedFunction.setState(lc, CompilationState.SYMBOLS_ASSIGNED);
         }
     
         @Override
         public Node leaveIdentNode(final IdentNode identNode) {
    -        final String name = identNode.getName();
    -
             if (identNode.isPropertyName()) {
                 return identNode;
             }
     
    +        final Symbol symbol = nameIsUsed(identNode.getName(), identNode);
    +
    +        if (!identNode.isInitializedHere()) {
    +            symbol.increaseUseCount();
    +        }
    +
    +        IdentNode newIdentNode = identNode.setSymbol(symbol);
    +
    +        // If a block-scoped var is used before its declaration mark it as dead.
    +        // We can only statically detect this for local vars, cross-function symbols require runtime checks.
    +        if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
    +            newIdentNode = newIdentNode.markDead();
    +        }
    +
    +        return end(newIdentNode);
    +    }
    +
    +    private Symbol nameIsUsed(final String name, final IdentNode origin) {
             final Block block = lc.getCurrentBlock();
     
             Symbol symbol = findSymbol(block, name);
    @@ -847,24 +889,11 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
                 maybeForceScope(symbol);
             } else {
                 log.info("No symbol exists. Declare as global: ", name);
    -            symbol = defineSymbol(block, name, identNode, IS_GLOBAL | IS_SCOPE);
    +            symbol = defineSymbol(block, name, origin, IS_GLOBAL | IS_SCOPE);
             }
     
             functionUsesSymbol(symbol);
    -
    -        if (!identNode.isInitializedHere()) {
    -            symbol.increaseUseCount();
    -        }
    -
    -        IdentNode newIdentNode = identNode.setSymbol(symbol);
    -
    -        // If a block-scoped var is used before its declaration mark it as dead.
    -        // We can only statically detect this for local vars, cross-function symbols require runtime checks.
    -        if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
    -            newIdentNode = newIdentNode.markDead();
    -        }
    -
    -        return end(newIdentNode);
    +        return symbol;
         }
     
         @Override
    @@ -912,7 +941,6 @@ final class AssignSymbols extends NodeVisitor implements Loggabl
                 return functionNode;
             }
     
    -        assert functionNode.getId() == 1;
             return functionNode.setBody(lc, functionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
         }
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java
    index 386effdc120..9f7fe79d2b0 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java
    @@ -59,6 +59,7 @@ import java.security.PrivilegedAction;
     import java.util.EnumSet;
     import java.util.HashSet;
     import java.util.Set;
    +
     import jdk.internal.org.objectweb.asm.ClassWriter;
     import jdk.internal.org.objectweb.asm.MethodVisitor;
     import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
    @@ -135,6 +136,16 @@ public class ClassEmitter implements Emitter {
         /** Set of constants access methods required. */
         private Set> constantMethodNeeded;
     
    +    private int methodCount;
    +
    +    private int initCount;
    +
    +    private int clinitCount;
    +
    +    private int fieldCount;
    +
    +    private final Set methodNames;
    +
         /**
          * Constructor - only used internally in this class as it breaks
          * abstraction towards ASM or other code generator below
    @@ -146,6 +157,11 @@ public class ClassEmitter implements Emitter {
             this.context        = context;
             this.cw             = cw;
             this.methodsStarted = new HashSet<>();
    +        this.methodNames    = new HashSet<>();
    +    }
    +
    +    public Set getMethodNames() {
    +        return methodNames;
         }
     
         /**
    @@ -208,6 +224,38 @@ public class ClassEmitter implements Emitter {
             return unitClassName;
         }
     
    +    /**
    +     * Get the method count, including init and clinit methods
    +     * @return method count
    +     */
    +    public int getMethodCount() {
    +        return methodCount;
    +    }
    +
    +    /**
    +     * Get the clinit count
    +     * @return clinit count
    +     */
    +    public int getClinitCount() {
    +        return clinitCount;
    +    }
    +
    +    /**
    +     * Get the init count
    +     * @return init count
    +     */
    +    public int getInitCount() {
    +        return initCount;
    +    }
    +
    +    /**
    +     * Get the field count
    +     * @return field count
    +     */
    +    public int getFieldCount() {
    +        return fieldCount;
    +    }
    +
         /**
          * Convert a binary name to a package/class name.
          *
    @@ -359,9 +407,16 @@ public class ClassEmitter implements Emitter {
          */
         @Override
         public void end() {
    -        assert classStarted;
    +        assert classStarted : "class not started for " + unitClassName;
     
             if (unitClassName != null) {
    +            final MethodEmitter initMethod = init(EnumSet.of(Flag.PRIVATE));
    +            initMethod.begin();
    +            initMethod.load(Type.OBJECT, 0);
    +            initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
    +            initMethod.returnVoid();
    +            initMethod.end();
    +
                 defineCommonUtilities();
             }
     
    @@ -419,6 +474,8 @@ public class ClassEmitter implements Emitter {
         }
     
         SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class rtype, final Class... ptypes) {
    +        methodCount++;
    +        methodNames.add(methodName);
             return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
         }
     
    @@ -446,6 +503,8 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving this method
          */
         MethodEmitter method(final EnumSet methodFlags, final String methodName, final Class rtype, final Class... ptypes) {
    +        methodCount++;
    +        methodNames.add(methodName);
             return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes));
         }
     
    @@ -471,6 +530,8 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving this method
          */
         MethodEmitter method(final EnumSet methodFlags, final String methodName, final String descriptor) {
    +        methodCount++;
    +        methodNames.add(methodName);
             return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null));
         }
     
    @@ -481,6 +542,8 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving this method
          */
         MethodEmitter method(final FunctionNode functionNode) {
    +        methodCount++;
    +        methodNames.add(functionNode.getName());
             final FunctionSignature signature = new FunctionSignature(functionNode);
             final MethodVisitor mv = cw.visitMethod(
                 ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0),
    @@ -499,6 +562,8 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving this method
          */
         MethodEmitter restOfMethod(final FunctionNode functionNode) {
    +        methodCount++;
    +        methodNames.add(functionNode.getName());
             final MethodVisitor mv = cw.visitMethod(
                 ACC_PUBLIC | ACC_STATIC,
                 functionNode.getName(),
    @@ -516,6 +581,7 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving 
          */
         MethodEmitter clinit() {
    +        clinitCount++;
             return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class);
         }
     
    @@ -525,6 +591,7 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving ()V
          */
         MethodEmitter init() {
    +        initCount++;
             return method(INIT.symbolName(), void.class);
         }
     
    @@ -535,6 +602,7 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving ()V
          */
         MethodEmitter init(final Class... ptypes) {
    +        initCount++;
             return method(INIT.symbolName(), void.class, ptypes);
         }
     
    @@ -547,6 +615,7 @@ public class ClassEmitter implements Emitter {
          * @return method emitter to use for weaving (...)V
          */
         MethodEmitter init(final EnumSet flags, final Class... ptypes) {
    +        initCount++;
             return method(flags, INIT.symbolName(), void.class, ptypes);
         }
     
    @@ -561,6 +630,7 @@ public class ClassEmitter implements Emitter {
          * @see ClassEmitter.Flag
          */
         final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType, final Object value) {
    +        fieldCount++;
             cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd();
         }
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
    index cfdb64bd1db..97b26212a46 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
    @@ -1622,9 +1622,18 @@ final class CodeGenerator extends NodeOperatorVisitor ", newUnit);
                     map.put(oldUnit, newUnit);
    @@ -430,8 +434,14 @@ enum CompilationPhase {
     
                 FunctionNode newFunctionNode = fn;
     
    +            //root class is special, as it is bootstrapped from createProgramFunction, thus it's skipped
    +            //in CodeGeneration - the rest can be used as a working "is compile unit used" metric
    +            fn.getCompileUnit().setUsed();
    +
                 compiler.getLogger().fine("Starting bytecode generation for ", quote(fn.getName()), " - restOf=", phases.isRestOfCompilation());
    +
                 final CodeGenerator codegen = new CodeGenerator(compiler, phases.isRestOfCompilation() ? compiler.getContinuationEntryPoints() : null);
    +
                 try {
                     // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
                     // in the lazy + optimistic world. See CodeGenerator.skipFunction().
    @@ -455,12 +465,18 @@ enum CompilationPhase {
                     final ClassEmitter classEmitter = compileUnit.getClassEmitter();
                     classEmitter.end();
     
    +                if (!compileUnit.isUsed()) {
    +                    compiler.getLogger().fine("Skipping unused compile unit ", compileUnit);
    +                    continue;
    +                }
    +
                     final byte[] bytecode = classEmitter.toByteArray();
                     assert bytecode != null;
     
                     final String className = compileUnit.getUnitClassName();
    +                compiler.addClass(className, bytecode); //classes are only added to the bytecode map if compile unit is used
     
    -                compiler.addClass(className, bytecode);
    +                CompileUnit.increaseEmitCount();
     
                     // should we verify the generated code?
                     if (senv._verify_code) {
    @@ -536,6 +552,9 @@ enum CompilationPhase {
     
                 // initialize function in the compile units
                 for (final CompileUnit unit : compiler.getCompileUnits()) {
    +                if (!unit.isUsed()) {
    +                    continue;
    +                }
                     unit.setCode(installedClasses.get(unit.getUnitClassName()));
                 }
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java
    index 2859bf463b4..d45a58f1c0b 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java
    @@ -42,6 +42,10 @@ public final class CompileUnit implements Comparable {
     
         private Class clazz;
     
    +    private boolean isUsed;
    +
    +    private static int emittedUnitCount;
    +
         CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
             this.className    = className;
             this.weight       = initialWeight;
    @@ -52,6 +56,33 @@ public final class CompileUnit implements Comparable {
             return new TreeSet<>();
         }
     
    +    static void increaseEmitCount() {
    +        emittedUnitCount++;
    +    }
    +
    +    public static int getEmittedUnitCount() {
    +        return emittedUnitCount;
    +    }
    +
    +    /**
    +     * Check if this compile unit is used
    +     * @return true if tagged as in use - i.e active code that needs to be generated
    +     */
    +    public boolean isUsed() {
    +        return isUsed;
    +    }
    +
    +    public boolean hasCode() {
    +        return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
    +    }
    +
    +    /**
    +     * Tag this compile unit as used
    +     */
    +    public void setUsed() {
    +        this.isUsed = true;
    +    }
    +
         /**
          * Return the class that contains the code for this unit, null if not
          * generated yet
    @@ -121,7 +152,8 @@ public final class CompileUnit implements Comparable {
     
         @Override
         public String toString() {
    -        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
    +        final String methods = classEmitter != null ? classEmitter.getMethodNames().toString() : "";
    +        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + " hasCode=" + methods + ']';
         }
     
         @Override
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java
    index bb59eb5fb72..0a1de709ffd 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java
    @@ -38,7 +38,6 @@ import java.lang.invoke.MethodType;
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.Comparator;
    -import java.util.EnumSet;
     import java.util.HashMap;
     import java.util.Iterator;
     import java.util.LinkedHashMap;
    @@ -51,8 +50,8 @@ import java.util.concurrent.atomic.AtomicInteger;
     import java.util.function.Consumer;
     import java.util.logging.Level;
     import jdk.internal.dynalink.support.NameCodec;
    -import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
     import jdk.nashorn.internal.codegen.types.Type;
    +import jdk.nashorn.internal.ir.Expression;
     import jdk.nashorn.internal.ir.FunctionNode;
     import jdk.nashorn.internal.ir.Optimistic;
     import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
    @@ -65,6 +64,7 @@ import jdk.nashorn.internal.runtime.ParserException;
     import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
     import jdk.nashorn.internal.runtime.ScriptEnvironment;
     import jdk.nashorn.internal.runtime.ScriptObject;
    +import jdk.nashorn.internal.runtime.ScriptRuntime;
     import jdk.nashorn.internal.runtime.Source;
     import jdk.nashorn.internal.runtime.logging.DebugLogger;
     import jdk.nashorn.internal.runtime.logging.Loggable;
    @@ -248,6 +248,15 @@ public final class Compiler implements Loggable {
                 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
             }
     
    +        @SuppressWarnings("unused") //TODO I'll use this soon
    +        private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
    +            final LinkedList list = new LinkedList<>();
    +            for (final CompilationPhase p : phases) {
    +                list.add(p == phase ? newPhase : p);
    +            }
    +            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
    +        }
    +
             private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
                 final LinkedList list = new LinkedList<>();
                 for (final CompilationPhase p : phases) {
    @@ -473,6 +482,19 @@ public final class Compiler implements Loggable {
             return typeEvaluator.getOptimisticType(node);
         }
     
    +    /**
    +     * Returns true if the expression can be safely evaluated, and its value is an object known to always use
    +     * String as the type of its property names retrieved through
    +     * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its
    +     * property name types.
    +     * @param expr the expression to test
    +     * @return true if the expression can be safely evaluated, and its value is an object known to always use
    +     * String as the type of its property iterators.
    +     */
    +    boolean hasStringPropertyIterator(final Expression expr) {
    +        return typeEvaluator.hasStringPropertyIterator(expr);
    +    }
    +
         void addInvalidatedProgramPoint(final int programPoint, final Type type) {
             invalidatedProgramPoints.put(programPoint, type);
         }
    @@ -675,16 +697,8 @@ public final class Compiler implements Loggable {
         CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) {
             final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict());
             final CompileUnit  compileUnit  = new CompileUnit(unitClassName, classEmitter, initialWeight);
    -
             classEmitter.begin();
     
    -        final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE));
    -        initMethod.begin();
    -        initMethod.load(Type.OBJECT, 0);
    -        initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
    -        initMethod.returnVoid();
    -        initMethod.end();
    -
             return compileUnit;
         }
     
    @@ -722,13 +736,6 @@ public final class Compiler implements Loggable {
             return name.replace('/', '.');
         }
     
    -    RecompilableScriptFunctionData getProgram() {
    -        if (compiledFunction == null) {
    -            return null;
    -        }
    -        return compiledFunction.getProgram();
    -    }
    -
         RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
             return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
         }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java
    index 0f8ea77fec6..4c1db02ba93 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java
    @@ -25,8 +25,6 @@
     
     package jdk.nashorn.internal.codegen;
     
    -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getClassName;
    -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
     import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
     
     import java.util.HashMap;
    @@ -34,6 +32,7 @@ import java.util.HashSet;
     import java.util.Iterator;
     import java.util.Map;
     import java.util.Set;
    +import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
     import jdk.nashorn.internal.ir.Block;
     import jdk.nashorn.internal.ir.FunctionNode;
     import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    @@ -44,7 +43,6 @@ import jdk.nashorn.internal.ir.Symbol;
     import jdk.nashorn.internal.ir.WithNode;
     import jdk.nashorn.internal.ir.visitor.NodeVisitor;
     import jdk.nashorn.internal.runtime.Context;
    -import jdk.nashorn.internal.runtime.PropertyMap;
     import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
     import jdk.nashorn.internal.runtime.logging.DebugLogger;
     import jdk.nashorn.internal.runtime.logging.Loggable;
    @@ -208,14 +206,10 @@ final class FindScopeDepths extends NodeVisitor implements Logga
     
             assert nestedFunctions != null;
             // Generate the object class and property map in case this function is ever used as constructor
    -        final int         fieldCount         = getPaddedFieldCount(newFunctionNode.getThisProperties());
    -        final String      allocatorClassName = Compiler.binaryName(getClassName(fieldCount));
    -        final PropertyMap allocatorMap       = PropertyMap.newMap(null, allocatorClassName, 0, fieldCount, 0);
             final RecompilableScriptFunctionData data = new RecompilableScriptFunctionData(
                     newFunctionNode,
                     compiler.getCodeInstaller(),
    -                allocatorClassName,
    -                allocatorMap,
    +                new AllocatorDescriptor(newFunctionNode.getThisProperties()),
                     nestedFunctions,
                     externalSymbolDepths.get(fnId),
                     internalSymbols.get(fnId)
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
    index 130bd66f906..995b29a6157 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
    @@ -551,13 +551,19 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
     
             final Expression init = forNode.getInit();
             if(forNode.isForIn()) {
    -            forNode.getModify().accept(this);
    -            enterTestFirstLoop(forNode, null, init);
    +            final JoinPredecessorExpression iterable = forNode.getModify();
    +            iterable.accept(this);
    +            enterTestFirstLoop(forNode, null, init,
    +                    // If we're iterating over property names, and we can discern from the runtime environment
    +                    // of the compilation that the object being iterated over must use strings for property
    +                    // names (e.g., it is a native JS object or array), then we'll not bother trying to treat
    +                    // the property names optimistically.
    +                    !forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression()));
             } else {
                 if(init != null) {
                     init.accept(this);
                 }
    -            enterTestFirstLoop(forNode, forNode.getModify(), null);
    +            enterTestFirstLoop(forNode, forNode.getModify(), null, false);
             }
             return false;
         }
    @@ -792,7 +798,8 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
             return false;
         }
     
    -    private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, final Expression iteratorValues) {
    +    private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
    +            final Expression iteratorValues, final boolean iteratorValuesAreObject) {
             final JoinPredecessorExpression test = loopNode.getTest();
             if(isAlwaysFalse(test)) {
                 test.accept(this);
    @@ -814,8 +821,12 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
                     jumpToLabel(test, breakLabel);
                 }
                 if(iteratorValues instanceof IdentNode) {
    -                // Receives iterator values; they're currently all objects (JDK-8034954).
    -                onAssignment((IdentNode)iteratorValues, LvarType.OBJECT);
    +                final IdentNode ident = (IdentNode)iteratorValues;
    +                // Receives iterator values; the optimistic type of the iterator values is tracked on the
    +                // identifier, but we override optimism if it's known that the object being iterated over will
    +                // never have primitive property names.
    +                onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT :
    +                    toLvarType(compiler.getOptimisticType(ident)));
                 }
                 final Block body = loopNode.getBody();
                 body.accept(this);
    @@ -955,7 +966,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
             if(whileNode.isDoWhile()) {
                 enterDoWhileLoop(whileNode);
             } else {
    -            enterTestFirstLoop(whileNode, null, null);
    +            enterTestFirstLoop(whileNode, null, null, false);
             }
             return false;
         }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
    index 9f713e04dde..2c87f3b9a97 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
    @@ -71,7 +71,6 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
     import jdk.nashorn.internal.ir.visitor.NodeVisitor;
     import jdk.nashorn.internal.parser.Token;
     import jdk.nashorn.internal.parser.TokenType;
    -import jdk.nashorn.internal.runtime.CodeInstaller;
     import jdk.nashorn.internal.runtime.Context;
     import jdk.nashorn.internal.runtime.JSType;
     import jdk.nashorn.internal.runtime.Source;
    @@ -93,9 +92,6 @@ final class Lower extends NodeOperatorVisitor implements Lo
     
         private final DebugLogger log;
     
    -    // needed only to get unique eval id
    -    private final CodeInstaller installer;
    -
         /**
          * Constructor.
          */
    @@ -143,7 +139,6 @@ final class Lower extends NodeOperatorVisitor implements Lo
                 }
             });
     
    -        this.installer = compiler.getCodeInstaller();
             this.log       = initLogger(compiler.getContext());
         }
     
    @@ -566,16 +561,13 @@ final class Lower extends NodeOperatorVisitor implements Lo
         private String evalLocation(final IdentNode node) {
             final Source source = lc.getCurrentFunction().getSource();
             final int pos = node.position();
    -        // Code installer is null when running with --compile-only, use 0 as id in that case
    -        final long id = installer == null ? 0 : installer.getUniqueEvalId();
             return new StringBuilder().
                 append(source.getName()).
                 append('#').
                 append(source.getLine(pos)).
                 append(':').
                 append(source.getColumn(pos)).
    -            append("@").
    -            append(id).
    +            append("").
                 toString();
         }
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
    index 815ce271bf6..a5a5cf6f31e 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
    @@ -308,7 +308,7 @@ public final class ObjectClassGenerator implements Loggable {
             newEmptyInit(className, classEmitter);
             newAllocate(className, classEmitter);
     
    -        return toByteArray(classEmitter);
    +        return toByteArray(className, classEmitter);
         }
     
         /**
    @@ -341,7 +341,7 @@ public final class ObjectClassGenerator implements Loggable {
             initWithArguments.returnVoid();
             initWithArguments.end();
     
    -        return toByteArray(classEmitter);
    +        return toByteArray(className, classEmitter);
         }
     
         /**
    @@ -484,15 +484,13 @@ public final class ObjectClassGenerator implements Loggable {
          * @param classEmitter Open class emitter.
          * @return Byte codes for the class.
          */
    -    private byte[] toByteArray(final ClassEmitter classEmitter) {
    +    private byte[] toByteArray(final String className, final ClassEmitter classEmitter) {
             classEmitter.end();
     
             final byte[] code = classEmitter.toByteArray();
             final ScriptEnvironment env = context.getEnv();
     
    -        if (env._print_code && env._print_code_dir == null) {
    -            env.getErr().println(ClassEmitter.disassemble(code));
    -        }
    +        DumpBytecode.dumpBytecode(env, log, code, className);
     
             if (env._verify_code) {
                 context.verify(code);
    @@ -827,5 +825,45 @@ public final class ObjectClassGenerator implements Loggable {
             return MH.findStatic(MethodHandles.lookup(), ObjectClassGenerator.class, name, MH.type(rtype, types));
         }
     
    +    /**
    +     * Describes the allocator class name and property map for a constructor function with the specified
    +     * number of "this" properties that it initializes.
    +     *
    +     */
    +    public static class AllocatorDescriptor {
    +        private final String allocatorClassName;
    +        private final PropertyMap allocatorMap;
     
    +        /**
    +         * Creates a new allocator descriptor
    +         * @param thisProperties the number of "this" properties that the function initializes
    +         */
    +        public AllocatorDescriptor(final int thisProperties) {
    +            final int paddedFieldCount = getPaddedFieldCount(thisProperties);
    +            this.allocatorClassName = Compiler.binaryName(getClassName(paddedFieldCount));
    +            this.allocatorMap = PropertyMap.newMap(null, allocatorClassName, 0, paddedFieldCount, 0);
    +        }
    +
    +        /**
    +         * Returns the name of the class that the function allocates
    +         * @return the name of the class that the function allocates
    +         */
    +        public String getAllocatorClassName() {
    +            return allocatorClassName;
    +        }
    +
    +        /**
    +         * Returns the allocator map for the function.
    +         * @return the allocator map for the function.
    +         */
    +        public PropertyMap getAllocatorMap() {
    +            return allocatorMap;
    +        }
    +
    +        @Override
    +        public String toString() {
    +            return "AllocatorDescriptor[allocatorClassName=" + allocatorClassName + ", allocatorMap.size=" +
    +                    allocatorMap.size() + "]";
    +        }
    +    }
     }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java
    index ea58d0a9d17..11a23ecd3a1 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java
    @@ -55,6 +55,19 @@ final class TypeEvaluator {
             this.runtimeScope = runtimeScope;
         }
     
    +    /**
    +     * Returns true if the expression can be safely evaluated, and its value is an object known to always use
    +     * String as the type of its property names retrieved through
    +     * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its
    +     * property name types.
    +     * @param expr the expression to test
    +     * @return true if the expression can be safely evaluated, and its value is an object known to always use
    +     * String as the type of its property iterators.
    +     */
    +    boolean hasStringPropertyIterator(final Expression expr) {
    +        return evaluateSafely(expr) instanceof ScriptObject;
    +    }
    +
         Type getOptimisticType(final Optimistic node) {
             assert compiler.useOptimisticTypes();
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
    index c157626547c..86a84ca6de8 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
    @@ -276,6 +276,14 @@ public class Block extends Node implements BreakableNode, Terminal, Flags
             return Collections.unmodifiableList(statements);
         }
     
    +    /**
    +     * Returns the number of statements in the block.
    +     * @return the number of statements in the block.
    +     */
    +    public int getStatementCount() {
    +        return statements.size();
    +    }
    +
         /**
          * Returns the line number of the first statement in the block.
          * @return the line number of the first statement in the block, or -1 if the block has no statements.
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CompileUnitHolder.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CompileUnitHolder.java
    new file mode 100644
    index 00000000000..27d69d53f67
    --- /dev/null
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CompileUnitHolder.java
    @@ -0,0 +1,40 @@
    +/*
    + * Copyright (c) 2010, 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.  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.nashorn.internal.ir;
    +
    +import jdk.nashorn.internal.codegen.CompileUnit;
    +
    +/**
    + * Marker interface for things in the IR that can hold compile units.
    + * {@link CompileUnit}
    + */
    +public interface CompileUnitHolder {
    +    /**
    +     * Return the compile unit held by this instance
    +     * @return compile unit
    +     */
    +    public CompileUnit getCompileUnit();
    +}
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
    index 4dd1bc3b943..b911f22272b 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
    @@ -34,10 +34,8 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
     
     import java.util.Collections;
     import java.util.EnumSet;
    -import java.util.HashSet;
     import java.util.Iterator;
     import java.util.List;
    -import java.util.Set;
     import java.util.function.Function;
     import jdk.nashorn.internal.AssertsEnabled;
     import jdk.nashorn.internal.codegen.CompileUnit;
    @@ -48,6 +46,7 @@ import jdk.nashorn.internal.codegen.types.Type;
     import jdk.nashorn.internal.ir.annotations.Ignore;
     import jdk.nashorn.internal.ir.annotations.Immutable;
     import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    +import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
     import jdk.nashorn.internal.runtime.ScriptFunction;
     import jdk.nashorn.internal.runtime.Source;
     import jdk.nashorn.internal.runtime.UserAccessorProperty;
    @@ -57,7 +56,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
      * IR representation for function (or script.)
      */
     @Immutable
    -public final class FunctionNode extends LexicalContextExpression implements Flags {
    +public final class FunctionNode extends LexicalContextExpression implements Flags, CompileUnitHolder {
         /** Type used for all FunctionNodes */
         public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
     
    @@ -110,8 +109,11 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
         /** Source of entity. */
         private final Source source;
     
    -    /** Unique ID used for recompilation among other things */
    -    private final int id;
    +    /**
    +     * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
    +     * to skip parsing inner functions.
    +     */
    +    private final Object endParserState;
     
         /** External function identifier. */
         @Ignore
    @@ -256,6 +258,14 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
         /** trace callsite values in this function? */
         public static final int IS_TRACE_VALUES    = 1 << 26;
     
    +    /**
    +     * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
    +     * parameter on invocation. Note that we aren't, in fact using this flag in function nodes.
    +     * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
    +     * will, however, cache the value of this flag.
    +     */
    +    public static final int NEEDS_CALLEE       = 1 << 27;
    +
         /** extension callsite flags mask */
         public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
             IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
    @@ -271,16 +281,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
         /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
         private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
     
    -    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval.
    -     *  We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
    +    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval. */
         private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
     
    -    /** Used to signify "null", e.g. if someone asks for the parent of the program node */
    -    public static final int NO_FUNCTION_ID = 0;
    -
    -    /** Where to start assigning global and unique function node ids */
    -    public static final int FIRST_FUNCTION_ID = NO_FUNCTION_ID + 1;
    -
         /** What is the return type of this function? */
         private Type returnType = Type.UNKNOWN;
     
    @@ -288,11 +291,10 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
          * Constructor
          *
          * @param source     the source
    -     * @param id         unique id
          * @param lineNumber line number
          * @param token      token
          * @param finish     finish
    -     * @param firstToken first token of the funtion node (including the function declaration)
    +     * @param firstToken first token of the function node (including the function declaration)
          * @param namespace  the namespace
          * @param ident      the identifier
          * @param name       the name of the function
    @@ -302,7 +304,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
          */
         public FunctionNode(
             final Source source,
    -        final int id,
             final int lineNumber,
             final long token,
             final int finish,
    @@ -316,7 +317,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
             super(token, finish);
     
             this.source           = source;
    -        this.id               = id;
             this.lineNumber       = lineNumber;
             this.ident            = ident;
             this.name             = name;
    @@ -331,11 +331,13 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
             this.body             = null;
             this.thisProperties   = 0;
             this.rootClass        = null;
    +        this.endParserState    = null;
         }
     
         private FunctionNode(
             final FunctionNode functionNode,
             final long lastToken,
    +        Object endParserState,
             final int flags,
             final String name,
             final Type returnType,
    @@ -347,6 +349,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
             final Class rootClass) {
             super(functionNode);
     
    +        this.endParserState    = endParserState;
             this.lineNumber       = functionNode.lineNumber;
             this.flags            = flags;
             this.name             = name;
    @@ -361,7 +364,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
     
             // the fields below never change - they are final and assigned in constructor
             this.source          = functionNode.source;
    -        this.id              = functionNode.id;
             this.ident           = functionNode.ident;
             this.namespace       = functionNode.namespace;
             this.kind            = functionNode.kind;
    @@ -429,11 +431,11 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
         }
     
         /**
    -     * Get the unique ID for this function
    +     * Get the unique ID for this function within the script file.
          * @return the id
          */
         public int getId() {
    -        return id;
    +        return position();
         }
     
         /**
    @@ -535,6 +537,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -606,6 +609,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -644,14 +648,23 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
         }
     
         /**
    -     * Check if the {@code eval} keyword is used in this function
    +     * Check if this function has a call expression for the identifier "eval" (that is, {@code eval(...)}).
          *
    -     * @return true if {@code eval} is used
    +     * @return true if {@code eval} is called.
          */
         public boolean hasEval() {
             return getFlag(HAS_EVAL);
         }
     
    +    /**
    +     * Returns true if a function nested (directly or transitively) within this function {@link #hasEval()}.
    +     *
    +     * @return true if a nested function calls {@code eval}.
    +     */
    +    public boolean hasNestedEval() {
    +        return getFlag(HAS_NESTED_EVAL);
    +    }
    +
         /**
          * Get the first token for this function
          * @return the first token
    @@ -741,6 +754,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags |
                                 (body.needsScope() ?
                                         FunctionNode.HAS_SCOPE_BLOCK :
    @@ -839,6 +853,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -899,6 +914,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -910,6 +926,41 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                             rootClass));
         }
     
    +    /**
    +     * Returns the end parser state for this function.
    +     * @return the end parser state for this function.
    +     */
    +    public Object getEndParserState() {
    +        return endParserState;
    +    }
    +
    +    /**
    +     * Set the end parser state for this function.
    +     * @param lc lexical context
    +     * @param endParserState the parser state to set
    +     * @return function node or a new one if state was changed
    +     */
    +    public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
    +        if (this.endParserState == endParserState) {
    +            return this;
    +        }
    +        return Node.replaceInLexicalContext(
    +                lc,
    +                this,
    +                new FunctionNode(
    +                        this,
    +                        lastToken,
    +                        endParserState,
    +                        flags,
    +                        name,
    +                        returnType,
    +                        compileUnit,
    +                        compilationState,
    +                        body,
    +                        parameters,
    +                        thisProperties, rootClass));
    +    }
    +
         /**
          * Get the name of this function
          * @return the name
    @@ -934,6 +985,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -999,6 +1051,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -1077,6 +1130,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                 new FunctionNode(
                     this,
                     lastToken,
    +                endParserState,
                     flags,
                     name,
                     type,
    @@ -1102,6 +1156,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
          * @see Compiler
          * @return the compile unit
          */
    +    @Override
         public CompileUnit getCompileUnit() {
             return compileUnit;
         }
    @@ -1123,6 +1178,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    @@ -1178,6 +1234,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
                     new FunctionNode(
                             this,
                             lastToken,
    +                        endParserState,
                             flags,
                             name,
                             returnType,
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
    index ef56ae117ed..8048ea3117b 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
    @@ -351,8 +351,7 @@ public class LexicalContext {
         }
     
         /**
    -     * Get the function for this block. If the block is itself a function
    -     * this returns identity
    +     * Get the function for this block.
          * @param block block for which to get function
          * @return function for block
          */
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java
    index 8ff4f9fd723..c6ede9467f1 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java
    @@ -603,7 +603,7 @@ public abstract class LiteralNode extends Expression implements PropertyKey {
              * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
              * be split if they are too large, for bytecode generation reasons
              */
    -        public static final class ArrayUnit {
    +        public static final class ArrayUnit implements CompileUnitHolder {
                 /** Compile unit associated with the postsets range. */
                 private final CompileUnit compileUnit;
     
    @@ -642,6 +642,7 @@ public abstract class LiteralNode extends Expression implements PropertyKey {
                  * The array compile unit
                  * @return array compile unit
                  */
    +            @Override
                 public CompileUnit getCompileUnit() {
                     return compileUnit;
                 }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java
    index ba2409e83c8..e7dd9ed205f 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java
    @@ -39,7 +39,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
      * Node indicating code is split across classes.
      */
     @Immutable
    -public class SplitNode extends LexicalContextStatement implements Labels {
    +public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder {
         /** Split node method name. */
         private final String name;
     
    @@ -116,6 +116,7 @@ public class SplitNode extends LexicalContextStatement implements Labels {
          * Get the compile unit for this split node
          * @return compile unit
          */
    +    @Override
         public CompileUnit getCompileUnit() {
             return compileUnit;
         }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
    index 1fe7cdb0f46..03a2c9ae700 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
    @@ -630,6 +630,24 @@ public final class Global extends ScriptObject implements Scope {
             throw new IllegalArgumentException("Unsupported primitive: " + self);
         }
     
    +    /**
    +     * Returns a method handle that creates a wrapper object for a JS primitive value.
    +     *
    +     * @param self receiver object
    +     * @return method handle to create wrapper objects for primitive receiver
    +     */
    +    public static MethodHandle getPrimitiveWrapFilter(final Object self) {
    +        if (self instanceof String || self instanceof ConsString) {
    +            return NativeString.WRAPFILTER;
    +        } else if (self instanceof Number) {
    +            return NativeNumber.WRAPFILTER;
    +        } else if (self instanceof Boolean) {
    +            return NativeBoolean.WRAPFILTER;
    +        }
    +        throw new IllegalArgumentException("Unsupported primitive: " + self);
    +    }
    +
    +
         /**
          * Create a new empty script object
          *
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java
    index a6581b5ba81..7bce42bdaa0 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java
    @@ -51,9 +51,9 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
     public final class NativeBoolean extends ScriptObject {
         private final boolean value;
     
    -    // Method handle to create an object wrapper for a primitive boolean
    -    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
    -    // Method handle to retrieve the Boolean prototype object
    +    /** Method handle to create an object wrapper for a primitive boolean. */
    +    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
    +    /** Method handle to retrieve the Boolean prototype object. */
         private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
     
         // initialized by nasgen
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
    index 134ff8d122d..ab544697159 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
    @@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects;
     import static jdk.nashorn.internal.lookup.Lookup.MH;
     import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    +import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
     
     import java.lang.invoke.MethodHandle;
     import java.lang.invoke.MethodHandles;
    @@ -697,7 +698,7 @@ public final class NativeJSAdapter extends ScriptObject {
                     if (methodHandle != null) {
                         return new GuardedInvocation(
                                 methodHandle,
    -                            testJSAdaptor(adaptee, findData.getGetter(Object.class, UnwarrantedOptimismException.INVALID_PROGRAM_POINT), findData.getOwner(), func),
    +                            testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
                                 adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
                     }
                  }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java
    index b4cff41e699..7ea27835729 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java
    @@ -57,9 +57,9 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
     @ScriptClass("Number")
     public final class NativeNumber extends ScriptObject {
     
    -    // Method handle to create an object wrapper for a primitive number
    -    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
    -    // Method handle to retrieve the Number prototype object
    +    /** Method handle to create an object wrapper for a primitive number. */
    +    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
    +    /** Method handle to retrieve the Number prototype object. */
         private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
     
         /** ECMA 15.7.3.2 largest positive finite value */
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
    index 0ae7fdc8daf..69d34c2d4b5 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
    @@ -71,9 +71,9 @@ public final class NativeString extends ScriptObject {
     
         private final CharSequence value;
     
    -    // Method handle to create an object wrapper for a primitive string
    -    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
    -    // Method handle to retrieve the String prototype object
    +    /** Method handle to create an object wrapper for a primitive string */
    +    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
    +    /** Method handle to retrieve the String prototype object */
         private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
     
         // initialized by nasgen
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java
    index 5c61396cb2b..589fb9c1b00 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java
    @@ -326,18 +326,28 @@ public abstract class AbstractParser {
         }
     
         /**
    -     * Check next token and advance.
    +     * Check current token and advance to the next token.
          *
          * @param expected Expected tokenType.
          *
          * @throws ParserException on unexpected token type
          */
         protected final void expect(final TokenType expected) throws ParserException {
    +        expectDontAdvance(expected);
    +        next();
    +    }
    +
    +    /**
    +     * Check current token, but don't advance to the next token.
    +     *
    +     * @param expected Expected tokenType.
    +     *
    +     * @throws ParserException on unexpected token type
    +     */
    +    protected final void expectDontAdvance(final TokenType expected) throws ParserException {
             if (type != expected) {
                 throw error(expectMessage(expected));
             }
    -
    -        next();
         }
     
         /**
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
    index 1dad69ec0f1..4bfeeaf2223 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
    @@ -35,6 +35,7 @@ import static jdk.nashorn.internal.parser.TokenType.ERROR;
     import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
     import static jdk.nashorn.internal.parser.TokenType.EXECSTRING;
     import static jdk.nashorn.internal.parser.TokenType.FLOATING;
    +import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
     import static jdk.nashorn.internal.parser.TokenType.HEXADECIMAL;
     import static jdk.nashorn.internal.parser.TokenType.LBRACE;
     import static jdk.nashorn.internal.parser.TokenType.LPAREN;
    @@ -85,6 +86,9 @@ public class Lexer extends Scanner {
         /** Type of last token added. */
         private TokenType last;
     
    +    private final boolean pauseOnFunctionBody;
    +    private boolean pauseOnNextLeftBrace;
    +
         private static final String SPACETAB = " \t";  // ASCII space and tab
         private static final String LFCR     = "\n\r"; // line feed and carriage return (ctrl-m)
     
    @@ -182,20 +186,23 @@ public class Lexer extends Scanner {
          * @param scripting are we in scripting mode
          */
         public Lexer(final Source source, final TokenStream stream, final boolean scripting) {
    -        this(source, 0, source.getLength(), stream, scripting);
    +        this(source, 0, source.getLength(), stream, scripting, false);
         }
     
         /**
    -     * Contructor
    +     * Constructor
          *
          * @param source    the source
          * @param start     start position in source from which to start lexing
          * @param len       length of source segment to lex
          * @param stream    token stream to lex
          * @param scripting are we in scripting mode
    +     * @param pauseOnFunctionBody if true, lexer will return from {@link #lexify()} when it encounters a
    +     * function body. This is used with the feature where the parser is skipping nested function bodies to
    +     * avoid reading ahead unnecessarily when we skip the function bodies.
          */
     
    -    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting) {
    +    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean pauseOnFunctionBody) {
             super(source.getContent(), 1, start, len);
             this.source      = source;
             this.stream      = stream;
    @@ -203,6 +210,8 @@ public class Lexer extends Scanner {
             this.nested      = false;
             this.pendingLine = 1;
             this.last        = EOL;
    +
    +        this.pauseOnFunctionBody = pauseOnFunctionBody;
         }
     
         private Lexer(final Lexer lexer, final State state) {
    @@ -216,6 +225,7 @@ public class Lexer extends Scanner {
             pendingLine = state.pendingLine;
             linePosition = state.linePosition;
             last = EOL;
    +        pauseOnFunctionBody = false;
         }
     
         static class State extends Scanner.State {
    @@ -810,6 +820,9 @@ public class Lexer extends Scanner {
             final int length = scanIdentifier();
             // Check to see if it is a keyword.
             final TokenType type = TokenLookup.lookupKeyword(content, start, length);
    +        if (type == FUNCTION && pauseOnFunctionBody) {
    +            pauseOnNextLeftBrace = true;
    +        }
             // Add keyword or identifier token.
             add(type, start);
         }
    @@ -1597,6 +1610,9 @@ public class Lexer extends Scanner {
                     // We break to let the parser decide what it is.
                     if (canStartLiteral(type)) {
                         break;
    +                } else if (type == LBRACE && pauseOnNextLeftBrace) {
    +                    pauseOnNextLeftBrace = false;
    +                    break;
                     }
                 } else if (Character.isJavaIdentifierStart(ch0) || ch0 == '\\' && ch1 == 'u') {
                     // Scan and add identifier or keyword.
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
    index 8b4e53cb5f2..6f47c3fc6a1 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
    @@ -148,7 +148,7 @@ public class Parser extends AbstractParser implements Loggable {
         /** to receive line information from Lexer when scanning multine literals. */
         protected final Lexer.LineInfoReceiver lineInfoReceiver;
     
    -    private int nextFunctionId;
    +    private RecompilableScriptFunctionData reparsedFunction;
     
         /**
          * Constructor
    @@ -171,7 +171,7 @@ public class Parser extends AbstractParser implements Loggable {
          * @param log debug logger if one is needed
          */
         public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) {
    -        this(env, source, errors, strict, FunctionNode.FIRST_FUNCTION_ID, 0, log);
    +        this(env, source, errors, strict, 0, log);
         }
     
         /**
    @@ -181,15 +181,13 @@ public class Parser extends AbstractParser implements Loggable {
          * @param source  source to parse
          * @param errors  error manager
          * @param strict  parser created with strict mode enabled.
    -     * @param nextFunctionId  starting value for assigning new unique ids to function nodes
          * @param lineOffset line offset to start counting lines from
          * @param log debug logger if one is needed
          */
    -    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int nextFunctionId, final int lineOffset, final DebugLogger log) {
    +    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
             super(source, errors, strict, lineOffset);
             this.env = env;
             this.namespace = new Namespace(env.getNamespace());
    -        this.nextFunctionId    = nextFunctionId;
             this.scripting = env._scripting;
             if (this.scripting) {
                 this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
    @@ -227,6 +225,16 @@ public class Parser extends AbstractParser implements Loggable {
             defaultNames.push(createIdentNode(0, 0, name));
         }
     
    +    /**
    +     * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this
    +     * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation).
    +     * This will trigger various special behaviors, such as skipping nested function bodies.
    +     * @param reparsedFunction the function being reparsed.
    +     */
    +    public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) {
    +        this.reparsedFunction = reparsedFunction;
    +    }
    +
         /**
          * Execute parse and return the resulting function node.
          * Errors will be thrown and the error manager will contain information
    @@ -264,7 +272,7 @@ public class Parser extends AbstractParser implements Loggable {
     
             try {
                 stream = new TokenStream();
    -            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions);
    +            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
                 lexer.line = lexer.pendingLine = lineOffset + 1;
                 line = lineOffset;
     
    @@ -472,7 +480,6 @@ loop:
             final FunctionNode functionNode =
                 new FunctionNode(
                     source,
    -                nextFunctionId++,
                     functionLine,
                     token,
                     Token.descPosition(token),
    @@ -2828,10 +2835,14 @@ loop:
             FunctionNode functionNode = null;
             long lastToken = 0L;
     
    +        final boolean parseBody;
    +        Object endParserState = null;
             try {
                 // Create a new function block.
                 functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
    -
    +            assert functionNode != null;
    +            final int functionId = functionNode.getId();
    +            parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
                 // Nashorn extension: expression closures
                 if (!env._no_syntax_extensions && type != LBRACE) {
                     /*
    @@ -2847,34 +2858,143 @@ loop:
                     assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
                     // EOL uses length field to store the line number
                     final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
    -                final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
    -                appendStatement(returnNode);
    -                functionNode.setFinish(lastFinish);
    -
    -            } else {
    -                expect(LBRACE);
    -
    -                // Gather the function elements.
    -                final List prevFunctionDecls = functionDeclarations;
    -                functionDeclarations = new ArrayList<>();
    -                try {
    -                    sourceElements(false);
    -                    addFunctionDeclarations(functionNode);
    -                } finally {
    -                    functionDeclarations = prevFunctionDecls;
    +                // Only create the return node if we aren't skipping nested functions. Note that we aren't
    +                // skipping parsing of these extended functions; they're considered to be small anyway. Also,
    +                // they don't end with a single well known token, so it'd be very hard to get correctly (see
    +                // the note below for reasoning on skipping happening before instead of after RBRACE for
    +                // details).
    +                if (parseBody) {
    +                    final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
    +                    appendStatement(returnNode);
                     }
    +                functionNode.setFinish(lastFinish);
    +            } else {
    +                expectDontAdvance(LBRACE);
    +                if (parseBody || !skipFunctionBody(functionNode)) {
    +                    next();
    +                    // Gather the function elements.
    +                    final List prevFunctionDecls = functionDeclarations;
    +                    functionDeclarations = new ArrayList<>();
    +                    try {
    +                        sourceElements(false);
    +                        addFunctionDeclarations(functionNode);
    +                    } finally {
    +                        functionDeclarations = prevFunctionDecls;
    +                    }
     
    -                lastToken = token;
    +                    lastToken = token;
    +                    if (parseBody) {
    +                        // Since the lexer can read ahead and lexify some number of tokens in advance and have
    +                        // them buffered in the TokenStream, we need to produce a lexer state as it was just
    +                        // before it lexified RBRACE, and not whatever is its current (quite possibly well read
    +                        // ahead) state.
    +                        endParserState = new ParserState(Token.descPosition(token), line, linePosition);
    +
    +                        // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of
    +                        // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the
    +                        // state after it. The reason is that RBRACE is a well-known token that we can expect and
    +                        // will never involve us getting into a weird lexer state, and as such is a great reparse
    +                        // point. Typical example of a weird lexer state after RBRACE would be:
    +                        //     function this_is_skipped() { ... } "use strict";
    +                        // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead
    +                        // of compensating for the possibility of a string literal (or similar) after RBRACE,
    +                        // we'll rather just restart parsing from this well-known, friendly token instead.
    +                    }
    +                }
                     expect(RBRACE);
                     functionNode.setFinish(finish);
                 }
             } finally {
                 functionNode = restoreFunctionNode(functionNode, lastToken);
             }
    +
    +        // NOTE: we can only do alterations to the function node after restoreFunctionNode.
    +
    +        if (parseBody) {
    +            functionNode = functionNode.setEndParserState(lc, endParserState);
    +        } else if (functionNode.getBody().getStatementCount() > 0){
    +            // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
    +            // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
    +            // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
    +            // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
    +            // nested bodies early if we were supposed to skip 'em.
    +            functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null,
    +                    Collections.emptyList()));
    +        }
    +
    +        if (reparsedFunction != null) {
    +            // We restore the flags stored in the function's ScriptFunctionData that we got when we first
    +            // eagerly parsed the code. We're doing it because some flags would be set based on the
    +            // content of the function, or even content of its nested functions, most of which are normally
    +            // skipped during an on-demand compilation.
    +            final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
    +            if (data != null) {
    +                // Data can be null if when we originally parsed the file, we removed the function declaration
    +                // as it was dead code.
    +                functionNode = functionNode.setFlags(lc, data.getFunctionFlags());
    +                // This compensates for missing markEval() in case the function contains an inner function
    +                // that contains eval(), that now we didn't discover since we skipped the inner function.
    +                if (functionNode.hasNestedEval()) {
    +                    assert functionNode.hasScopeBlock();
    +                    functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null));
    +                }
    +            }
    +        }
             printAST(functionNode);
             return functionNode;
         }
     
    +    private boolean skipFunctionBody(final FunctionNode functionNode) {
    +        if (reparsedFunction == null) {
    +            // Not reparsing, so don't skip any function body.
    +            return false;
    +        }
    +        // Skip to the RBRACE of this function, and continue parsing from there.
    +        final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
    +        if (data == null) {
    +            // Nested function is not known to the reparsed function. This can happen if the FunctionNode was
    +            // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the
    +            // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it.
    +            return false;
    +        }
    +        final ParserState parserState = (ParserState)data.getEndParserState();
    +        assert parserState != null;
    +
    +        stream.reset();
    +        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions);
    +        line = parserState.line;
    +        linePosition = parserState.linePosition;
    +        // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
    +        // the RBRACE.
    +        type = SEMICOLON;
    +        k = -1;
    +        next();
    +
    +        return true;
    +    }
    +
    +    /**
    +     * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer
    +     * for resuming parsing after skipping a function body.
    +     */
    +    private static class ParserState {
    +        private final int position;
    +        private final int line;
    +        private final int linePosition;
    +
    +        ParserState(final int position, final int line, final int linePosition) {
    +            this.position = position;
    +            this.line = line;
    +            this.linePosition = linePosition;
    +        }
    +
    +        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) {
    +            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true);
    +            newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
    +            return newLexer;
    +        }
    +    }
    +
         private void printAST(final FunctionNode functionNode) {
             if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
                 env.getErr().println(new ASTWriter(functionNode));
    @@ -3247,6 +3367,9 @@ loop:
                 } else {
                     lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
                 }
    +            // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
    +            // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
    +            // this method when the parser skips a nested function.
                 lc.setBlockNeedsScope(lc.getFunctionBody(fn));
             }
         }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java
    index ee81ce3921b..f7df999f997 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java
    @@ -209,4 +209,8 @@ public class TokenStream {
             in = count;
             buffer = newBuffer;
         }
    +
    +    void reset() {
    +        in = out = count = base = 0;
    +    }
     }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java
    new file mode 100644
    index 00000000000..e4d6ccb10ef
    --- /dev/null
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java
    @@ -0,0 +1,104 @@
    +/*
    + * Copyright (c) 2014, 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.nashorn.internal.runtime;
    +
    +import static jdk.nashorn.internal.lookup.Lookup.MH;
    +
    +import java.io.Serializable;
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import jdk.nashorn.internal.codegen.CompilerConstants;
    +import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
    +
    +/**
    + * Encapsulates the allocation strategy for a function when used as a constructor. Basically the same as
    + * {@link AllocatorDescriptor}, but with an additionally cached resolved method handle. There is also a
    + * canonical default allocation strategy for functions that don't assign any "this" properties (vast majority
    + * of all functions), therefore saving some storage space in {@link RecompilableScriptFunctionData} that would
    + * otherwise be lost to identical tuples of (map, className, handle) fields.
    + */
    +final class AllocationStrategy implements Serializable {
    +    private static final long serialVersionUID = 1L;
    +
    +    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
    +
    +    private static final AllocationStrategy DEFAULT_STRATEGY = new AllocationStrategy(new AllocatorDescriptor(0));
    +
    +    /** Allocator map from allocator descriptor */
    +    private final PropertyMap allocatorMap;
    +
    +    /** Name of class where allocator function resides */
    +    private final String allocatorClassName;
    +
    +    /** lazily generated allocator */
    +    private transient MethodHandle allocator;
    +
    +    private AllocationStrategy(final AllocatorDescriptor desc) {
    +        this.allocatorMap = desc.getAllocatorMap();
    +        // These classes get loaded, so an interned variant of their name is most likely around anyway.
    +        this.allocatorClassName = desc.getAllocatorClassName().intern();
    +    }
    +
    +    private boolean matches(final AllocatorDescriptor desc) {
    +        return desc.getAllocatorMap().size() == allocatorMap.size() &&
    +                desc.getAllocatorClassName().equals(allocatorClassName);
    +    }
    +
    +    static AllocationStrategy get(final AllocatorDescriptor desc) {
    +        return DEFAULT_STRATEGY.matches(desc) ? DEFAULT_STRATEGY : new AllocationStrategy(desc);
    +    }
    +
    +    PropertyMap getAllocatorMap() {
    +        return allocatorMap;
    +    }
    +
    +    ScriptObject allocate(final PropertyMap map) {
    +        try {
    +            if (allocator == null) {
    +                allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName),
    +                        CompilerConstants.ALLOCATE.symbolName(), MH.type(ScriptObject.class, PropertyMap.class));
    +            }
    +            return (ScriptObject)allocator.invokeExact(map);
    +        } catch (final RuntimeException | Error e) {
    +            throw e;
    +        } catch (final Throwable t) {
    +            throw new RuntimeException(t);
    +        }
    +    }
    +
    +    private Object readResolve() {
    +        if(allocatorMap.size() == DEFAULT_STRATEGY.allocatorMap.size() &&
    +                allocatorClassName.equals(DEFAULT_STRATEGY.allocatorClassName)) {
    +            return DEFAULT_STRATEGY;
    +        }
    +        return this;
    +    }
    +
    +    @Override
    +    public String toString() {
    +        return "AllocationStrategy[allocatorClassName=" + allocatorClassName + ", allocatorMap.size=" +
    +                allocatorMap.size() + "]";
    +    }
    +}
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java
    index db42e2814e5..7a7df467819 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java
    @@ -79,12 +79,6 @@ public interface CodeInstaller {
          */
         public long getUniqueScriptId();
     
    -    /**
    -     * Get next unique eval id
    -     * @return unique eval id
    -     */
    -    public long getUniqueEvalId();
    -
         /**
          * Store a compiled script for later reuse
          * @param source the script source
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
    index 958b2590c5b..28a81dea91e 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
    @@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime;
     import static jdk.nashorn.internal.lookup.Lookup.MH;
     import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
     import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
    -
     import java.lang.invoke.CallSite;
     import java.lang.invoke.MethodHandle;
     import java.lang.invoke.MethodHandles;
    @@ -39,6 +38,7 @@ import java.util.Map;
     import java.util.TreeMap;
     import java.util.function.Supplier;
     import java.util.logging.Level;
    +
     import jdk.internal.dynalink.linker.GuardedInvocation;
     import jdk.nashorn.internal.codegen.Compiler;
     import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
    index cdf91c49096..c144d363427 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
    @@ -196,16 +196,11 @@ public final class Context {
             }
     
             @Override
    -        public long getUniqueEvalId() {
    -            return context.getUniqueEvalId();
    -        }
    -
    -        @Override
    -        public void storeScript(final String classInfoFile, final Source source, final String mainClassName,
    +        public void storeScript(final String cacheKey, final Source source, final String mainClassName,
                                     final Map classBytes, final Map initializers,
                                     final Object[] constants, final int compilationId) {
                 if (context.codeStore != null) {
    -                context.codeStore.storeScript(classInfoFile, source, mainClassName, classBytes, initializers, constants, compilationId);
    +                context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
                 }
             }
     
    @@ -334,9 +329,6 @@ public final class Context {
         /** Unique id for script. Used only when --loader-per-compile=false */
         private final AtomicLong uniqueScriptId;
     
    -    /** Unique id for 'eval' */
    -    private final AtomicLong uniqueEvalId;
    -
         /** Optional class filter to use for Java classes. Can be null. */
         private final ClassFilter classFilter;
     
    @@ -450,7 +442,6 @@ public final class Context {
                 this.uniqueScriptId = new AtomicLong();
             }
             this.errors    = errors;
    -        this.uniqueEvalId = new AtomicLong();
     
             // if user passed -classpath option, make a class loader with that and set it as
             // thread context class loader so that script can access classes from that path.
    @@ -1190,10 +1181,6 @@ public final class Context {
                  }, CREATE_LOADER_ACC_CTXT);
         }
     
    -    private long getUniqueEvalId() {
    -        return uniqueEvalId.getAndIncrement();
    -    }
    -
         private long getUniqueScriptId() {
             return uniqueScriptId.getAndIncrement();
         }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
    index 1b10bd446a0..72a2d835208 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
    @@ -29,7 +29,9 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
     import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
     
     import java.lang.invoke.MethodHandle;
    +import jdk.internal.dynalink.linker.LinkRequest;
     import jdk.nashorn.internal.codegen.ObjectClassGenerator;
    +import jdk.nashorn.internal.objects.Global;
     
     /**
      * This class represents the result from a find property search.
    @@ -79,25 +81,17 @@ public final class FindProperty {
          * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
          * @return method handle for the getter
          */
    -    public MethodHandle getGetter(final Class type, final int programPoint) {
    +    public MethodHandle getGetter(final Class type, final int programPoint, final LinkRequest request) {
             final MethodHandle getter;
             if (isValid(programPoint)) {
                 getter = property.getOptimisticGetter(type, programPoint);
             } else {
                 getter = property.getGetter(type);
             }
    -        return getGetterInner(getter);
    -    }
    -
    -    private MethodHandle getGetterInner(final MethodHandle getter) {
             if (property instanceof UserAccessorProperty) {
    -            final UserAccessorProperty uc        = (UserAccessorProperty)property;
    -            final ScriptObject         owner     = getOwner();
    -            final ScriptObject         container = (owner != null) ? owner : self;
    -            return MH.insertArguments(getter, 0, uc.getAccessors(container));
    +            return insertAccessorsGetter((UserAccessorProperty) property, request, getter);
             }
             return getter;
    -
         }
     
         /**
    @@ -111,18 +105,31 @@ public final class FindProperty {
          *
          * @return method handle for the getter
          */
    -    public MethodHandle getSetter(final Class type, final boolean strict) {
    -        final MethodHandle setter = property.getSetter(type, getOwner().getMap());
    +    public MethodHandle getSetter(final Class type, final boolean strict, final LinkRequest request) {
    +        MethodHandle setter = property.getSetter(type, getOwner().getMap());
             if (property instanceof UserAccessorProperty) {
    -            final UserAccessorProperty uc        = (UserAccessorProperty)property;
    -            final ScriptObject         owner     = getOwner();
    -            final ScriptObject         container = (owner != null) ? owner : self;
    -            return MH.insertArguments(setter, 0, uc.getAccessors(container), strict ? property.getKey() : null);
    +            setter =  MH.insertArguments(setter, 1, strict ? property.getKey() : null);
    +            return insertAccessorsGetter((UserAccessorProperty) property, request, setter);
             }
     
             return setter;
         }
     
    +    // Fold an accessor getter into the method handle of a user accessor property.
    +    private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
    +        MethodHandle superGetter = uap.getAccessorsGetter();
    +        if (isInherited()) {
    +            superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
    +        }
    +        if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
    +            final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver());
    +            superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0))));
    +        }
    +        superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class));
    +
    +        return MH.foldArguments(mh, superGetter);
    +    }
    +
         /**
          * Return the {@code ScriptObject} owning of the property:  this means the prototype.
          * @return owner of property
    @@ -136,7 +143,7 @@ public final class FindProperty {
          * @return appropriate receiver
          */
         public ScriptObject getGetterReceiver() {
    -        return property != null && property.hasGetterFunction(prototype) ? self : prototype;
    +        return property != null && property instanceof UserAccessorProperty ? self : prototype;
         }
     
         /**
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java
    index cc6a2de1a0d..df947cdb0c0 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java
    @@ -28,6 +28,8 @@ package jdk.nashorn.internal.runtime;
     import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
     import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
     import static jdk.nashorn.internal.lookup.Lookup.MH;
    +import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
     import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
     
     import java.lang.invoke.MethodHandle;
    @@ -370,22 +372,19 @@ public final class GlobalConstants implements Loggable {
          * @param find      property lookup
          * @param receiver  receiver
          * @param desc      callsite descriptor
    -     * @param request   link request
    -     * @param operator  operator
          *
          * @return resulting getter, or null if failed to create constant
          */
    -    synchronized GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
    -        if (GLOBAL_ONLY && !find.getOwner().isGlobal()) {
    +    synchronized GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) {
    +        // Also return null if property may have side effects
    +        if ((GLOBAL_ONLY && !find.getOwner().isGlobal()) || find.getProperty() instanceof UserAccessorProperty) {
                 return null;
             }
     
    -        final int programPoint         = NashornCallSiteDescriptor.isOptimistic(desc) ?
    -            NashornCallSiteDescriptor.getProgramPoint(desc) :
    -            UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    -        final boolean     isOptimistic = programPoint != UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    -        final Class    retType      = desc.getMethodType().returnType();
    -        final String      name         = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
    +        final boolean  isOptimistic = NashornCallSiteDescriptor.isOptimistic(desc);
    +        final int      programPoint = isOptimistic ? getProgramPoint(desc) : INVALID_PROGRAM_POINT;
    +        final Class retType      = desc.getMethodType().returnType();
    +        final String   name         = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
     
             final Access acc = getOrCreateSwitchPoint(name);
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
    index 12f4bac8aa7..5f5229ba3c3 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
    @@ -42,6 +42,7 @@ import jdk.nashorn.internal.codegen.Compiler;
     import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
     import jdk.nashorn.internal.codegen.CompilerConstants;
     import jdk.nashorn.internal.codegen.FunctionSignature;
    +import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
     import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
     import jdk.nashorn.internal.codegen.TypeMap;
     import jdk.nashorn.internal.codegen.types.Type;
    @@ -55,7 +56,6 @@ import jdk.nashorn.internal.parser.TokenType;
     import jdk.nashorn.internal.runtime.logging.DebugLogger;
     import jdk.nashorn.internal.runtime.logging.Loggable;
     import jdk.nashorn.internal.runtime.logging.Logger;
    -
     /**
      * This is a subclass that represents a script function that may be regenerated,
      * for example with specialization based on call site types, or lazily generated.
    @@ -81,26 +81,29 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
         /** Token of this function within the source. */
         private final long token;
     
    -    /** Allocator map from makeMap() */
    -    private final PropertyMap allocatorMap;
    +    /**
    +     * Represents the allocation strategy (property map, script object class, and method handle) for when
    +     * this function is used as a constructor. Note that majority of functions (those not setting any this.*
    +     * properties) will share a single canonical "default strategy" instance.
    +     */
    +    private final AllocationStrategy allocationStrategy;
    +
    +    /**
    +     * Opaque object representing parser state at the end of the function. Used when reparsing outer function
    +     * to help with skipping parsing inner functions.
    +     */
    +    private final Object endParserState;
     
         /** Code installer used for all further recompilation/specialization of this ScriptFunction */
         private transient CodeInstaller installer;
     
    -    /** Name of class where allocator function resides */
    -    private final String allocatorClassName;
    -
    -    /** lazily generated allocator */
    -    private transient MethodHandle allocator;
    -
         private final Map nestedFunctions;
     
         /** Id to parent function if one exists */
         private RecompilableScriptFunctionData parent;
     
    -    private final boolean isDeclared;
    -    private final boolean isAnonymous;
    -    private final boolean needsCallee;
    +    /** Copy of the {@link FunctionNode} flags. */
    +    private final int functionFlags;
     
         private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
     
    @@ -119,8 +122,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
          *
          * @param functionNode        functionNode that represents this function code
          * @param installer           installer for code regeneration versions of this function
    -     * @param allocatorClassName  name of our allocator class, will be looked up dynamically if used as a constructor
    -     * @param allocatorMap        allocator map to seed instances with, when constructing
    +     * @param allocationDescriptor descriptor for the allocation behavior when this function is used as a constructor
          * @param nestedFunctions     nested function map
          * @param externalScopeDepths external scope depths
          * @param internalSymbols     internal symbols to method, defined in its scope
    @@ -128,30 +130,27 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
         public RecompilableScriptFunctionData(
             final FunctionNode functionNode,
             final CodeInstaller installer,
    -        final String allocatorClassName,
    -        final PropertyMap allocatorMap,
    +        final AllocatorDescriptor allocationDescriptor,
             final Map nestedFunctions,
             final Map externalScopeDepths,
             final Set internalSymbols) {
     
             super(functionName(functionNode),
                   Math.min(functionNode.getParameters().size(), MAX_ARITY),
    -              getFlags(functionNode));
    +              getDataFlags(functionNode));
     
             this.functionName        = functionNode.getName();
             this.lineNumber          = functionNode.getLineNumber();
    -        this.isDeclared          = functionNode.isDeclared();
    -        this.needsCallee         = functionNode.needsCallee();
    -        this.isAnonymous         = functionNode.isAnonymous();
    +        this.functionFlags       = functionNode.getFlags() | (functionNode.needsCallee() ? FunctionNode.NEEDS_CALLEE : 0);
             this.functionNodeId      = functionNode.getId();
             this.source              = functionNode.getSource();
    +        this.endParserState      = functionNode.getEndParserState();
             this.token               = tokenFor(functionNode);
             this.installer           = installer;
    -        this.allocatorClassName  = allocatorClassName;
    -        this.allocatorMap        = allocatorMap;
    -        this.nestedFunctions     = nestedFunctions;
    -        this.externalScopeDepths = externalScopeDepths;
    -        this.internalSymbols     = new HashSet<>(internalSymbols);
    +        this.allocationStrategy  = AllocationStrategy.get(allocationDescriptor);
    +        this.nestedFunctions     = smallMap(nestedFunctions);
    +        this.externalScopeDepths = smallMap(externalScopeDepths);
    +        this.internalSymbols     = smallSet(new HashSet<>(internalSymbols));
     
             for (final RecompilableScriptFunctionData nfn : nestedFunctions.values()) {
                 assert nfn.getParent() == null;
    @@ -161,6 +160,27 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
             createLogger();
         }
     
    +    private static  Map smallMap(final Map map) {
    +        if (map == null || map.isEmpty()) {
    +            return Collections.emptyMap();
    +        } else if (map.size() == 1) {
    +            final Map.Entry entry = map.entrySet().iterator().next();
    +            return Collections.singletonMap(entry.getKey(), entry.getValue());
    +        } else {
    +            return map;
    +        }
    +    }
    +
    +    private static  Set smallSet(final Set set) {
    +        if (set == null || set.isEmpty()) {
    +            return Collections.emptySet();
    +        } else if (set.size() == 1) {
    +            return Collections.singleton(set.iterator().next());
    +        } else {
    +            return set;
    +        }
    +    }
    +
         @Override
         public DebugLogger getLogger() {
             return log;
    @@ -190,17 +210,30 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
          * @return the external symbol table with proto depths
          */
         public int getExternalSymbolDepth(final String symbolName) {
    -        final Map map = externalScopeDepths;
    -        if (map == null) {
    -            return -1;
    -        }
    -        final Integer depth = map.get(symbolName);
    +        final Integer depth = externalScopeDepths.get(symbolName);
             if (depth == null) {
                 return -1;
             }
             return depth;
         }
     
    +    /**
    +     * Returns the names of all external symbols this function uses.
    +     * @return the names of all external symbols this function uses.
    +     */
    +    public Set getExternalSymbolNames() {
    +        return Collections.unmodifiableSet(externalScopeDepths.keySet());
    +    }
    +
    +    /**
    +     * Returns the opaque object representing the parser state at the end of this function's body, used to
    +     * skip parsing this function when reparsing its containing outer function.
    +     * @return the object representing the end parser state
    +     */
    +    public Object getEndParserState() {
    +        return endParserState;
    +    }
    +
         /**
          * Get the parent of this RecompilableScriptFunctionData. If we are
          * a nested function, we have a parent. Note that "null" return value
    @@ -269,7 +302,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
     
         @Override
         public boolean inDynamicContext() {
    -        return (flags & IN_DYNAMIC_CONTEXT) != 0;
    +        return getFunctionFlag(FunctionNode.IN_DYNAMIC_CONTEXT);
         }
     
         private static String functionName(final FunctionNode fn) {
    @@ -293,7 +326,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
             return Token.toDesc(TokenType.FUNCTION, position, length);
         }
     
    -    private static int getFlags(final FunctionNode functionNode) {
    +    private static int getDataFlags(final FunctionNode functionNode) {
             int flags = IS_CONSTRUCTOR;
             if (functionNode.isStrict()) {
                 flags |= IS_STRICT;
    @@ -307,37 +340,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
             if (functionNode.isVarArg()) {
                 flags |= IS_VARIABLE_ARITY;
             }
    -        if (functionNode.inDynamicContext()) {
    -            flags |= IN_DYNAMIC_CONTEXT;
    -        }
             return flags;
         }
     
         @Override
         PropertyMap getAllocatorMap() {
    -        return allocatorMap;
    +        return allocationStrategy.getAllocatorMap();
         }
     
         @Override
         ScriptObject allocate(final PropertyMap map) {
    -        try {
    -            ensureHasAllocator(); //if allocatorClass name is set to null (e.g. for bound functions) we don't even try
    -            return allocator == null ? null : (ScriptObject)allocator.invokeExact(map);
    -        } catch (final RuntimeException | Error e) {
    -            throw e;
    -        } catch (final Throwable t) {
    -            throw new RuntimeException(t);
    -        }
    -    }
    -
    -    private void ensureHasAllocator() throws ClassNotFoundException {
    -        if (allocator == null && allocatorClassName != null) {
    -            this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.symbolName(), MH.type(ScriptObject.class, PropertyMap.class));
    -        }
    +        return allocationStrategy.allocate(map);
         }
     
         FunctionNode reparse() {
    -        final boolean isProgram = functionNodeId == FunctionNode.FIRST_FUNCTION_ID;
             // NOTE: If we aren't recompiling the top-level program, we decrease functionNodeId 'cause we'll have a synthetic program node
             final int descPosition = Token.descPosition(token);
             final Context context = Context.getContextTrusted();
    @@ -346,18 +362,27 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
                 source,
                 new Context.ThrowErrorManager(),
                 isStrict(),
    -            functionNodeId - (isProgram ? 0 : 1),
                 lineNumber - 1,
                 context.getLogger(Parser.class)); // source starts at line 0, so even though lineNumber is the correct declaration line, back off one to make it exclusive
     
    -        if (isAnonymous) {
    +        if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
                 parser.setFunctionName(functionName);
             }
    +        parser.setReparsedFunction(this);
     
    -        final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition, Token.descLength(token), true);
    -        // Parser generates a program AST even if we're recompiling a single function, so when we are only recompiling a
    -        // single function, extract it from the program.
    -        return (isProgram ? program : extractFunctionFromScript(program)).setName(null, functionName);
    +        final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition,
    +                Token.descLength(token), true);
    +        // Parser generates a program AST even if we're recompiling a single function, so when we are only
    +        // recompiling a single function, extract it from the program.
    +        return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
    +    }
    +
    +    private boolean getFunctionFlag(final int flag) {
    +        return (functionFlags & flag) != 0;
    +    }
    +
    +    private boolean isProgram() {
    +        return getFunctionFlag(FunctionNode.IS_PROGRAM);
         }
     
         TypeMap typeMap(final MethodType fnCallSiteType) {
    @@ -546,7 +571,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
             assert fns.size() == 1 : "got back more than one method in recompilation";
             final FunctionNode f = fns.iterator().next();
             assert f.getId() == functionNodeId;
    -        if (!isDeclared && f.isDeclared()) {
    +        if (!getFunctionFlag(FunctionNode.IS_DECLARED) && f.isDeclared()) {
                 return f.clearFlag(null, FunctionNode.IS_DECLARED);
             }
             return f;
    @@ -669,7 +694,15 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
     
         @Override
         public boolean needsCallee() {
    -        return needsCallee;
    +        return getFunctionFlag(FunctionNode.NEEDS_CALLEE);
    +    }
    +
    +    /**
    +     * Returns the {@link FunctionNode} flags associated with this function data.
    +     * @return the {@link FunctionNode} flags associated with this function data.
    +     */
    +    public int getFunctionFlags() {
    +        return functionFlags;
         }
     
         @Override
    @@ -720,21 +753,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
             return null;
         }
     
    -    /**
    -     * Get the uppermost parent, the program, for this data
    -     * @return program
    -     */
    -    public RecompilableScriptFunctionData getProgram() {
    -        RecompilableScriptFunctionData program = this;
    -        while (true) {
    -            final RecompilableScriptFunctionData p = program.getParent();
    -            if (p == null) {
    -                return program;
    -            }
    -            program = p;
    -        }
    -    }
    -
         /**
          * Check whether a certain name is a global symbol, i.e. only exists as defined
          * in outermost scope and not shadowed by being parameter or assignment in inner
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
    index 3cd292a7f71..d92b12d9d66 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
    @@ -90,8 +90,6 @@ public abstract class ScriptFunctionData implements Serializable {
         public static final int USES_THIS      = 1 << 4;
         /** Is this a variable arity function? */
         public static final int IS_VARIABLE_ARITY = 1 << 5;
    -    /** Is this declared in a dynamic context */
    -    public static final int IN_DYNAMIC_CONTEXT = 1 << 6;
     
         /** Flag for strict or built-in functions */
         public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
    index d2f88258c3d..cabd13575f5 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
    @@ -1050,7 +1050,7 @@ public abstract class ScriptObject implements PropertyAccess {
         }
     
         private static int getIntValue(final FindProperty find, final int programPoint) {
    -        final MethodHandle getter = find.getGetter(int.class, programPoint);
    +        final MethodHandle getter = find.getGetter(int.class, programPoint, null);
             if (getter != null) {
                 try {
                     return (int)getter.invokeExact((Object)find.getGetterReceiver());
    @@ -1065,7 +1065,7 @@ public abstract class ScriptObject implements PropertyAccess {
         }
     
         private static long getLongValue(final FindProperty find, final int programPoint) {
    -        final MethodHandle getter = find.getGetter(long.class, programPoint);
    +        final MethodHandle getter = find.getGetter(long.class, programPoint, null);
             if (getter != null) {
                 try {
                     return (long)getter.invokeExact((Object)find.getGetterReceiver());
    @@ -1080,7 +1080,7 @@ public abstract class ScriptObject implements PropertyAccess {
         }
     
         private static double getDoubleValue(final FindProperty find, final int programPoint) {
    -        final MethodHandle getter = find.getGetter(double.class, programPoint);
    +        final MethodHandle getter = find.getGetter(double.class, programPoint, null);
             if (getter != null) {
                 try {
                     return (double)getter.invokeExact((Object)find.getGetterReceiver());
    @@ -1971,7 +1971,7 @@ public abstract class ScriptObject implements PropertyAccess {
                 }
             }
     
    -        final GuardedInvocation cinv = Global.getConstants().findGetMethod(find, this, desc, request, operator);
    +        final GuardedInvocation cinv = Global.getConstants().findGetMethod(find, this, desc);
             if (cinv != null) {
                 return cinv;
             }
    @@ -1983,7 +1983,7 @@ public abstract class ScriptObject implements PropertyAccess {
                     NashornCallSiteDescriptor.getProgramPoint(desc) :
                     UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
     
    -        mh = find.getGetter(returnType, programPoint);
    +        mh = find.getGetter(returnType, programPoint, request);
             // Get the appropriate guard for this callsite and property.
             final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck);
             final ScriptObject owner = find.getOwner();
    @@ -1995,8 +1995,9 @@ public abstract class ScriptObject implements PropertyAccess {
                 mh = Lookup.emptyGetter(returnType);
                 protoSwitchPoint = getProtoSwitchPoint(name, owner);
             } else if (!find.isSelf()) {
    -            assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
    -            if (!property.hasGetterFunction(owner)) {
    +            assert mh.type().returnType().equals(returnType) :
    +                    "return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
    +            if (!(property instanceof UserAccessorProperty)) {
                     // Add a filter that replaces the self object with the prototype owning the property.
                     mh = addProtoFilter(mh, find.getProtoChainLength());
                 }
    @@ -2167,7 +2168,7 @@ public abstract class ScriptObject implements PropertyAccess {
                 }
             }
     
    -        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
    +        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
     
             final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
             if (cinv != null) {
    @@ -2320,13 +2321,13 @@ public abstract class ScriptObject implements PropertyAccess {
                             find.isSelf()?
                                 getKnownFunctionPropertyGuardSelf(
                                     getMap(),
    -                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
    +                                find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
                                     func)
                                 :
                                 //TODO this always does a scriptobject check
                                 getKnownFunctionPropertyGuardProto(
                                     getMap(),
    -                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
    +                                find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
                                     find.getProtoChainLength(),
                                     func),
                             getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
    index 38bf53b62f7..757cb3051e9 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
    @@ -33,6 +33,7 @@ import java.lang.invoke.MethodHandle;
     import java.lang.invoke.SwitchPoint;
     import jdk.internal.dynalink.CallSiteDescriptor;
     import jdk.internal.dynalink.linker.GuardedInvocation;
    +import jdk.internal.dynalink.linker.LinkRequest;
     import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
     import jdk.nashorn.internal.runtime.linker.NashornGuards;
     
    @@ -48,7 +49,7 @@ final class SetMethodCreator {
         private final FindProperty       find;
         private final CallSiteDescriptor desc;
         private final Class           type;
    -    private final boolean            explicitInstanceOfCheck;
    +    private final LinkRequest        request;
     
         /**
          * Creates a new property setter method creator.
    @@ -56,14 +57,15 @@ final class SetMethodCreator {
          * @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we
          * want to create a setter for. Can be null if the property does not yet exist on the object.
          * @param desc the descriptor of the call site that triggered the property setter lookup
    +     * @param request the link request
          */
    -    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) {
    -        this.sobj = sobj;
    -        this.map  = sobj.getMap();
    -        this.find = find;
    -        this.desc = desc;
    -        this.type = desc.getMethodType().parameterType(1);
    -        this.explicitInstanceOfCheck = explicitInstanceOfCheck;
    +    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final LinkRequest request) {
    +        this.sobj    = sobj;
    +        this.map     = sobj.getMap();
    +        this.find    = find;
    +        this.desc    = desc;
    +        this.type    = desc.getMethodType().parameterType(1);
    +        this.request = request;
     
         }
     
    @@ -111,6 +113,7 @@ final class SetMethodCreator {
                 // getGuard() and getException() either both return null, or neither does. The reason for that is that now
                 // getGuard returns a map guard that casts its argument to ScriptObject, and if that fails, we need to
                 // relink on ClassCastException.
    +            final boolean explicitInstanceOfCheck = NashornGuards.explicitInstanceOfCheck(desc, request);
                 return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc, explicitInstanceOfCheck),
                         (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
             }
    @@ -140,6 +143,7 @@ final class SetMethodCreator {
     
         private SetMethod createExistingPropertySetter() {
             final Property property = find.getProperty();
    +        final boolean isStrict  = NashornCallSiteDescriptor.isStrict(desc);
             final MethodHandle methodHandle;
     
             if (NashornCallSiteDescriptor.isDeclaration(desc)) {
    @@ -152,7 +156,7 @@ final class SetMethodCreator {
                 final PropertyMap oldMap = getMap();
                 final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
                 final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
    -            final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
    +            final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, isStrict, request);
                 final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
     
                 // cas map used as guard, if true that means we can do the set fast
    @@ -161,14 +165,14 @@ final class SetMethodCreator {
                 casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
                 methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
             } else {
    -            methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
    +            methodHandle = find.getSetter(type, isStrict, request);
             }
     
             assert methodHandle != null;
             assert property     != null;
     
             final MethodHandle boundHandle;
    -        if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
    +        if (!(property instanceof UserAccessorProperty) && find.isInherited()) {
                 boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
             } else {
                 boundHandle = methodHandle;
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java
    index ae61345a1dd..e1d464d9267 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java
    @@ -33,6 +33,8 @@ import java.util.List;
     import java.util.Map;
     import java.util.concurrent.TimeUnit;
     import java.util.function.Supplier;
    +
    +import jdk.nashorn.internal.codegen.CompileUnit;
     import jdk.nashorn.internal.runtime.logging.DebugLogger;
     import jdk.nashorn.internal.runtime.logging.Loggable;
     import jdk.nashorn.internal.runtime.logging.Logger;
    @@ -189,7 +191,7 @@ public final class Timing implements Loggable {
                 maxKeyLength++;
     
                 final StringBuilder sb = new StringBuilder();
    -            sb.append("Accumulated complation phase Timings:\n\n");
    +            sb.append("Accumulated compilation phase timings:\n\n");
                 for (final Map.Entry entry : timings.entrySet()) {
                     int len;
     
    @@ -224,6 +226,9 @@ public final class Timing implements Loggable {
                     append((int)(knownTime * 100.0 / total)).
                     append("%])");
     
    +            sb.append("\n\nEmitted compile units: ").
    +                append(CompileUnit.getEmittedUnitCount());
    +
                 return sb.toString();
             }
     
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java
    index d7b52c1d4fa..7350ff43551 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java
    @@ -34,8 +34,8 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
     
     import java.lang.invoke.MethodHandle;
     import java.lang.invoke.MethodHandles;
    +import java.lang.invoke.MethodType;
     import java.util.concurrent.Callable;
    -import jdk.nashorn.internal.codegen.CompilerConstants;
     import jdk.nashorn.internal.lookup.Lookup;
     import jdk.nashorn.internal.runtime.linker.Bootstrap;
     
    @@ -48,7 +48,7 @@ public final class UserAccessorProperty extends SpillProperty {
     
         private static final long serialVersionUID = -5928687246526840321L;
     
    -    static class Accessors {
    +    static final class Accessors {
             Object getter;
             Object setter;
     
    @@ -67,20 +67,20 @@ public final class UserAccessorProperty extends SpillProperty {
             }
         }
     
    +    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
    +
         /** Getter method handle */
    -    private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
    -            "userAccessorGetter", Object.class, Accessors.class, Object.class);
    +    private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class);
     
         /** Setter method handle */
    -    private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
    -            "userAccessorSetter", void.class, Accessors.class, String.class, Object.class, Object.class);
    +    private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class);
     
         /** Dynamic invoker for getter */
    -    private static final Object INVOKE_UA_GETTER = new Object();
    +    private static final Object GETTER_INVOKER_KEY = new Object();
     
         private static MethodHandle getINVOKE_UA_GETTER() {
     
    -        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
    +        return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY,
                     new Callable() {
                         @Override
                         public MethodHandle call() {
    @@ -91,10 +91,10 @@ public final class UserAccessorProperty extends SpillProperty {
         }
     
         /** Dynamic invoker for setter */
    -    private static Object INVOKE_UA_SETTER = new Object();
    +    private static Object SETTER_INVOKER_KEY = new Object();
     
         private static MethodHandle getINVOKE_UA_SETTER() {
    -        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
    +        return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY,
                     new Callable() {
                         @Override
                         public MethodHandle call() {
    @@ -190,7 +190,7 @@ public final class UserAccessorProperty extends SpillProperty {
     
         @Override
         public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
    -        return userAccessorGetter(getAccessors((owner != null) ? owner : self), self);
    +        return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self);
         }
     
         @Override
    @@ -210,13 +210,13 @@ public final class UserAccessorProperty extends SpillProperty {
     
         @Override
         public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
    -        userAccessorSetter(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
    +        invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
         }
     
         @Override
         public MethodHandle getGetter(final Class type) {
             //this returns a getter on the format (Accessors, Object receiver)
    -        return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
    +        return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type);
         }
     
         @Override
    @@ -260,7 +260,7 @@ public final class UserAccessorProperty extends SpillProperty {
     
         @Override
         public MethodHandle getSetter(final Class type, final PropertyMap currentMap) {
    -        return USER_ACCESSOR_SETTER.methodHandle();
    +        return INVOKE_SETTER_ACCESSOR;
         }
     
         @Override
    @@ -269,11 +269,21 @@ public final class UserAccessorProperty extends SpillProperty {
             return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
         }
     
    +    /**
    +     * Get the getter for the {@code Accessors} object.
    +     * This is the the super {@code Object} type getter with {@code Accessors} return type.
    +     *
    +     * @return The getter handle for the Accessors
    +     */
    +    MethodHandle getAccessorsGetter() {
    +        return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
    +    }
    +
         // User defined getter and setter are always called by "dyn:call". Note that the user
         // getter/setter may be inherited. If so, proto is bound during lookup. In either
         // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
         // to be called is retrieved everytime and applied.
    -    static Object userAccessorGetter(final Accessors gs, final Object self) {
    +    private static Object invokeGetterAccessor(final Accessors gs, final Object self) {
             final Object func = gs.getter;
             if (func instanceof ScriptFunction) {
                 try {
    @@ -288,7 +298,7 @@ public final class UserAccessorProperty extends SpillProperty {
             return UNDEFINED;
         }
     
    -    static void userAccessorSetter(final Accessors gs, final String name, final Object self, final Object value) {
    +    private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) {
             final Object func = gs.setter;
             if (func instanceof ScriptFunction) {
                 try {
    @@ -303,4 +313,8 @@ public final class UserAccessorProperty extends SpillProperty {
             }
         }
     
    +    private static MethodHandle findOwnMH_S(final String name, final Class rtype, final Class... types) {
    +        return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types));
    +    }
    +
     }
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
    index d271da6d952..f377c9d80f2 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
    @@ -32,11 +32,10 @@ import java.lang.invoke.MethodType;
     import jdk.internal.dynalink.CallSiteDescriptor;
     import jdk.internal.dynalink.linker.GuardedInvocation;
     import jdk.internal.dynalink.linker.LinkRequest;
    -import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
     import jdk.internal.dynalink.support.Guards;
    -import jdk.nashorn.internal.lookup.Lookup;
     import jdk.nashorn.internal.runtime.FindProperty;
     import jdk.nashorn.internal.runtime.ScriptObject;
    +import jdk.nashorn.internal.runtime.UserAccessorProperty;
     
     /**
      * Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
    @@ -86,15 +85,6 @@ public final class PrimitiveLookup {
                                                         final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
                                                         final MethodHandle protoFilter) {
             final CallSiteDescriptor desc = request.getCallSiteDescriptor();
    -        final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
    -        if ("setProp".equals(operator) || "setElem".equals(operator)) {
    -            final MethodType type = desc.getMethodType();
    -            MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1)));
    -            if (type.parameterCount() == 3) {
    -                method = MH.dropArguments(method, 2, type.parameterType(2));
    -            }
    -            return new GuardedInvocation(method, guard);
    -        }
     
             if(desc.getNameTokenCount() > 2) {
                 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
    @@ -102,7 +92,7 @@ public final class PrimitiveLookup {
                 if(find == null) {
                     // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
                     return null;
    -            } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
    +            } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
                     // If property is found in the prototype object bind the method handle directly to
                     // the proto filter instead of going through wrapper instantiation below.
                     final ScriptObject proto = wrappedReceiver.getProto();
    diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java
    index 2c8f7951b30..58ab97c1896 100644
    --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java
    +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java
    @@ -246,7 +246,7 @@ public class Shell {
     
                 // For each file on the command line.
                 for (final String fileName : files) {
    -                final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors, env._strict, FunctionNode.FIRST_FUNCTION_ID, 0, context.getLogger(Parser.class)).parse();
    +                final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors, env._strict, 0, context.getLogger(Parser.class)).parse();
     
                     if (errors.getNumberOfErrors() != 0) {
                         return COMPILATION_ERROR;
    diff --git a/nashorn/test/script/basic/JDK-8030182_2.js b/nashorn/test/script/basic/JDK-8030182_2.js
    index 9ad8f31bae5..4c2f5c429f6 100644
    --- a/nashorn/test/script/basic/JDK-8030182_2.js
    +++ b/nashorn/test/script/basic/JDK-8030182_2.js
    @@ -41,6 +41,6 @@ str +="g()";
     try {
         eval(str);
     } catch (e) {
    -    print(e.stack.replace(/\\/g, '/').replace(/@[0-9]+/, '@'));
    +    print(e.stack.replace(/\\/g, '/'));
     }
     
    diff --git a/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED b/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED
    index 9fdd913f12d..afc582e964c 100644
    --- a/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED
    +++ b/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED
    @@ -1,3 +1,3 @@
     ReferenceError: "g" is not defined
    -	at  (test/script/basic/JDK-8030182_2.js#42:4@:-1)
    +	at  (test/script/basic/JDK-8030182_2.js#42:4:-1)
     	at  (test/script/basic/JDK-8030182_2.js:42)
    diff --git a/nashorn/test/script/basic/JDK-8048079_1.js b/nashorn/test/script/basic/JDK-8048079_1a.js
    similarity index 97%
    rename from nashorn/test/script/basic/JDK-8048079_1.js
    rename to nashorn/test/script/basic/JDK-8048079_1a.js
    index 36a1fe6b78f..8d37e19e3aa 100644
    --- a/nashorn/test/script/basic/JDK-8048079_1.js
    +++ b/nashorn/test/script/basic/JDK-8048079_1a.js
    @@ -25,11 +25,10 @@
      * JDK-8048079: Persistent code store is broken after optimistic types merge
      *
      * @test
    - * @run
    + * @runif external.prototype
      * @option -pcc
      * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
      * @fork
      */
     
     load(__DIR__ + 'prototype.js');
    -load(__DIR__ + 'yui.js');
    diff --git a/nashorn/test/script/basic/JDK-8048079_1a.js.EXPECTED b/nashorn/test/script/basic/JDK-8048079_1a.js.EXPECTED
    new file mode 100644
    index 00000000000..e677550c981
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8048079_1a.js.EXPECTED
    @@ -0,0 +1 @@
    +parsed and compiled ok prototype.js
    diff --git a/nashorn/test/script/basic/JDK-8048079_2.js b/nashorn/test/script/basic/JDK-8048079_1b.js
    similarity index 96%
    rename from nashorn/test/script/basic/JDK-8048079_2.js
    rename to nashorn/test/script/basic/JDK-8048079_1b.js
    index 36a1fe6b78f..8106e1e4877 100644
    --- a/nashorn/test/script/basic/JDK-8048079_2.js
    +++ b/nashorn/test/script/basic/JDK-8048079_1b.js
    @@ -25,11 +25,10 @@
      * JDK-8048079: Persistent code store is broken after optimistic types merge
      *
      * @test
    - * @run
    + * @runif external.yui
      * @option -pcc
      * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
      * @fork
      */
     
    -load(__DIR__ + 'prototype.js');
     load(__DIR__ + 'yui.js');
    diff --git a/nashorn/test/script/basic/JDK-8048079_2.js.EXPECTED b/nashorn/test/script/basic/JDK-8048079_1b.js.EXPECTED
    similarity index 64%
    rename from nashorn/test/script/basic/JDK-8048079_2.js.EXPECTED
    rename to nashorn/test/script/basic/JDK-8048079_1b.js.EXPECTED
    index 371f63a54d5..28dd1b9d2c0 100644
    --- a/nashorn/test/script/basic/JDK-8048079_2.js.EXPECTED
    +++ b/nashorn/test/script/basic/JDK-8048079_1b.js.EXPECTED
    @@ -1,3 +1,2 @@
    -parsed and compiled ok prototype.js
     parsed and compiled ok yui-min.js
     parsed and compiled ok yui.js
    diff --git a/nashorn/test/script/basic/JDK-8048079_2a.js b/nashorn/test/script/basic/JDK-8048079_2a.js
    new file mode 100644
    index 00000000000..7d08c0042fb
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8048079_2a.js
    @@ -0,0 +1,34 @@
    +/*
    + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8048079: Persistent code store is broken after optimistic types merge.
    + * Same script as JDK-8048079_1a.js to exercise code cache.
    + * @test
    + * @runif external.prototype
    + * @option -pcc
    + * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
    + * @fork
    + */
    +
    +load(__DIR__ + 'prototype.js');
    diff --git a/nashorn/test/script/basic/JDK-8048079_2a.js.EXPECTED b/nashorn/test/script/basic/JDK-8048079_2a.js.EXPECTED
    new file mode 100644
    index 00000000000..e677550c981
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8048079_2a.js.EXPECTED
    @@ -0,0 +1 @@
    +parsed and compiled ok prototype.js
    diff --git a/nashorn/test/script/basic/JDK-8048079_2b.js b/nashorn/test/script/basic/JDK-8048079_2b.js
    new file mode 100644
    index 00000000000..60287a243b6
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8048079_2b.js
    @@ -0,0 +1,34 @@
    +/*
    + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8048079: Persistent code store is broken after optimistic types merge
    + * Same script as JDK-8048079_1b.js to exercise code cache again.
    + * @test
    + * @runif external.yui
    + * @option -pcc
    + * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
    + * @fork
    + */
    +
    +load(__DIR__ + 'yui.js');
    diff --git a/nashorn/test/script/basic/JDK-8048079_1.js.EXPECTED b/nashorn/test/script/basic/JDK-8048079_2b.js.EXPECTED
    similarity index 64%
    rename from nashorn/test/script/basic/JDK-8048079_1.js.EXPECTED
    rename to nashorn/test/script/basic/JDK-8048079_2b.js.EXPECTED
    index 371f63a54d5..28dd1b9d2c0 100644
    --- a/nashorn/test/script/basic/JDK-8048079_1.js.EXPECTED
    +++ b/nashorn/test/script/basic/JDK-8048079_2b.js.EXPECTED
    @@ -1,3 +1,2 @@
    -parsed and compiled ok prototype.js
     parsed and compiled ok yui-min.js
     parsed and compiled ok yui.js
    diff --git a/nashorn/test/script/basic/JDK-8058179.js b/nashorn/test/script/basic/JDK-8058179.js
    new file mode 100644
    index 00000000000..1ecd823d8be
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8058179.js
    @@ -0,0 +1,48 @@
    +/*
    + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + * 
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + * 
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + * 
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + * 
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8058179: Global constants get in the way of self-modifying properties
    + *
    + * @test
    + * @run
    + */
    +
    +var global = this;
    +
    +Object.defineProperty(global, "value", {
    +    get: function() {
    +        print("getting value");
    +        global["value"] = "value 2";
    +        return "value 1";
    +    },
    +    set: function(value) {
    +        print("setting value: " + value);
    +        delete global["value"];
    +        global["value"] = value;
    +    },
    +    configurable: true
    +});
    +
    +print(value);
    +print(value);
    diff --git a/nashorn/test/script/basic/JDK-8058179.js.EXPECTED b/nashorn/test/script/basic/JDK-8058179.js.EXPECTED
    new file mode 100644
    index 00000000000..6d8ed6f6eac
    --- /dev/null
    +++ b/nashorn/test/script/basic/JDK-8058179.js.EXPECTED
    @@ -0,0 +1,4 @@
    +getting value
    +setting value: value 2
    +value 1
    +value 2
    diff --git a/nashorn/test/script/basic/es6/const-empty.js.EXPECTED b/nashorn/test/script/basic/es6/const-empty.js.EXPECTED
    index 00a4ccd9b01..d3684a893aa 100644
    --- a/nashorn/test/script/basic/es6/const-empty.js.EXPECTED
    +++ b/nashorn/test/script/basic/es6/const-empty.js.EXPECTED
    @@ -1,3 +1,3 @@
    -SyntaxError: test/script/basic/es6/const-empty.js#33:4@1:2:7 Missing assignment to constant "x"
    +SyntaxError: test/script/basic/es6/const-empty.js#33:4:2:7 Missing assignment to constant "x"
     const x;
            ^
    diff --git a/nashorn/test/script/basic/es6/const-redeclare-extra.js b/nashorn/test/script/basic/es6/const-redeclare-extra.js
    new file mode 100644
    index 00000000000..6d77e18e5ca
    --- /dev/null
    +++ b/nashorn/test/script/basic/es6/const-redeclare-extra.js
    @@ -0,0 +1,59 @@
    +/*
    + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + * 
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + * 
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + * 
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + * 
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8057678: Tests for let&const keywords in Nashorn
    + *
    + * @test
    + * @run
    + * @option --language=es6
    + * @option -scripting
    + */
    +
    +
    +function tryIt (code) {
    +    try {
    +        eval(code)
    +    } catch (e) {
    +        print(e)
    +    }
    +}
    +
    +tryIt(<:3:8 Variable "x" has already been declared
    +    var x = {};
    +        ^
    +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:8 Variable "x" has already been declared
    +    var x = 2;
    +        ^
    +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:13 Variable "x" has already been declared
    +    function x () {}
    +             ^
    diff --git a/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED b/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED
    index ed7711a9b9e..44b6a70fd9a 100644
    --- a/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED
    +++ b/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED
    @@ -1,3 +1,3 @@
    -SyntaxError: test/script/basic/es6/const-redeclare.js#33:4@1:2:6 Variable "x" has already been declared
    +SyntaxError: test/script/basic/es6/const-redeclare.js#33:4:2:6 Variable "x" has already been declared
     const x = 2;
           ^
    diff --git a/nashorn/test/script/basic/es6/let-redeclare-extra.js b/nashorn/test/script/basic/es6/let-redeclare-extra.js
    new file mode 100644
    index 00000000000..630513f4ed3
    --- /dev/null
    +++ b/nashorn/test/script/basic/es6/let-redeclare-extra.js
    @@ -0,0 +1,70 @@
    +/*
    + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + * 
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + * 
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + * 
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + * 
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8057678: Tests for let&const keywords in Nashorn
    + *
    + * @test
    + * @run
    + * @option --language=es6
    + * @option -scripting
    + */
    +
    +function tryIt (code) {
    +    try {
    +        eval(code)
    +    } catch (e) {
    +        print(e)
    +    }
    +}
    +
    +tryIt(<:2:8 Variable "x" has already been declared
    +    let x = 2;
    +        ^
    +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:8 Variable "x" has already been declared
    +    var x = 2;
    +        ^
    +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variable "x" has already been declared
    +    var x = 2;
    +        ^
    +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:10 Variable "x" has already been declared
    +    const x = function (){};
    +          ^
    +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:13 Variable "a" has already been declared
    +    function a () {};
    +             ^
    diff --git a/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED b/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
    index 5f603e3dd30..299e35ef3fc 100644
    --- a/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
    +++ b/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
    @@ -1,3 +1,3 @@
    -SyntaxError: test/script/basic/es6/let-redeclare.js#33:4@1:2:4 Variable "x" has already been declared
    +SyntaxError: test/script/basic/es6/let-redeclare.js#33:4:2:4 Variable "x" has already been declared
     let x = 2;
         ^
    diff --git a/nashorn/test/script/basic/es6/let_const_closure.js b/nashorn/test/script/basic/es6/let_const_closure.js
    new file mode 100644
    index 00000000000..43da4713bd7
    --- /dev/null
    +++ b/nashorn/test/script/basic/es6/let_const_closure.js
    @@ -0,0 +1,123 @@
    +/*
    + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8057678: Tests for let&const keywords in Nashorn
    + *
    + * @test
    + * @run
    + * @option --language=es6
    + * @option -scripting
    + */
    +
    +function tryIt(code) {
    +    try {
    +        eval(code)
    +    } catch (e) {
    +        print(e)
    +    }
    +}
    +
    +
    +tryIt(<:3:8 Assignment to constant "a"
    +        a--
    +        ^
    +SyntaxError: test/script/basic/es6/let_const_reuse.js#35:9:3:8 Assignment to constant "a"
    +        a--
    +        ^
    +ReferenceError: "a" is not defined
    diff --git a/nashorn/test/script/basic/es6/let_different_types.js b/nashorn/test/script/basic/es6/let_different_types.js
    new file mode 100644
    index 00000000000..39ff246dd9a
    --- /dev/null
    +++ b/nashorn/test/script/basic/es6/let_different_types.js
    @@ -0,0 +1,73 @@
    +/*
    + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + * 
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + * 
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + * 
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + * 
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * JDK-8057678: Tests for let&const keywords in Nashorn
    + *
    + * @test
    + * @run
    + * @option --language=es6
    + * @option -scripting
    + */
    +
    +function tryIt (code) {
    +    try {
    +        eval(code)
    +    } catch (e) {
    +        print(e)
    +    }
    +}
    +
    +tryIt(< 0);
    +      print(a)
    +      print(b)
    +CODE)
    +
    +tryIt(< 0) {
    +            a--
    +            let b = a
    +       }
    +       print(a)
    +       print(b)
    +CODE)
    +
    +tryIt(< 0) {
    +            a--
    +            const b = a
    +       }
    +       print(a)
    +       print(b)
    +CODE)
    +
    +tryIt(< 0);
    +       print(a)
    +       print(b)
    +CODE)
    diff --git a/nashorn/test/script/basic/es6/let_loops.js.EXPECTED b/nashorn/test/script/basic/es6/let_loops.js.EXPECTED
    new file mode 100644
    index 00000000000..8a0c63e585b
    --- /dev/null
    +++ b/nashorn/test/script/basic/es6/let_loops.js.EXPECTED
    @@ -0,0 +1,8 @@
    +0
    +ReferenceError: "b" is not defined
    +0
    +ReferenceError: "b" is not defined
    +0
    +ReferenceError: "b" is not defined
    +0
    +ReferenceError: "b" is not defined
    diff --git a/nashorn/test/script/basic/optimistic_check_type.js b/nashorn/test/script/basic/optimistic_check_type.js
    index d2b50a4c3fb..67e27c22fc5 100644
    --- a/nashorn/test/script/basic/optimistic_check_type.js
    +++ b/nashorn/test/script/basic/optimistic_check_type.js
    @@ -36,13 +36,18 @@ var trees = new Array("redwood", "bay", "cedar", "oak");
     
     // Testing conditional operator
     print(inspect("" ? b : x.a, "ternary operator"))
    -print(inspect(x.b ? b : x.a, "ternary operator"))
    -print(inspect(c ? b : a, "ternary operator"))
    -print(inspect(!c ? b : a, "ternary operator"))
    -print(inspect(d ? b : x.c, "ternary operator"))
    +var b1 = b;
    +print(inspect(x.b ? b1 : x.a, "ternary operator"))
    +var b2 = b;
    +print(inspect(c ? b2 : a, "ternary operator"))
    +var b3 = b;
    +print(inspect(!c ? b3 : a, "ternary operator"))
    +var b4 = b;
    +print(inspect(d ? b4 : x.c, "ternary operator"))
     print(inspect(x.c ? a : c, "ternary operator"))
     print(inspect(c ? d : a, "ternary operator"))
    -print(inspect(c ? +a : b, "ternary operator"))
    +var b5 = b;
    +print(inspect(c ? +a : b5, "ternary operator"))
     
     // Testing format methods
     print(inspect(b.toFixed(2), "global double toFixed()"))
    @@ -53,11 +58,14 @@ print(inspect(b.toExponential(2), "global double toExponential()"))
     print(inspect(trees[1], "member object"))
     trees[1] = undefined;
     print(inspect(trees[1], "member undefined"))
    -print(inspect(1 in trees ? b : a, "conditional on array member"))
    +var b6=b;
    +print(inspect(1 in trees ? b6 : a, "conditional on array member"))
     delete trees[2]
    -print(inspect(2 in trees ? b : a, "conditional on array member"))
    +var b7=b;
    +print(inspect(2 in trees ? b7 : a, "conditional on array member"))
     print(inspect(3 in trees ? trees[2]="bay" : a, "conditional on array member"))
    -print(inspect("oak" in trees ? b : a, "conditional on array member"))
    +var b8=b;
    +print(inspect("oak" in trees ? b8 : a, "conditional on array member"))
     
     // Testing nested functions and return value
     function f1() {
    diff --git a/nashorn/test/script/basic/splitter.js b/nashorn/test/script/basic/splitter.js
    index 5637b274e22..395e7505a6e 100644
    --- a/nashorn/test/script/basic/splitter.js
    +++ b/nashorn/test/script/basic/splitter.js
    @@ -30,7 +30,5 @@
      * @fork
      */
     
    -load(__DIR__ + 'prototype.js');
    -load(__DIR__ + 'yui.js');
     load(__DIR__ + 'NASHORN-689.js');
     load(__DIR__ + 'NASHORN-58.js');
    diff --git a/nashorn/test/script/basic/splitter.js.EXPECTED b/nashorn/test/script/basic/splitter.js.EXPECTED
    index dafab972491..51ea8615119 100644
    --- a/nashorn/test/script/basic/splitter.js.EXPECTED
    +++ b/nashorn/test/script/basic/splitter.js.EXPECTED
    @@ -1,6 +1,3 @@
    -parsed and compiled ok prototype.js
    -parsed and compiled ok yui-min.js
    -parsed and compiled ok yui.js
     a=10
     a=9
     a=8
    diff --git a/nashorn/test/script/basic/splitter_prototype.js b/nashorn/test/script/basic/splitter_prototype.js
    new file mode 100644
    index 00000000000..ae97616fb99
    --- /dev/null
    +++ b/nashorn/test/script/basic/splitter_prototype.js
    @@ -0,0 +1,33 @@
    +/*
    + * Copyright (c) 2010, 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 various scripts with low splitter threshold
    + *
    + * @test
    + * @option -Dnashorn.compiler.splitter.threshold=200
    + * @runif external.prototype
    + * @fork
    + */
    +
    +load(__DIR__ + 'prototype.js');
    diff --git a/nashorn/test/script/basic/splitter_prototype.js.EXPECTED b/nashorn/test/script/basic/splitter_prototype.js.EXPECTED
    new file mode 100644
    index 00000000000..e677550c981
    --- /dev/null
    +++ b/nashorn/test/script/basic/splitter_prototype.js.EXPECTED
    @@ -0,0 +1 @@
    +parsed and compiled ok prototype.js
    diff --git a/nashorn/test/script/basic/splitter_yui.js b/nashorn/test/script/basic/splitter_yui.js
    new file mode 100644
    index 00000000000..e03f53b9d8c
    --- /dev/null
    +++ b/nashorn/test/script/basic/splitter_yui.js
    @@ -0,0 +1,33 @@
    +/*
    + * Copyright (c) 2010, 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 various scripts with low splitter threshold
    + *
    + * @test
    + * @option -Dnashorn.compiler.splitter.threshold=200
    + * @runif external.yui
    + * @fork
    + */
    +
    +load(__DIR__ + 'yui.js');
    diff --git a/nashorn/test/script/basic/splitter_yui.js.EXPECTED b/nashorn/test/script/basic/splitter_yui.js.EXPECTED
    new file mode 100644
    index 00000000000..28dd1b9d2c0
    --- /dev/null
    +++ b/nashorn/test/script/basic/splitter_yui.js.EXPECTED
    @@ -0,0 +1,2 @@
    +parsed and compiled ok yui-min.js
    +parsed and compiled ok yui.js
    diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
    index dfec1600db9..865c97d6fdf 100644
    --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
    +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
    @@ -407,6 +407,75 @@ public class ScopeTest {
             Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
         }
     
    +
    +    /**
    +     * Test multi-threaded access to prototype user accessor properties for shared script classes with multiple globals.
    +     */
    +    @Test
    +    public static void multiThreadedAccessorTest() throws ScriptException, InterruptedException {
    +        final ScriptEngineManager m = new ScriptEngineManager();
    +        final ScriptEngine e = m.getEngineByName("nashorn");
    +        final Bindings b = e.createBindings();
    +        final ScriptContext origContext = e.getContext();
    +        final ScriptContext newCtxt = new SimpleScriptContext();
    +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
    +
    +        e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'original context' })", origContext);
    +        e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'new context', configurable: true })", newCtxt);
    +        final String sharedScript = "({}).foo";
    +
    +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
    +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
    +        t1.start();
    +        t2.start();
    +        t1.join();
    +        t2.join();
    +
    +        final Object obj3 = e.eval("delete Object.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
    +        assertEquals(obj3, "newer context");
    +        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
    +        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
    +
    +        t3.start();
    +        t4.start();
    +        t3.join();
    +        t4.join();
    +    }
    +
    +    /**
    +     * Test multi-threaded access to primitive prototype user accessor properties for shared script classes with multiple globals.
    +     */
    +    @Test
    +    public static void multiThreadedPrimitiveAccessorTest() throws ScriptException, InterruptedException {
    +        final ScriptEngineManager m = new ScriptEngineManager();
    +        final ScriptEngine e = m.getEngineByName("nashorn");
    +        final Bindings b = e.createBindings();
    +        final ScriptContext origContext = e.getContext();
    +        final ScriptContext newCtxt = new SimpleScriptContext();
    +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
    +
    +        e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'original context' })", origContext);
    +        e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'new context' })", newCtxt);
    +        final String sharedScript = "''.foo";
    +
    +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
    +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
    +        t1.start();
    +        t2.start();
    +        t1.join();
    +        t2.join();
    +
    +        final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
    +        assertEquals(obj3, "newer context");
    +        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
    +        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
    +
    +        t3.start();
    +        t4.start();
    +        t3.join();
    +        t4.join();
    +    }
    +
         /**
          * Test multi-threaded scope function invocation for shared script classes with multiple globals.
          */
    diff --git a/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
    index b711aad19e4..4a96a4ae2e7 100644
    --- a/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
    +++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
    @@ -261,14 +261,17 @@ final class TestFinder {
                         isTest = false;
                         isNotTest = true;
                         break;
    -                case "@runif":
    -                    if (System.getProperty(scanner.next()) != null) {
    +                case "@runif": {
    +                    final String prop = scanner.next();
    +                    if (System.getProperty(prop) != null) {
                             shouldRun = true;
                         } else {
    +                        factory.log("WARNING: (" + prop + ") skipping " + testFile);
                             isTest = false;
                             isNotTest = true;
                         }
                         break;
    +                }
                     case "@run":
                         shouldRun = true;
                         break;