diff --git a/.hgtags b/.hgtags index 21ee327289c..0eced0f9e0d 100644 --- a/.hgtags +++ b/.hgtags @@ -356,3 +356,4 @@ c870cb782aca71093d2584376f27f0cfbfec0e3a jdk-9+109 a6614ff7bf09da74be1d0ef3d9755090d244697a jdk-9+111 7359994942f8d8e723b584d66a3a92c2e9e95e5c jdk-9+112 6072af7a98be3922f26bdce71b53bb3646cb2ac9 jdk-9+113 +c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 827538cea99..e13ddc6f1e0 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -356,3 +356,4 @@ c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108 f900d5afd9c83a0df8f36161c27c5e4c86a66f4c jdk-9+111 03543a758cd5890f2266e4b9678378a925dde22a jdk-9+112 55b6d550828d1223b364e6ead4a56e56411c56df jdk-9+113 +1d992540870ff33fe6cc550443388588df9b9e4f jdk-9+114 diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 91bf548fbf8..b27cb9a0b70 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -305,7 +305,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], BOOT_JDK_SOURCETARGET="-source 8 -target 8" AC_SUBST(BOOT_JDK_SOURCETARGET) - ADD_JVM_ARG_IF_OK([-Xpatch:], dummy, [$JAVA]) + ADD_JVM_ARG_IF_OK([-Xpatch:foo=bar], dummy, [$JAVA]) AC_MSG_CHECKING([if Boot JDK supports modules]) if test "x$JVM_ARG_OK" = "xtrue"; then AC_MSG_RESULT([yes]) @@ -444,9 +444,9 @@ AC_DEFUN([BOOTJDK_CHECK_BUILD_JDK], BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1` # Extra M4 quote needed to protect [] in grep expression. - [FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep '\"1\.[9]\.'`] + [FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | $EGREP '\"9([\.+-].*)?\"'`] if test "x$FOUND_CORRECT_VERSION" = x; then - AC_MSG_NOTICE([Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring]) + AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring]) AC_MSG_NOTICE([(Your Build JDK must be version 9)]) BUILD_JDK_FOUND=no else diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index a3c69e02d08..06348d0da00 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -454,7 +454,7 @@ AC_DEFUN_ONCE([BPERF_SETUP_SMART_JAVAC], AC_MSG_RESULT([$ENABLE_JAVAC_SERVER]) AC_SUBST(ENABLE_JAVAC_SERVER) - if test "x$ENABLE_JAVAC_SERVER" = "xyes" || "x$ENABLE_SJAVAC" = "xyes"; then + if test "x$ENABLE_JAVAC_SERVER" = "xyes" || test "x$ENABLE_SJAVAC" = "xyes"; then # When using a server javac, the small client instances do not need much # resources. JAVA_FLAGS_JAVAC="$JAVA_FLAGS_SMALL" diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index c7bab7c53a8..1f0c414e102 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -227,6 +227,7 @@ LIB_SETUP_LIBRARIES HOTSPOT_SETUP_BUILD_TWEAKS JDKOPT_DETECT_INTREE_EC +JDKOPT_ENABLE_DISABLE_FAILURE_HANDLER ############################################################################### # diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 0c503ce2be9..d6b14430edc 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -650,6 +650,7 @@ TEST_JOBS JOBS MEMORY_SIZE NUM_CORES +BUILD_FAILURE_HANDLER ENABLE_INTREE_EC HOTSPOT_MAKE_ARGS LIBZIP_CAN_USE_MMAP @@ -1172,6 +1173,7 @@ with_lcms with_dxsdk with_dxsdk_lib with_dxsdk_include +enable_jtreg_failure_handler with_num_cores with_memory_size with_jobs @@ -1940,6 +1942,12 @@ Optional Features: disable bundling of the freetype library with the build result [enabled on Windows or when using --with-freetype, disabled otherwise] + --enable-jtreg-failure-handler + forces build of the jtreg failure handler to be + enabled, missing dependencies become fatal errors. + Default is auto, where the failure handler is built + if all dependencies are present and otherwise just + disabled. --enable-sjavac use sjavac to do fast incremental compiles [disabled] --disable-javac-server disable javac server [enabled] @@ -4274,6 +4282,12 @@ pkgadd_help() { # +################################################################################ +# +# Check if building of the jtreg failure handler should be enabled. +# + + # # Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4950,7 +4964,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1458755892 +DATE_WHEN_GENERATED=1460963400 ############################################################################### # @@ -29770,13 +29784,13 @@ $as_echo "$tool_specified" >&6; } - $ECHO "Check if jvm arg is ok: -Xpatch:" >&5 - $ECHO "Command: $JAVA -Xpatch: -version" >&5 - OUTPUT=`$JAVA -Xpatch: -version 2>&1` + $ECHO "Check if jvm arg is ok: -Xpatch:foo=bar" >&5 + $ECHO "Command: $JAVA -Xpatch:foo=bar -version" >&5 + OUTPUT=`$JAVA -Xpatch:foo=bar -version 2>&1` FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - dummy="$dummy -Xpatch:" + dummy="$dummy -Xpatch:foo=bar" JVM_ARG_OK=true else $ECHO "Arg failed:" >&5 @@ -29856,10 +29870,10 @@ $as_echo "$as_me: (This might be a JRE instead of an JDK)" >&6;} BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1` # Extra M4 quote needed to protect [] in grep expression. - FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep '\"1\.[9]\.'` + FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | $EGREP '\"9([\.+-].*)?\"'` if test "x$FOUND_CORRECT_VERSION" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&5 -$as_echo "$as_me: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&5 +$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: (Your Build JDK must be version 9)" >&5 $as_echo "$as_me: (Your Build JDK must be version 9)" >&6;} BUILD_JDK_FOUND=no @@ -62037,6 +62051,45 @@ $as_echo "no" >&6; } + # Check whether --enable-jtreg-failure-handler was given. +if test "${enable_jtreg_failure_handler+set}" = set; then : + enableval=$enable_jtreg_failure_handler; +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if jtreg failure handler should be built" >&5 +$as_echo_n "checking if jtreg failure handler should be built... " >&6; } + + if test "x$enable_jtreg_failure_handler" = "xyes"; then + if test "x$JT_HOME" = "x"; then + as_fn_error $? "Cannot enable jtreg failure handler without jtreg." "$LINENO" 5 + else + BUILD_FAILURE_HANDLER=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5 +$as_echo "yes, forced" >&6; } + fi + elif test "x$enable_jtreg_failure_handler" = "xno"; then + BUILD_FAILURE_HANDLER=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 +$as_echo "no, forced" >&6; } + elif test "x$enable_jtreg_failure_handler" = "xauto" \ + || test "x$enable_jtreg_failure_handler" = "x"; then + if test "x$JT_HOME" = "x"; then + BUILD_FAILURE_HANDLER=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, missing jtreg" >&5 +$as_echo "no, missing jtreg" >&6; } + else + BUILD_FAILURE_HANDLER=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, jtreg present" >&5 +$as_echo "yes, jtreg present" >&6; } + fi + else + as_fn_error $? "Invalid value for --enable-jtreg-failure-handler: $enable_jtreg_failure_handler" "$LINENO" 5 + fi + + + + ############################################################################### # # Configure parts of the build that only affect the build performance, @@ -62510,7 +62563,7 @@ $as_echo_n "checking whether to use javac server... " >&6; } $as_echo "$ENABLE_JAVAC_SERVER" >&6; } - if test "x$ENABLE_JAVAC_SERVER" = "xyes" || "x$ENABLE_SJAVAC" = "xyes"; then + if test "x$ENABLE_JAVAC_SERVER" = "xyes" || test "x$ENABLE_SJAVAC" = "xyes"; then # When using a server javac, the small client instances do not need much # resources. JAVA_FLAGS_JAVAC="$JAVA_FLAGS_SMALL" diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 3c677d8adde..4937c6b1ad1 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -408,7 +408,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_BUILD], ################################################################################ # -# jlink options. +# jlink options. # We always keep packaged modules in JDK image. # AC_DEFUN_ONCE([JDKOPT_SETUP_JLINK_OPTIONS], @@ -433,3 +433,42 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JLINK_OPTIONS], AC_SUBST(JLINK_KEEP_PACKAGED_MODULES) ]) + +################################################################################ +# +# Check if building of the jtreg failure handler should be enabled. +# +AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_FAILURE_HANDLER], +[ + AC_ARG_ENABLE([jtreg-failure-handler], [AS_HELP_STRING([--enable-jtreg-failure-handler], + [forces build of the jtreg failure handler to be enabled, missing dependencies + become fatal errors. Default is auto, where the failure handler is built if all + dependencies are present and otherwise just disabled.])]) + + AC_MSG_CHECKING([if jtreg failure handler should be built]) + + if test "x$enable_jtreg_failure_handler" = "xyes"; then + if test "x$JT_HOME" = "x"; then + AC_MSG_ERROR([Cannot enable jtreg failure handler without jtreg.]) + else + BUILD_FAILURE_HANDLER=true + AC_MSG_RESULT([yes, forced]) + fi + elif test "x$enable_jtreg_failure_handler" = "xno"; then + BUILD_FAILURE_HANDLER=false + AC_MSG_RESULT([no, forced]) + elif test "x$enable_jtreg_failure_handler" = "xauto" \ + || test "x$enable_jtreg_failure_handler" = "x"; then + if test "x$JT_HOME" = "x"; then + BUILD_FAILURE_HANDLER=false + AC_MSG_RESULT([no, missing jtreg]) + else + BUILD_FAILURE_HANDLER=true + AC_MSG_RESULT([yes, jtreg present]) + fi + else + AC_MSG_ERROR([Invalid value for --enable-jtreg-failure-handler: $enable_jtreg_failure_handler]) + fi + + AC_SUBST(BUILD_FAILURE_HANDLER) +]) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 0af5e6d0e2d..3b6cbd5cbaa 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -260,6 +260,8 @@ HOTSPOT_DIST=@HOTSPOT_DIST@ BUILD_HOTSPOT=@BUILD_HOTSPOT@ +BUILD_FAILURE_HANDLER := @BUILD_FAILURE_HANDLER@ + # The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep # it in sync. BOOT_JDK:=@BOOT_JDK@ diff --git a/common/bin/compare.sh b/common/bin/compare.sh index e46c9f306ff..db73426481d 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -41,7 +41,7 @@ if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then STAT_PRINT_SIZE="-f %z" elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then FULLDUMP_CMD="$DUMPBIN -all" - LDD_CMD="$DUMPBIN -dependants | $GREP .dll" + LDD_CMD="$DUMPBIN -dependents" DIS_CMD="$DUMPBIN -disasm:nobytes" STAT_PRINT_SIZE="-c %s" elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then @@ -824,12 +824,25 @@ compare_bin_file() { # Check dependencies if [ -n "$LDD_CMD" ]; then - (cd $FILE_WORK_DIR && $CP $OTHER_FILE . && $LDD_CMD $NAME 2>/dev/null | $AWK '{ print $1;}' | $SORT | $TEE $WORK_FILE_BASE.deps.other | $UNIQ > $WORK_FILE_BASE.deps.other.uniq) - (cd $FILE_WORK_DIR && $CP $THIS_FILE . && $LDD_CMD $NAME 2 $WORK_FILE_BASE.deps.this.uniq) + if [ "$OPENJDK_TARGET_OS" = "windows" ]; then + LDD_FILTER="$GREP \.dll" + else + LDD_FILTER="$CAT" + fi + (cd $FILE_WORK_DIR && $CP $OTHER_FILE . && $LDD_CMD $NAME 2>/dev/null \ + | $LDD_FILTER | $AWK '{ print $1;}' | $SORT \ + | $TEE $WORK_FILE_BASE.deps.other \ + | $UNIQ > $WORK_FILE_BASE.deps.other.uniq) + (cd $FILE_WORK_DIR && $CP $THIS_FILE . && $LDD_CMD $NAME 2 $WORK_FILE_BASE.deps.this.uniq) (cd $FILE_WORK_DIR && $RM -f $NAME) - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this > $WORK_FILE_BASE.deps.diff - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq > $WORK_FILE_BASE.deps.diff.uniq + LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this \ + > $WORK_FILE_BASE.deps.diff + LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq \ + > $WORK_FILE_BASE.deps.diff.uniq if [ -s $WORK_FILE_BASE.deps.diff ]; then if [ -s $WORK_FILE_BASE.deps.diff.uniq ]; then diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index a3372cf3fe2..d6f86f2e2ac 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -214,7 +214,7 @@ var getJibProfiles = function (input) { var getJibProfilesCommon = function (input) { var common = { dependencies: ["boot_jdk", "gnumake", "jtreg"], - configure_args: ["--with-default-make-target=all"], + configure_args: ["--with-default-make-target=all", "--enable-jtreg-failure-handler"], configure_args_32bit: ["--with-target-bits=32", "--with-jvm-variants=client,server"], configure_args_debug: ["--enable-debug"], configure_args_slowdebug: ["--with-debug-level=slowdebug"], diff --git a/corba/.hgtags b/corba/.hgtags index c9e18d22968..df49fd73654 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -356,3 +356,4 @@ b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109 2bb92dd44275679edb29fdbffc3b7cbebc9a6bf0 jdk-9+111 780d0620add32bf545471cf65038c9ac6d9c036d jdk-9+112 cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113 +10d175b0368c30f54350fc648adc41b94ce357ee jdk-9+114 diff --git a/corba/src/java.corba/share/classes/sun/corba/Bridge.java b/corba/src/java.corba/share/classes/sun/corba/Bridge.java index 1891612219c..ddc96b21a7c 100644 --- a/corba/src/java.corba/share/classes/sun/corba/Bridge.java +++ b/corba/src/java.corba/share/classes/sun/corba/Bridge.java @@ -37,7 +37,7 @@ import java.security.Permission; import java.security.PrivilegedAction; import jdk.internal.misc.Unsafe ; -import sun.reflect.ReflectionFactory ; +import jdk.internal.reflect.ReflectionFactory; /** This class provides the methods for fundamental JVM operations * needed in the ORB that are not part of the public Java API. This includes: diff --git a/hotspot/.hgtags b/hotspot/.hgtags index c5580667c41..472e5185290 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -516,3 +516,4 @@ c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107 c558850fac5750d8ca98a45180121980f57cdd28 jdk-9+111 76582e8dc9e6374e4f99ab797c8d364b6e9449b4 jdk-9+112 c569f8d89269fb6205b90f727581eb8cc04132f9 jdk-9+113 +b64432bae5271735fd53300b2005b713e98ef411 jdk-9+114 diff --git a/hotspot/make/aix/adlc_updater b/hotspot/make/aix/adlc_updater index 6d31b792c05..99e04e333f2 100644 --- a/hotspot/make/aix/adlc_updater +++ b/hotspot/make/aix/adlc_updater @@ -9,12 +9,15 @@ # fix_lines() { # repair bare #line directives in $1 to refer to $2 - awk < $1 > $1+ ' + # and add an override of __FILE__ with just the basename on the + # first line of the file. + awk < $1 > $1+ -v F2=$2 ' + BEGIN { print "#line 1 \"" F2 "\""; } /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} {print} - ' F2=$2 + ' mv $1+ $1 } -fix_lines $2/$1 $3/$1 +fix_lines $2/$1 $1 [ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ ( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/aix/makefiles/trace.make b/hotspot/make/aix/makefiles/trace.make index 549acb21190..f4f9e7f8e6c 100644 --- a/hotspot/make/aix/makefiles/trace.make +++ b/hotspot/make/aix/makefiles/trace.make @@ -27,14 +27,17 @@ # # It knows how to build and run the tools to generate trace files. -include $(GAMMADIR)/make/linux/makefiles/rules.make +include $(GAMMADIR)/make/aix/makefiles/rules.make include $(GAMMADIR)/make/altsrc.make # ######################################################################### -HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ - echo "true"; else echo "false";\ - fi) +HAS_ALT_SRC := false +ifndef OPENJDK + ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), ) + HAS_ALT_SRC := true + endif +endif TOPDIR = $(shell echo `pwd`) GENERATED = $(TOPDIR)/../generated @@ -50,23 +53,30 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) -TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp + TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen -XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ - $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +TraceXml = $(TraceSrcDir)/trace.xml ifeq ($(HAS_ALT_SRC), true) - XML_DEPS += $(TraceAltSrcDir)/traceevents.xml + TraceXml = $(TraceAltSrcDir)/trace.xml +endif + +XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \ + $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \ + $(TraceAltSrcDir)/traceeventtypes.xml endif .PHONY: all clean cleanall @@ -79,26 +89,26 @@ GENERATE_CODE= \ $(QUIETLY) echo $(LOG_INFO) Generating $@; \ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@ -$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) +$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) $(GENERATE_CODE) ifeq ($(HAS_ALT_SRC), false) -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) else -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) +$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) $(GENERATE_CODE) endif diff --git a/hotspot/make/bsd/adlc_updater b/hotspot/make/bsd/adlc_updater index 6d31b792c05..99e04e333f2 100644 --- a/hotspot/make/bsd/adlc_updater +++ b/hotspot/make/bsd/adlc_updater @@ -9,12 +9,15 @@ # fix_lines() { # repair bare #line directives in $1 to refer to $2 - awk < $1 > $1+ ' + # and add an override of __FILE__ with just the basename on the + # first line of the file. + awk < $1 > $1+ -v F2=$2 ' + BEGIN { print "#line 1 \"" F2 "\""; } /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} {print} - ' F2=$2 + ' mv $1+ $1 } -fix_lines $2/$1 $3/$1 +fix_lines $2/$1 $1 [ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ ( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/bsd/makefiles/trace.make b/hotspot/make/bsd/makefiles/trace.make index 88f17a7326e..af46df58ce0 100644 --- a/hotspot/make/bsd/makefiles/trace.make +++ b/hotspot/make/bsd/makefiles/trace.make @@ -32,9 +32,12 @@ include $(GAMMADIR)/make/altsrc.make # ######################################################################### -HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ - echo "true"; else echo "false";\ - fi) +HAS_ALT_SRC := false +ifndef OPENJDK + ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), ) + HAS_ALT_SRC := true + endif +endif TOPDIR = $(shell echo `pwd`) GENERATED = $(TOPDIR)/../generated @@ -50,24 +53,30 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) -TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp + TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif - TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen -XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ - $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +TraceXml = $(TraceSrcDir)/trace.xml ifeq ($(HAS_ALT_SRC), true) - XML_DEPS += $(TraceAltSrcDir)/traceevents.xml + TraceXml = $(TraceAltSrcDir)/trace.xml +endif + +XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \ + $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \ + $(TraceAltSrcDir)/traceeventtypes.xml endif .PHONY: all clean cleanall @@ -80,32 +89,31 @@ GENERATE_CODE= \ $(QUIETLY) echo $(LOG_INFO) Generating $@; \ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@ -$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) +$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) $(GENERATE_CODE) ifeq ($(HAS_ALT_SRC), false) -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) else -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) +$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) $(GENERATE_CODE) endif # ######################################################################### - clean cleanall: rm $(TraceGeneratedFiles) diff --git a/hotspot/make/linux/adlc_updater b/hotspot/make/linux/adlc_updater index 6d31b792c05..99e04e333f2 100644 --- a/hotspot/make/linux/adlc_updater +++ b/hotspot/make/linux/adlc_updater @@ -9,12 +9,15 @@ # fix_lines() { # repair bare #line directives in $1 to refer to $2 - awk < $1 > $1+ ' + # and add an override of __FILE__ with just the basename on the + # first line of the file. + awk < $1 > $1+ -v F2=$2 ' + BEGIN { print "#line 1 \"" F2 "\""; } /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} {print} - ' F2=$2 + ' mv $1+ $1 } -fix_lines $2/$1 $3/$1 +fix_lines $2/$1 $1 [ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ ( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/linux/makefiles/trace.make b/hotspot/make/linux/makefiles/trace.make index 229b68c434b..09cb921094e 100644 --- a/hotspot/make/linux/makefiles/trace.make +++ b/hotspot/make/linux/makefiles/trace.make @@ -32,9 +32,12 @@ include $(GAMMADIR)/make/altsrc.make # ######################################################################### -HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ - echo "true"; else echo "false";\ - fi) +HAS_ALT_SRC := false +ifndef OPENJDK + ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), ) + HAS_ALT_SRC := true + endif +endif TOPDIR = $(shell echo `pwd`) GENERATED = $(TOPDIR)/../generated @@ -50,23 +53,30 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) -TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp + TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen -XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ - $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +TraceXml = $(TraceSrcDir)/trace.xml ifeq ($(HAS_ALT_SRC), true) - XML_DEPS += $(TraceAltSrcDir)/traceevents.xml + TraceXml = $(TraceAltSrcDir)/trace.xml +endif + +XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \ + $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \ + $(TraceAltSrcDir)/traceeventtypes.xml endif .PHONY: all clean cleanall @@ -79,26 +89,26 @@ GENERATE_CODE= \ $(QUIETLY) echo $(LOG_INFO) Generating $@; \ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@ -$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) +$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) $(GENERATE_CODE) ifeq ($(HAS_ALT_SRC), false) -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) else -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) +$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) $(GENERATE_CODE) endif @@ -107,5 +117,3 @@ endif clean cleanall: rm $(TraceGeneratedFiles) - - diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 120103a04ba..a937f93b84c 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -109,8 +109,7 @@ JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; - JVM_GetStackTraceDepth; - JVM_GetStackTraceElement; + JVM_GetStackTraceElements; JVM_GetSystemPackage; JVM_GetSystemPackages; JVM_GetTemporaryDirectory; diff --git a/hotspot/make/solaris/adlc_updater b/hotspot/make/solaris/adlc_updater index 6d31b792c05..8b1df724e60 100644 --- a/hotspot/make/solaris/adlc_updater +++ b/hotspot/make/solaris/adlc_updater @@ -9,12 +9,15 @@ # fix_lines() { # repair bare #line directives in $1 to refer to $2 - awk < $1 > $1+ ' + # and add an override of __FILE__ with just the basename on the + # first line of the file. + nawk < $1 > $1+ -v F2=$2 ' + BEGIN { print "#line 1 \"" F2 "\""; } /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} {print} - ' F2=$2 + ' mv $1+ $1 } -fix_lines $2/$1 $3/$1 +fix_lines $2/$1 $1 [ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ ( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/solaris/makefiles/trace.make b/hotspot/make/solaris/makefiles/trace.make index 09979558ea7..ed7046295b3 100644 --- a/hotspot/make/solaris/makefiles/trace.make +++ b/hotspot/make/solaris/makefiles/trace.make @@ -32,9 +32,12 @@ include $(GAMMADIR)/make/altsrc.make # ######################################################################### -HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ - echo "true"; else echo "false";\ - fi) +HAS_ALT_SRC := false +ifndef OPENJDK + ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), ) + HAS_ALT_SRC := true + endif +endif TOPDIR = $(shell echo `pwd`) GENERATED = $(TOPDIR)/../generated @@ -50,23 +53,30 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) -TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp + TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen -XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ - $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +TraceXml = $(TraceSrcDir)/trace.xml ifeq ($(HAS_ALT_SRC), true) - XML_DEPS += $(TraceAltSrcDir)/traceevents.xml + TraceXml = $(TraceAltSrcDir)/trace.xml +endif + +XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \ + $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \ + $(TraceAltSrcDir)/traceeventtypes.xml endif .PHONY: all clean cleanall @@ -79,26 +89,26 @@ GENERATE_CODE= \ $(QUIETLY) echo $(LOG_INFO) Generating $@; \ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@ -$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) +$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) $(GENERATE_CODE) ifeq ($(HAS_ALT_SRC), false) -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) else -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) +$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) $(GENERATE_CODE) endif diff --git a/hotspot/make/windows/build.make b/hotspot/make/windows/build.make index 68b31ba2123..603f15c0c0b 100644 --- a/hotspot/make/windows/build.make +++ b/hotspot/make/windows/build.make @@ -114,11 +114,15 @@ VARIANT_TEXT=Tiered # Define HOTSPOT_VM_DISTRO based on settings in make/openjdk_distro # or make/hotspot_distro. !ifndef HOTSPOT_VM_DISTRO +!ifndef OPENJDK !if exists($(WorkSpace)\src\closed) !include $(WorkSpace)\make\hotspot_distro !else !include $(WorkSpace)\make\openjdk_distro !endif +!else +!include $(WorkSpace)\make\openjdk_distro +!endif !endif HS_FILEDESC=$(HOTSPOT_VM_DISTRO) $(ARCH_TEXT) $(VARIANT_TEXT) VM diff --git a/hotspot/make/windows/create_obj_files.sh b/hotspot/make/windows/create_obj_files.sh index cc3d276ff24..685f7f3b0f5 100644 --- a/hotspot/make/windows/create_obj_files.sh +++ b/hotspot/make/windows/create_obj_files.sh @@ -55,7 +55,11 @@ COMMONSRC_REL=src ALTSRC_REL=src/closed # Change this to pick up alt sources from somewhere else COMMONSRC=${WorkSpace}/${COMMONSRC_REL} -ALTSRC=${WorkSpace}/${ALTSRC_REL} +if [ "x$OPENJDK" != "xtrue" ]; then + ALTSRC=${WorkSpace}/${ALTSRC_REL} +else + ALTSRC=PATH_THAT_DOES_NOT_EXIST +fi BASE_PATHS="`if [ -d ${ALTSRC}/share/vm ]; then $FIND ${ALTSRC}/share/vm ! -name vm -prune -type d \! \( -name adlc -o -name c1 -o -name gc -o -name opto -o -name shark -o -name libadt \); fi`" BASE_PATHS="${BASE_PATHS} ` $FIND ${COMMONSRC}/share/vm ! -name vm -prune -type d \! \( -name adlc -o -name c1 -o -name gc -o -name opto -o -name shark -o -name libadt \)`" @@ -158,6 +162,6 @@ for e in ${Src_Files}; do fi Obj_Files="${Obj_Files}$o " done -Obj_Files=`echo ${Obj_Files} | tr ' ' '\n' | sort` +Obj_Files=`echo ${Obj_Files} | tr ' ' '\n' | LC_ALL=C sort` echo Obj_Files=${Obj_Files} diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index cef70861acb..fbbe6f16490 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -276,3 +276,7 @@ ifneq ($(SPEC),) MAKE_ARGS += MT="$(subst /,\\,$(MT))" endif endif + +ifdef OPENJDK + MAKE_ARGS += OPENJDK="$(OPENJDK)" +endif diff --git a/hotspot/make/windows/makefiles/trace.make b/hotspot/make/windows/makefiles/trace.make index b32646e3310..eecc890663f 100644 --- a/hotspot/make/windows/makefiles/trace.make +++ b/hotspot/make/windows/makefiles/trace.make @@ -32,15 +32,21 @@ # ######################################################################### -TraceAltSrcDir = $(WorkSpace)/src/closed/share/vm/trace -TraceSrcDir = $(WorkSpace)/src/share/vm/trace +TraceAltSrcDir = $(WorkSpace)\src\closed\share\vm\trace +TraceSrcDir = $(WorkSpace)\src\share\vm\trace + +!ifndef OPENJDK +!if EXISTS($(TraceAltSrcDir)) +HAS_ALT_SRC = true +!endif +!endif TraceGeneratedNames = \ traceEventClasses.hpp \ traceEventIds.hpp \ traceTypes.hpp -!if EXISTS($(TraceAltSrcDir)) +!ifdef HAS_ALT_SRC TraceGeneratedNames = $(TraceGeneratedNames) \ traceRequestables.hpp \ traceEventControl.hpp @@ -51,22 +57,30 @@ TraceGeneratedNames = $(TraceGeneratedNames) \ #Should be equivalent to "TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)" TraceGeneratedFiles = \ $(TraceOutDir)/traceEventClasses.hpp \ - $(TraceOutDir)/traceEventIds.hpp \ - $(TraceOutDir)/traceTypes.hpp + $(TraceOutDir)/traceEventIds.hpp \ + $(TraceOutDir)/traceTypes.hpp -!if EXISTS($(TraceAltSrcDir)) +!ifdef HAS_ALT_SRC TraceGeneratedFiles = $(TraceGeneratedFiles) \ - $(TraceOutDir)/traceRequestables.hpp \ + $(TraceOutDir)/traceRequestables.hpp \ $(TraceOutDir)/traceEventControl.hpp !endif XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen -XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ - $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +TraceXml = $(TraceSrcDir)/trace.xml -!if EXISTS($(TraceAltSrcDir)) -XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml +!ifdef HAS_ALT_SRC +TraceXml = $(TraceAltSrcDir)/trace.xml +!endif + +XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \ + $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml + +!ifdef HAS_ALT_SRC +XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceeventscustom.xml \ + $(TraceAltSrcDir)/traceeventtypes.xml !endif .PHONY: all clean cleanall @@ -76,33 +90,33 @@ XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml default:: @if not exist $(TraceOutDir) mkdir $(TraceOutDir) -$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) @echo Generating $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp -$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) +$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) @echo Generating $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp -!if !EXISTS($(TraceAltSrcDir)) +!ifndef HAS_ALT_SRC -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) @echo Generating OpenJDK $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp !else -$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventClasses.hpp: $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) @echo Generating AltSrc $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp -$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) +$(TraceOutDir)/traceRequestables.hpp: $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) @echo Generating AltSrc $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp -$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) +$(TraceOutDir)/traceEventControl.hpp: $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) @echo Generating AltSrc $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp + $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp !endif @@ -110,5 +124,3 @@ $(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir) cleanall : rm $(TraceGeneratedFiles) - - diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 0e7b3c13519..fd42111866b 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -118,6 +118,7 @@ LD_FLAGS=$(LD_FLAGS) $(STACK_SIZE) /subsystem:windows /dll /base:0x8000000 $(EXP CXX_INCLUDE_DIRS=/I "..\generated" +!ifndef OPENJDK !if exists($(ALTSRC)\share\vm) CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) /I "$(ALTSRC)\share\vm" !endif @@ -133,6 +134,7 @@ CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) /I "$(ALTSRC)\os_cpu\windows_$(Platform_arc !if exists($(ALTSRC)\cpu\$(Platform_arch)\vm) CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) /I "$(ALTSRC)\cpu\$(Platform_arch)\vm" !endif +!endif # OPENJDK CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) \ /I "$(COMMONSRC)\share\vm" \ @@ -187,10 +189,12 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/os_cpu/windows_$(Platform_arch)/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/cpu/$(Platform_arch)/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/opto +!ifndef OPENJDK !if exists($(ALTSRC)\share\vm\jfr) VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/buffers !endif +!endif # OPENJDK VM_PATH={$(VM_PATH)} @@ -310,6 +314,7 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {$(COMMONSRC)\os_cpu\windows_$(Platform_arch)\vm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +!ifndef OPENJDK {$(ALTSRC)\share\vm\c1}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -392,6 +397,13 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {$(ALTSRC)\os_cpu\windows_$(Platform_arch)\vm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(ALTSRC)\share\vm\jfr}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + +{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +!endif + {..\generated\incls}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -404,12 +416,6 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {..\generated\tracefiles}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< -{$(ALTSRC)\share\vm\jfr}.cpp.obj:: - $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< - -{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj:: - $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< - default:: _build_pch_file.obj: diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 3288fbedfb8..e92411bab18 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -14242,6 +14242,48 @@ instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl ins_pipe(pipe_cmp_branch); %} +instruct cmpUI_imm0_branch(cmpOpU cmp, iRegIorL2I op1, immI0 op2, label labl, rFlagsRegU cr) %{ + match(If cmp (CmpU op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq + || n->in(1)->as_Bool()->_test._test == BoolTest::gt + || n->in(1)->as_Bool()->_test._test == BoolTest::le); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cbw$cmp $op1, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ || cond == Assembler::LS) + __ cbzw($op1$$Register, *L); + else + __ cbnzw($op1$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct cmpUL_imm0_branch(cmpOpU cmp, iRegL op1, immL0 op2, label labl, rFlagsRegU cr) %{ + match(If cmp (CmpU op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq + || n->in(1)->as_Bool()->_test._test == BoolTest::gt + || n->in(1)->as_Bool()->_test._test == BoolTest::le); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $op1, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ || cond == Assembler::LS) + __ cbz($op1$$Register, *L); + else + __ cbnz($op1$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + // Test bit and Branch // Patterns for short (< 32KiB) variants diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp index 85e0f2e4eca..965a5c8072f 100644 --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp @@ -1221,6 +1221,38 @@ public: INSN(caspal, true, true) #undef INSN + // 8.1 Atomic operations + void lse_atomic(Register Rs, Register Rt, Register Rn, + enum operand_size sz, int op1, int op2, bool a, bool r) { + starti; + f(sz, 31, 30), f(0b111000, 29, 24), f(a, 23), f(r, 22), f(1, 21); + rf(Rs, 16), f(op1, 15), f(op2, 14, 12), f(0, 11, 10), rf(Rn, 5), zrf(Rt, 0); + } + +#define INSN(NAME, NAME_A, NAME_L, NAME_AL, op1, op2) \ + void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) { \ + lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, false); \ + } \ + void NAME_A(operand_size sz, Register Rs, Register Rt, Register Rn) { \ + lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, false); \ + } \ + void NAME_L(operand_size sz, Register Rs, Register Rt, Register Rn) { \ + lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, true); \ + } \ + void NAME_AL(operand_size sz, Register Rs, Register Rt, Register Rn) {\ + lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, true); \ + } + INSN(ldadd, ldadda, ldaddl, ldaddal, 0, 0b000); + INSN(ldbic, ldbica, ldbicl, ldbical, 0, 0b001); + INSN(ldeor, ldeora, ldeorl, ldeoral, 0, 0b010); + INSN(ldorr, ldorra, ldorrl, ldorral, 0, 0b011); + INSN(ldsmax, ldsmaxa, ldsmaxl, ldsmaxal, 0, 0b100); + INSN(ldsmin, ldsmina, ldsminl, ldsminal, 0, 0b101); + INSN(ldumax, ldumaxa, ldumaxl, ldumaxal, 0, 0b110); + INSN(ldumin, ldumina, lduminl, lduminal, 0, 0b111); + INSN(swp, swpa, swpl, swpal, 1, 0b000); +#undef INSN + // Load register (literal) #define INSN(NAME, opc, V) \ void NAME(Register Rt, address dest) { \ diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 082c1505466..976e69133bc 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -1556,54 +1556,14 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { } void LIR_Assembler::casw(Register addr, Register newval, Register cmpval) { - if (UseLSE) { - __ mov(rscratch1, cmpval); - __ casal(Assembler::word, rscratch1, newval, addr); - __ cmpw(rscratch1, cmpval); - __ cset(rscratch1, Assembler::NE); - } else { - Label retry_load, nope; - // flush and load exclusive from the memory location - // and fail if it is not what we expect - __ prfm(Address(addr), PSTL1STRM); - __ bind(retry_load); - __ ldaxrw(rscratch1, addr); - __ cmpw(rscratch1, cmpval); - __ cset(rscratch1, Assembler::NE); - __ br(Assembler::NE, nope); - // if we store+flush with no intervening write rscratch1 wil be zero - __ stlxrw(rscratch1, newval, addr); - // retry so we only ever return after a load fails to compare - // ensures we don't return a stale value after a failed write. - __ cbnzw(rscratch1, retry_load); - __ bind(nope); - } + __ cmpxchg(addr, cmpval, newval, Assembler::word, /* acquire*/ true, /* release*/ true, rscratch1); + __ cset(rscratch1, Assembler::NE); __ membar(__ AnyAny); } void LIR_Assembler::casl(Register addr, Register newval, Register cmpval) { - if (UseLSE) { - __ mov(rscratch1, cmpval); - __ casal(Assembler::xword, rscratch1, newval, addr); - __ cmp(rscratch1, cmpval); - __ cset(rscratch1, Assembler::NE); - } else { - Label retry_load, nope; - // flush and load exclusive from the memory location - // and fail if it is not what we expect - __ prfm(Address(addr), PSTL1STRM); - __ bind(retry_load); - __ ldaxr(rscratch1, addr); - __ cmp(rscratch1, cmpval); - __ cset(rscratch1, Assembler::NE); - __ br(Assembler::NE, nope); - // if we store+flush with no intervening write rscratch1 wil be zero - __ stlxr(rscratch1, newval, addr); - // retry so we only ever return after a load fails to compare - // ensures we don't return a stale value after a failed write. - __ cbnz(rscratch1, retry_load); - __ bind(nope); - } + __ cmpxchg(addr, cmpval, newval, Assembler::xword, /* acquire*/ true, /* release*/ true, rscratch1); + __ cset(rscratch1, Assembler::NE); __ membar(__ AnyAny); } @@ -3121,38 +3081,32 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr BasicType type = src->type(); bool is_oop = type == T_OBJECT || type == T_ARRAY; - void (MacroAssembler::* lda)(Register Rd, Register Ra); - void (MacroAssembler::* add)(Register Rd, Register Rn, RegisterOrConstant increment); - void (MacroAssembler::* stl)(Register Rs, Register Rt, Register Rn); + void (MacroAssembler::* add)(Register prev, RegisterOrConstant incr, Register addr); + void (MacroAssembler::* xchg)(Register prev, Register newv, Register addr); switch(type) { case T_INT: - lda = &MacroAssembler::ldaxrw; - add = &MacroAssembler::addw; - stl = &MacroAssembler::stlxrw; + xchg = &MacroAssembler::atomic_xchgalw; + add = &MacroAssembler::atomic_addalw; break; case T_LONG: - lda = &MacroAssembler::ldaxr; - add = &MacroAssembler::add; - stl = &MacroAssembler::stlxr; + xchg = &MacroAssembler::atomic_xchgal; + add = &MacroAssembler::atomic_addal; break; case T_OBJECT: case T_ARRAY: if (UseCompressedOops) { - lda = &MacroAssembler::ldaxrw; - add = &MacroAssembler::addw; - stl = &MacroAssembler::stlxrw; + xchg = &MacroAssembler::atomic_xchgalw; + add = &MacroAssembler::atomic_addalw; } else { - lda = &MacroAssembler::ldaxr; - add = &MacroAssembler::add; - stl = &MacroAssembler::stlxr; + xchg = &MacroAssembler::atomic_xchgal; + add = &MacroAssembler::atomic_addal; } break; default: ShouldNotReachHere(); - lda = &MacroAssembler::ldaxr; - add = &MacroAssembler::add; - stl = &MacroAssembler::stlxr; // unreachable + xchg = &MacroAssembler::atomic_xchgal; + add = &MacroAssembler::atomic_addal; // unreachable } switch (code) { @@ -3170,14 +3124,8 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr assert_different_registers(inc.as_register(), dst, addr.base(), tmp, rscratch1, rscratch2); } - Label again; __ lea(tmp, addr); - __ prfm(Address(tmp), PSTL1STRM); - __ bind(again); - (_masm->*lda)(dst, tmp); - (_masm->*add)(rscratch1, dst, inc); - (_masm->*stl)(rscratch2, rscratch1, tmp); - __ cbnzw(rscratch2, again); + (_masm->*add)(dst, inc, tmp); break; } case lir_xchg: @@ -3186,17 +3134,12 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr Register obj = as_reg(data); Register dst = as_reg(dest); if (is_oop && UseCompressedOops) { - __ encode_heap_oop(rscratch1, obj); - obj = rscratch1; + __ encode_heap_oop(rscratch2, obj); + obj = rscratch2; } - assert_different_registers(obj, addr.base(), tmp, rscratch2, dst); - Label again; + assert_different_registers(obj, addr.base(), tmp, rscratch1, dst); __ lea(tmp, addr); - __ prfm(Address(tmp), PSTL1STRM); - __ bind(again); - (_masm->*lda)(dst, tmp); - (_masm->*stl)(rscratch2, obj, tmp); - __ cbnzw(rscratch2, again); + (_masm->*xchg)(dst, obj, tmp); if (is_oop && UseCompressedOops) { __ decode_heap_oop(dst); } diff --git a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp index 304c2e678bc..f4170aeb85b 100644 --- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp @@ -55,6 +55,7 @@ define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); +define_pd_global(intx, PostLoopMultiversioning, false); // InitialCodeCacheSize derived from specjbb2000 run. define_pd_global(intx, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize define_pd_global(intx, CodeCacheExpansionSize, 64*K); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 691e6bb29c2..0ede2e9847a 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -1637,6 +1637,11 @@ Address MacroAssembler::form_address(Register Rd, Register base, long byte_offse } void MacroAssembler::atomic_incw(Register counter_addr, Register tmp, Register tmp2) { + if (UseLSE) { + mov(tmp, 1); + ldadd(Assembler::word, tmp, zr, counter_addr); + return; + } Label retry_load; prfm(Address(counter_addr), PSTL1STRM); bind(retry_load); @@ -2172,8 +2177,18 @@ static bool different(Register a, RegisterOrConstant b, Register c) { return a != b.as_register() && a != c && b.as_register() != c; } -#define ATOMIC_OP(LDXR, OP, IOP, STXR) \ -void MacroAssembler::atomic_##OP(Register prev, RegisterOrConstant incr, Register addr) { \ +#define ATOMIC_OP(NAME, LDXR, OP, IOP, AOP, STXR, sz) \ +void MacroAssembler::atomic_##NAME(Register prev, RegisterOrConstant incr, Register addr) { \ + if (UseLSE) { \ + prev = prev->is_valid() ? prev : zr; \ + if (incr.is_register()) { \ + AOP(sz, incr.as_register(), prev, addr); \ + } else { \ + mov(rscratch2, incr.as_constant()); \ + AOP(sz, rscratch2, prev, addr); \ + } \ + return; \ + } \ Register result = rscratch2; \ if (prev->is_valid()) \ result = different(prev, incr, addr) ? prev : rscratch2; \ @@ -2190,13 +2205,20 @@ void MacroAssembler::atomic_##OP(Register prev, RegisterOrConstant incr, Registe } \ } -ATOMIC_OP(ldxr, add, sub, stxr) -ATOMIC_OP(ldxrw, addw, subw, stxrw) +ATOMIC_OP(add, ldxr, add, sub, ldadd, stxr, Assembler::xword) +ATOMIC_OP(addw, ldxrw, addw, subw, ldadd, stxrw, Assembler::word) +ATOMIC_OP(addal, ldaxr, add, sub, ldaddal, stlxr, Assembler::xword) +ATOMIC_OP(addalw, ldaxrw, addw, subw, ldaddal, stlxrw, Assembler::word) #undef ATOMIC_OP -#define ATOMIC_XCHG(OP, LDXR, STXR) \ +#define ATOMIC_XCHG(OP, AOP, LDXR, STXR, sz) \ void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) { \ + if (UseLSE) { \ + prev = prev->is_valid() ? prev : zr; \ + AOP(sz, newv, prev, addr); \ + return; \ + } \ Register result = rscratch2; \ if (prev->is_valid()) \ result = different(prev, newv, addr) ? prev : rscratch2; \ @@ -2211,8 +2233,10 @@ void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) { mov(prev, result); \ } -ATOMIC_XCHG(xchg, ldxr, stxr) -ATOMIC_XCHG(xchgw, ldxrw, stxrw) +ATOMIC_XCHG(xchg, swp, ldxr, stxr, Assembler::xword) +ATOMIC_XCHG(xchgw, swp, ldxrw, stxrw, Assembler::word) +ATOMIC_XCHG(xchgal, swpal, ldaxr, stlxr, Assembler::xword) +ATOMIC_XCHG(xchgalw, swpal, ldaxrw, stlxrw, Assembler::word) #undef ATOMIC_XCHG diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 64ef4f65eca..b114e1b9c80 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -957,9 +957,13 @@ public: void atomic_add(Register prev, RegisterOrConstant incr, Register addr); void atomic_addw(Register prev, RegisterOrConstant incr, Register addr); + void atomic_addal(Register prev, RegisterOrConstant incr, Register addr); + void atomic_addalw(Register prev, RegisterOrConstant incr, Register addr); void atomic_xchg(Register prev, Register newv, Register addr); void atomic_xchgw(Register prev, Register newv, Register addr); + void atomic_xchgal(Register prev, Register newv, Register addr); + void atomic_xchgalw(Register prev, Register newv, Register addr); void orptr(Address adr, RegisterOrConstant src) { ldr(rscratch2, adr); diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index c7966aea22e..0aeba4cb33c 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 30805fb4150..d618c0351f7 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -1711,20 +1711,42 @@ class StubGenerator: public StubCodeGenerator { // to a long, int, short, or byte copy loop. // address generate_unsafe_copy(const char *name, - address byte_copy_entry) { -#ifdef PRODUCT - return StubRoutines::_jbyte_arraycopy; -#else + address byte_copy_entry, + address short_copy_entry, + address int_copy_entry, + address long_copy_entry) { + Label L_long_aligned, L_int_aligned, L_short_aligned; + Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame + // bump this on entry, not on exit: - __ lea(rscratch2, ExternalAddress((address)&SharedRuntime::_unsafe_array_copy_ctr)); - __ incrementw(Address(rscratch2)); + inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr); + + __ orr(rscratch1, s, d); + __ orr(rscratch1, rscratch1, count); + + __ andr(rscratch1, rscratch1, BytesPerLong-1); + __ cbz(rscratch1, L_long_aligned); + __ andr(rscratch1, rscratch1, BytesPerInt-1); + __ cbz(rscratch1, L_int_aligned); + __ tbz(rscratch1, 0, L_short_aligned); __ b(RuntimeAddress(byte_copy_entry)); + + __ BIND(L_short_aligned); + __ lsr(count, count, LogBytesPerShort); // size => short_count + __ b(RuntimeAddress(short_copy_entry)); + __ BIND(L_int_aligned); + __ lsr(count, count, LogBytesPerInt); // size => int_count + __ b(RuntimeAddress(int_copy_entry)); + __ BIND(L_long_aligned); + __ lsr(count, count, LogBytesPerLong); // size => long_count + __ b(RuntimeAddress(long_copy_entry)); + return start; -#endif } // @@ -2090,7 +2112,10 @@ class StubGenerator: public StubCodeGenerator { /*dest_uninitialized*/true); StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", - entry_jbyte_arraycopy); + entry_jbyte_arraycopy, + entry_jshort_arraycopy, + entry_jint_arraycopy, + entry_jlong_arraycopy); StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", entry_jbyte_arraycopy, diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp index 59bdeeeb044..7fe8f147c27 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp @@ -32,6 +32,7 @@ #include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "interpreter/bytecodeTracer.hpp" +#include "memory/resourceArea.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" @@ -1967,7 +1968,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { __ push(RegSet::range(r0, r15), sp); __ mov(c_rarg2, r0); // Pass itos __ call_VM(noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), + CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), c_rarg1, c_rarg2, c_rarg3); __ pop(RegSet::range(r0, r15), sp); __ pop(state); @@ -1982,14 +1983,8 @@ void TemplateInterpreterGenerator::count_bytecode() { __ push(rscratch1); __ push(rscratch2); __ push(rscratch3); - Label L; - __ mov(rscratch2, (address) &BytecodeCounter::_counter_value); - __ prfm(Address(rscratch2), PSTL1STRM); - __ bind(L); - __ ldxr(rscratch1, rscratch2); - __ add(rscratch1, rscratch1, 1); - __ stxr(rscratch3, rscratch1, rscratch2); - __ cbnzw(rscratch3, L); + __ mov(rscratch3, (address) &BytecodeCounter::_counter_value); + __ atomic_add(noreg, 1, rscratch3); __ pop(rscratch3); __ pop(rscratch2); __ pop(rscratch1); diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp index 7cb6fd7ce1a..2ed5e7ef9bd 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp @@ -73,6 +73,7 @@ public: CPU_SHA1 = (1<<5), CPU_SHA2 = (1<<6), CPU_CRC32 = (1<<7), + CPU_LSE = (1<<8), CPU_A53MAC = (1 << 30), CPU_DMB_ATOMICS = (1 << 31), }; diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 3cae863f41c..c5e7087eadc 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -624,6 +624,7 @@ class Assembler : public AbstractAssembler { VNOR_OPCODE = (4u << OPCODE_SHIFT | 1284u ), VOR_OPCODE = (4u << OPCODE_SHIFT | 1156u ), VXOR_OPCODE = (4u << OPCODE_SHIFT | 1220u ), + VRLD_OPCODE = (4u << OPCODE_SHIFT | 196u ), VRLB_OPCODE = (4u << OPCODE_SHIFT | 4u ), VRLW_OPCODE = (4u << OPCODE_SHIFT | 132u ), VRLH_OPCODE = (4u << OPCODE_SHIFT | 68u ), @@ -2047,6 +2048,7 @@ class Assembler : public AbstractAssembler { inline void vnor( VectorRegister d, VectorRegister a, VectorRegister b); inline void vor( VectorRegister d, VectorRegister a, VectorRegister b); inline void vxor( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vrld( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlb( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlh( VectorRegister d, VectorRegister a, VectorRegister b); diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index 8393a579151..4e7f7df8f24 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -839,6 +839,7 @@ inline void Assembler::vandc( VectorRegister d, VectorRegister a, VectorRegist inline void Assembler::vnor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VNOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vxor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VXOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vrld( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlb( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLH_OPCODE | vrt(d) | vra(a) | vrb(b)); } diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index 7be5e000897..0dc6714f7e4 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -55,6 +55,7 @@ define_pd_global(bool, UseTLAB, true); define_pd_global(bool, ResizeTLAB, true); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); +define_pd_global(intx, PostLoopMultiversioning, false); // Peephole and CISC spilling both break the graph, and so make the // scheduler sick. diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index dea4bfca545..a4bb111d9e0 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,6 +28,7 @@ #include "classfile/javaClasses.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" #define __ _masm-> diff --git a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp index 77353f891e7..984eb01f53f 100644 --- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ #include "code/vmreg.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "memory/resourceArea.hpp" #include "nativeInst_ppc.hpp" #include "opto/runtime.hpp" #include "runtime/interfaceSupport.hpp" diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index c945027a50d..49df282945d 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -31,6 +31,7 @@ #include "frame_ppc.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 85a83c8179b..0f6c6f77fdb 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -2417,6 +2417,433 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Arguments for generated stub (little endian only): + // R3_ARG1 - source byte array address + // R4_ARG2 - destination byte array address + // R5_ARG3 - round key array + address generate_aescrypt_encryptBlock() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock"); + + address start = __ function_entry(); + + Label L_doLast; + + Register from = R3_ARG1; // source array address + Register to = R4_ARG2; // destination array address + Register key = R5_ARG3; // round key array + + Register keylen = R8; + Register temp = R9; + Register keypos = R10; + Register hex = R11; + Register fifteen = R12; + + VectorRegister vRet = VR0; + + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + + VectorRegister fromPerm = VR5; + VectorRegister keyPerm = VR6; + VectorRegister toPerm = VR7; + VectorRegister fSplt = VR8; + + VectorRegister vTmp1 = VR9; + VectorRegister vTmp2 = VR10; + VectorRegister vTmp3 = VR11; + VectorRegister vTmp4 = VR12; + + VectorRegister vLow = VR13; + VectorRegister vHigh = VR14; + + __ li (hex, 16); + __ li (fifteen, 15); + __ vspltisb (fSplt, 0x0f); + + // load unaligned from[0-15] to vsRet + __ lvx (vRet, from); + __ lvx (vTmp1, fifteen, from); + __ lvsl (fromPerm, from); + __ vxor (fromPerm, fromPerm, fSplt); + __ vperm (vRet, vRet, vTmp1, fromPerm); + + // load keylen (44 or 52 or 60) + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); + + // to load keys + __ lvsr (keyPerm, key); + __ vxor (vTmp2, vTmp2, vTmp2); + __ vspltisb (vTmp2, -16); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vsldoi (keyPerm, keyPerm, keyPerm, -8); + + // load the 1st round key to vKey1 + __ li (keypos, 0); + __ lvx (vKey1, keypos, key); + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey1, vTmp1, vKey1, keyPerm); + + // 1st round + __ vxor (vRet, vRet, vKey1); + + // load the 2nd round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 3rd round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 4th round key to vKey3 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 5th round key to vKey4 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // 2nd - 5th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // load the 6th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 7th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 8th round key to vKey3 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 9th round key to vKey4 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // 6th - 9th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // load the 10th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // if all round keys are loaded, skip next 4 rounds + __ cmpwi (CCR0, keylen, 44); + __ beq (CCR0, L_doLast); + + // 10th - 11th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // load the 12th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 13th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // if all round keys are loaded, skip next 2 rounds + __ cmpwi (CCR0, keylen, 52); + __ beq (CCR0, L_doLast); + + // 12th - 13th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // load the 14th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 15th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + __ bind(L_doLast); + + // last two rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipherlast (vRet, vRet, vKey2); + + __ neg (temp, to); + __ lvsr (toPerm, temp); + __ vspltisb (vTmp2, -1); + __ vxor (vTmp1, vTmp1, vTmp1); + __ vperm (vTmp2, vTmp2, vTmp1, toPerm); + __ vxor (toPerm, toPerm, fSplt); + __ lvx (vTmp1, to); + __ vperm (vRet, vRet, vRet, toPerm); + __ vsel (vTmp1, vTmp1, vRet, vTmp2); + __ lvx (vTmp4, fifteen, to); + __ stvx (vTmp1, to); + __ vsel (vRet, vRet, vTmp4, vTmp2); + __ stvx (vRet, fifteen, to); + + __ blr(); + return start; + } + + // Arguments for generated stub (little endian only): + // R3_ARG1 - source byte array address + // R4_ARG2 - destination byte array address + // R5_ARG3 - K (key) in little endian int array + address generate_aescrypt_decryptBlock() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock"); + + address start = __ function_entry(); + + Label L_doLast; + Label L_do44; + Label L_do52; + Label L_do60; + + Register from = R3_ARG1; // source array address + Register to = R4_ARG2; // destination array address + Register key = R5_ARG3; // round key array + + Register keylen = R8; + Register temp = R9; + Register keypos = R10; + Register hex = R11; + Register fifteen = R12; + + VectorRegister vRet = VR0; + + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + VectorRegister vKey5 = VR5; + + VectorRegister fromPerm = VR6; + VectorRegister keyPerm = VR7; + VectorRegister toPerm = VR8; + VectorRegister fSplt = VR9; + + VectorRegister vTmp1 = VR10; + VectorRegister vTmp2 = VR11; + VectorRegister vTmp3 = VR12; + VectorRegister vTmp4 = VR13; + + VectorRegister vLow = VR14; + VectorRegister vHigh = VR15; + + __ li (hex, 16); + __ li (fifteen, 15); + __ vspltisb (fSplt, 0x0f); + + // load unaligned from[0-15] to vsRet + __ lvx (vRet, from); + __ lvx (vTmp1, fifteen, from); + __ lvsl (fromPerm, from); + __ vxor (fromPerm, fromPerm, fSplt); + __ vperm (vRet, vRet, vTmp1, fromPerm); // align [and byte swap in LE] + + // load keylen (44 or 52 or 60) + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); + + // to load keys + __ lvsr (keyPerm, key); + __ vxor (vTmp2, vTmp2, vTmp2); + __ vspltisb (vTmp2, -16); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vsldoi (keyPerm, keyPerm, keyPerm, -8); + + __ cmpwi (CCR0, keylen, 44); + __ beq (CCR0, L_do44); + + __ cmpwi (CCR0, keylen, 52); + __ beq (CCR0, L_do52); + + // load the 15th round key to vKey11 + __ li (keypos, 240); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 14th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 13th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // load the 12th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + + // 1st - 5th rounds + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + + __ b (L_doLast); + + __ bind (L_do52); + + // load the 13th round key to vKey11 + __ li (keypos, 208); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 12th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // 1st - 3rd rounds + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + + __ b (L_doLast); + + __ bind (L_do44); + + // load the 11th round key to vKey11 + __ li (keypos, 176); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // 1st round + __ vxor (vRet, vRet, vKey1); + + __ bind (L_doLast); + + // load the 10th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 9th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 8th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 7th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // load the 6th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey5, vTmp2, vTmp1, keyPerm); + + // last 10th - 6th rounds + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + + // load the 5th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 4th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 3rd round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // load the 2nd round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp2, vTmp1, keyPerm); + + // load the 1st round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + + // last 5th - 1th rounds + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipherlast (vRet, vRet, vKey5); + + __ neg (temp, to); + __ lvsr (toPerm, temp); + __ vspltisb (vTmp2, -1); + __ vxor (vTmp1, vTmp1, vTmp1); + __ vperm (vTmp2, vTmp2, vTmp1, toPerm); + __ vxor (toPerm, toPerm, fSplt); + __ lvx (vTmp1, to); + __ vperm (vRet, vRet, vRet, toPerm); + __ vsel (vTmp1, vTmp1, vRet, vTmp2); + __ lvx (vTmp4, fifteen, to); + __ stvx (vTmp1, to); + __ vsel (vRet, vRet, vTmp4, vTmp2); + __ stvx (vRet, fifteen, to); + + __ blr(); + return start; + } void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of @@ -2693,10 +3120,6 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); - if (UseAESIntrinsics) { - guarantee(!UseAESIntrinsics, "not yet implemented."); - } - // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, @@ -2719,6 +3142,12 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_montgomerySquare = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square); } + + if (UseAESIntrinsics) { + StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); + StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + } + } public: diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp index 19b732a2ad6..8979e213acf 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp @@ -2211,7 +2211,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp); __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp); __ mflr(R31); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false); __ mtlr(R31); __ pop(state); diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 6743b2967f9..88c03a3dc43 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -122,7 +122,7 @@ void VM_Version::initialize() { (has_fcfids() ? " fcfids" : ""), (has_vand() ? " vand" : ""), (has_lqarx() ? " lqarx" : ""), - (has_vcipher() ? " vcipher" : ""), + (has_vcipher() ? " aes" : ""), (has_vpmsumb() ? " vpmsumb" : ""), (has_tcheck() ? " tcheck" : ""), (has_mfdscr() ? " mfdscr" : "") @@ -186,6 +186,28 @@ void VM_Version::initialize() { } // The AES intrinsic stubs require AES instruction support. +#if defined(VM_LITTLE_ENDIAN) + if (has_vcipher()) { + if (FLAG_IS_DEFAULT(UseAES)) { + UseAES = true; + } + } else if (UseAES) { + if (!FLAG_IS_DEFAULT(UseAES)) + warning("AES instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseAES, false); + } + + if (UseAES && has_vcipher()) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + UseAESIntrinsics = true; + } + } else if (UseAESIntrinsics) { + if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + +#else if (UseAES) { warning("AES instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseAES, false); @@ -195,6 +217,7 @@ void VM_Version::initialize() { warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } +#endif if (UseAESCTRIntrinsics) { warning("AES/CTR intrinsics are not available on this CPU"); diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 42ae95d04c7..9cef4721b92 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -53,6 +53,7 @@ define_pd_global(bool, UseTLAB, true); define_pd_global(bool, ResizeTLAB, true); define_pd_global(intx, LoopUnrollLimit, 60); // Design center runs on 1.3.1 define_pd_global(intx, LoopPercentProfileLimit, 10); +define_pd_global(intx, PostLoopMultiversioning, false); define_pd_global(intx, MinJumpTableSize, 5); // Peephole and CISC spilling both break the graph, and so makes the diff --git a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp index 4d51de2921a..f93dbf17212 100644 --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" #define __ _masm-> diff --git a/hotspot/src/cpu/sparc/vm/runtime_sparc.cpp b/hotspot/src/cpu/sparc/vm/runtime_sparc.cpp index 0e498d71285..53d63e57cc3 100644 --- a/hotspot/src/cpu/sparc/vm/runtime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/runtime_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "classfile/systemDictionary.hpp" #include "code/vmreg.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "nativeInst_sparc.hpp" #include "opto/runtime.hpp" #include "runtime/interfaceSupport.hpp" diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 65cbf6e8315..ab9fed0d5d1 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp index 172221ab47b..153bd2b2319 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp @@ -1966,7 +1966,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { // Pass a 0 (not used in sparc) and the top of stack to the bytecode tracer __ mov( Otos_l2, G3_scratch ); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), G0, Otos_l1, G3_scratch); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), G0, Otos_l1, G3_scratch); __ mov(Lscratch, O7); // restore return address __ pop(state); __ retl(); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index dd9e30156e1..e30a0289b32 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -3147,8 +3147,7 @@ void Assembler::packuswb(XMMRegister dst, XMMRegister src) { void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "some form of AVX must be enabled"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3156,7 +3155,7 @@ void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, int void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, int vector_len) { assert(VM_Version::supports_avx2(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x00); emit_int8(0xC0 | encode); emit_int8(imm8); @@ -3199,8 +3198,7 @@ void Assembler::pcmpeqb(XMMRegister dst, XMMRegister src) { void Assembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3210,8 +3208,7 @@ void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3222,9 +3219,8 @@ void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vect InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; int dst_enc = kdst->encoding(); - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); emit_operand(as_Register(dst_enc), src); } @@ -3242,8 +3238,7 @@ void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3253,8 +3248,7 @@ void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3265,9 +3259,8 @@ void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, Address src, int vect InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; int dst_enc = kdst->encoding(); - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); emit_operand(as_Register(dst_enc), src); } @@ -3285,8 +3278,7 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { void Assembler::vpcmpeqd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x76); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3296,8 +3288,7 @@ void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x76); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3308,9 +3299,8 @@ void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, Address src, int vect InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; int dst_enc = kdst->encoding(); - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x76); emit_operand(as_Register(dst_enc), src); } @@ -3328,8 +3318,7 @@ void Assembler::pcmpeqq(XMMRegister dst, XMMRegister src) { void Assembler::vpcmpeqq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x29); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3339,8 +3328,7 @@ void Assembler::evpcmpeqq(KRegister kdst, XMMRegister nds, XMMRegister src, int assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x29); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3352,9 +3340,8 @@ void Assembler::evpcmpeqq(KRegister kdst, XMMRegister nds, Address src, int vect InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; int dst_enc = kdst->encoding(); - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, nds->encoding(), dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x29); emit_operand(as_Register(dst_enc), src); } @@ -3988,7 +3975,7 @@ void Assembler::palignr(XMMRegister dst, XMMRegister src, int imm8) { void Assembler::pblendw(XMMRegister dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0x0E); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -4395,8 +4382,7 @@ void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_operand(dst, src); } @@ -4404,8 +4390,7 @@ void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4415,8 +4400,7 @@ void Assembler::vaddss(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_operand(dst, src); } @@ -4424,8 +4408,7 @@ void Assembler::vaddss(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vaddss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4435,8 +4418,7 @@ void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_operand(dst, src); } @@ -4444,8 +4426,7 @@ void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4455,8 +4436,7 @@ void Assembler::vdivss(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_operand(dst, src); } @@ -4464,8 +4444,7 @@ void Assembler::vdivss(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vdivss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4475,8 +4454,7 @@ void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_operand(dst, src); } @@ -4484,8 +4462,7 @@ void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4495,8 +4472,7 @@ void Assembler::vmulss(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_operand(dst, src); } @@ -4504,8 +4480,7 @@ void Assembler::vmulss(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vmulss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4515,8 +4490,7 @@ void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_operand(dst, src); } @@ -4524,8 +4498,7 @@ void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4535,8 +4508,7 @@ void Assembler::vsubss(XMMRegister dst, XMMRegister nds, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_operand(dst, src); } @@ -4544,8 +4516,7 @@ void Assembler::vsubss(XMMRegister dst, XMMRegister nds, Address src) { void Assembler::vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4584,8 +4555,7 @@ void Assembler::addps(XMMRegister dst, XMMRegister src) { void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4593,8 +4563,7 @@ void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vaddps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4604,8 +4573,7 @@ void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_operand(dst, src); } @@ -4615,8 +4583,7 @@ void Assembler::vaddps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x58); emit_operand(dst, src); } @@ -4640,8 +4607,7 @@ void Assembler::subps(XMMRegister dst, XMMRegister src) { void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4649,8 +4615,7 @@ void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vsubps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4660,8 +4625,7 @@ void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_operand(dst, src); } @@ -4671,8 +4635,7 @@ void Assembler::vsubps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x5C); emit_operand(dst, src); } @@ -4706,8 +4669,7 @@ void Assembler::mulps(XMMRegister dst, XMMRegister src) { void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4715,8 +4677,7 @@ void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vmulps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4726,8 +4687,7 @@ void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_operand(dst, src); } @@ -4737,8 +4697,7 @@ void Assembler::vmulps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x59); emit_operand(dst, src); } @@ -4762,8 +4721,7 @@ void Assembler::divps(XMMRegister dst, XMMRegister src) { void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4771,8 +4729,7 @@ void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vdivps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4782,8 +4739,7 @@ void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_operand(dst, src); } @@ -4793,8 +4749,7 @@ void Assembler::vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x5E); emit_operand(dst, src); } @@ -4802,8 +4757,7 @@ void Assembler::vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::vsqrtpd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x51); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4857,8 +4811,7 @@ void Assembler::andpd(XMMRegister dst, Address src) { void Assembler::vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x54); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4866,8 +4819,7 @@ void Assembler::vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x54); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4877,8 +4829,7 @@ void Assembler::vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x54); emit_operand(dst, src); } @@ -4888,8 +4839,7 @@ void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x54); emit_operand(dst, src); } @@ -4949,8 +4899,7 @@ void Assembler::xorps(XMMRegister dst, Address src) { void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x57); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4958,8 +4907,7 @@ void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x57); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4969,8 +4917,7 @@ void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x57); emit_operand(dst, src); } @@ -4980,8 +4927,7 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x57); emit_operand(dst, src); } @@ -4991,8 +4937,7 @@ void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int v assert(VM_Version::supports_avx() && (vector_len == 0) || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x01); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5001,8 +4946,7 @@ void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int v assert(VM_Version::supports_avx() && (vector_len == 0) || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x02); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5035,7 +4979,7 @@ void Assembler::paddd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFE); emit_operand(dst, src); } @@ -5067,8 +5011,7 @@ void Assembler::phaddd(XMMRegister dst, XMMRegister src) { void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5076,8 +5019,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5085,8 +5027,7 @@ void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFE); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5094,8 +5035,7 @@ void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD4); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5105,8 +5045,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); emit_operand(dst, src); } @@ -5116,8 +5055,7 @@ void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); emit_operand(dst, src); } @@ -5127,8 +5065,7 @@ void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFE); emit_operand(dst, src); } @@ -5138,8 +5075,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD4); emit_operand(dst, src); } @@ -5178,8 +5114,7 @@ void Assembler::psubq(XMMRegister dst, XMMRegister src) { void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5187,8 +5122,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5196,8 +5130,7 @@ void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFA); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5205,8 +5138,7 @@ void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFB); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5216,8 +5148,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); emit_operand(dst, src); } @@ -5227,8 +5158,7 @@ void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); emit_operand(dst, src); } @@ -5238,8 +5168,7 @@ void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFA); emit_operand(dst, src); } @@ -5249,8 +5178,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFB); emit_operand(dst, src); } @@ -5274,8 +5202,7 @@ void Assembler::pmulld(XMMRegister dst, XMMRegister src) { void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5283,8 +5210,7 @@ void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5292,8 +5218,7 @@ void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 2, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5303,8 +5228,7 @@ void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); emit_operand(dst, src); } @@ -5314,8 +5238,7 @@ void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_operand(dst, src); } @@ -5325,8 +5248,7 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_operand(dst, src); } @@ -5638,8 +5560,7 @@ void Assembler::pand(XMMRegister dst, XMMRegister src) { void Assembler::vpand(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDB); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5649,8 +5570,7 @@ void Assembler::vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_ InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDB); emit_operand(dst, src); } @@ -5674,8 +5594,7 @@ void Assembler::por(XMMRegister dst, XMMRegister src) { void Assembler::vpor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xEB); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5685,8 +5604,7 @@ void Assembler::vpor(XMMRegister dst, XMMRegister nds, Address src, int vector_l InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xEB); emit_operand(dst, src); } @@ -5702,8 +5620,7 @@ void Assembler::pxor(XMMRegister dst, XMMRegister src) { void Assembler::vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xEF); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5713,20 +5630,96 @@ void Assembler::vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_ InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xEF); emit_operand(dst, src); } +// vinserti forms + +void Assembler::vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_avx2(), ""); + assert(imm8 <= 0x01, "imm8: %u", imm8); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x38); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - insert into lower 128 bits + // 0x01 - insert into upper 128 bits + emit_int8(imm8 & 0x01); +} + +void Assembler::vinserti128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { + assert(VM_Version::supports_avx2(), ""); + assert(dst != xnoreg, "sanity"); + assert(imm8 <= 0x01, "imm8: %u", imm8); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x38); + emit_operand(dst, src); + // 0x00 - insert into lower 128 bits + // 0x01 - insert into upper 128 bits + emit_int8(imm8 & 0x01); +} + +void Assembler::vinserti32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); + assert(imm8 <= 0x03, "imm8: %u", imm8); + InstructionAttr attributes(AVX_512bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x38); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - insert into q0 128 bits (0..127) + // 0x01 - insert into q1 128 bits (128..255) + // 0x02 - insert into q2 128 bits (256..383) + // 0x03 - insert into q3 128 bits (384..511) + emit_int8(imm8 & 0x03); +} + +void Assembler::vinserti32x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { + assert(VM_Version::supports_avx(), ""); + assert(dst != xnoreg, "sanity"); + assert(imm8 <= 0x03, "imm8: %u", imm8); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x18); + emit_operand(dst, src); + // 0x00 - insert into q0 128 bits (0..127) + // 0x01 - insert into q1 128 bits (128..255) + // 0x02 - insert into q2 128 bits (256..383) + // 0x03 - insert into q3 128 bits (384..511) + emit_int8(imm8 & 0x03); +} + +void Assembler::vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); + assert(imm8 <= 0x01, "imm8: %u", imm8); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x38); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - insert into lower 256 bits + // 0x01 - insert into upper 256 bits + emit_int8(imm8 & 0x01); +} + + +// vinsertf forms + void Assembler::vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_avx(), ""); assert(imm8 <= 0x01, "imm8: %u", imm8); int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 128 bits @@ -5734,33 +5727,19 @@ void Assembler::vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, u emit_int8(imm8 & 0x01); } -void Assembler::vinsertf64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_evex(), ""); - assert(imm8 <= 0x01, "imm8: %u", imm8); - InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x1A); - emit_int8((unsigned char)(0xC0 | encode)); - // 0x00 - insert into lower 256 bits - // 0x01 - insert into upper 256 bits - emit_int8(imm8 & 0x01); -} - -void Assembler::vinsertf64x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { - assert(VM_Version::supports_evex(), ""); +void Assembler::vinsertf128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { + assert(VM_Version::supports_avx(), ""); assert(dst != xnoreg, "sanity"); assert(imm8 <= 0x01, "imm8: %u", imm8); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; InstructionMark im(this); - InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_64bit); - // swap src<->dst for encoding - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x1A); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x18); emit_operand(dst, src); - // 0x00 - insert into lower 256 bits - // 0x01 - insert into upper 256 bits + // 0x00 - insert into lower 128 bits + // 0x01 - insert into upper 128 bits emit_int8(imm8 & 0x01); } @@ -5768,8 +5747,7 @@ void Assembler::vinsertf32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, assert(VM_Version::supports_evex(), ""); assert(imm8 <= 0x03, "imm8: %u", imm8); InstructionAttr attributes(AVX_512bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into q0 128 bits (0..127) @@ -5784,12 +5762,10 @@ void Assembler::vinsertf32x4(XMMRegister dst, XMMRegister nds, Address src, uint assert(dst != xnoreg, "sanity"); assert(imm8 <= 0x03, "imm8: %u", imm8); int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; - int nds_enc = nds->is_valid() ? nds->encoding() : 0; InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); - // swap src<->dst for encoding - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_operand(dst, src); // 0x00 - insert into q0 128 bits (0..127) @@ -5799,98 +5775,36 @@ void Assembler::vinsertf32x4(XMMRegister dst, XMMRegister nds, Address src, uint emit_int8(imm8 & 0x03); } -void Assembler::vinsertf128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { - assert(VM_Version::supports_avx(), ""); - assert(dst != xnoreg, "sanity"); - assert(imm8 <= 0x01, "imm8: %u", imm8); - int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); - // swap src<->dst for encoding - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x18); - emit_operand(dst, src); - // 0x00 - insert into lower 128 bits - // 0x01 - insert into upper 128 bits - emit_int8(imm8 & 0x01); -} - -void Assembler::vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_avx(), ""); - assert(imm8 <= 0x01, "imm8: %u", imm8); - int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x19); - emit_int8((unsigned char)(0xC0 | encode)); - // 0x00 - extract from lower 128 bits - // 0x01 - extract from upper 128 bits - emit_int8(imm8 & 0x01); -} - -void Assembler::vextractf128(Address dst, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_avx(), ""); - assert(src != xnoreg, "sanity"); - assert(imm8 <= 0x01, "imm8: %u", imm8); - int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; - InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); - vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x19); - emit_operand(src, dst); - // 0x00 - extract from lower 128 bits - // 0x01 - extract from upper 128 bits - emit_int8(imm8 & 0x01); -} - -void Assembler::vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_avx2(), ""); - assert(imm8 <= 0x01, "imm8: %u", imm8); - int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x38); - emit_int8((unsigned char)(0xC0 | encode)); - // 0x00 - insert into lower 128 bits - // 0x01 - insert into upper 128 bits - emit_int8(imm8 & 0x01); -} - -void Assembler::vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { +void Assembler::vinsertf64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_evex(), ""); assert(imm8 <= 0x01, "imm8: %u", imm8); InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x38); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x1A); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 256 bits // 0x01 - insert into upper 256 bits emit_int8(imm8 & 0x01); } -void Assembler::vinserti128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { - assert(VM_Version::supports_avx2(), ""); +void Assembler::vinsertf64x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); assert(imm8 <= 0x01, "imm8: %u", imm8); - int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; - int nds_enc = nds->is_valid() ? nds->encoding() : 0; InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); - // swap src<->dst for encoding - vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x38); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_64bit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x1A); emit_operand(dst, src); - // 0x00 - insert into lower 128 bits - // 0x01 - insert into upper 128 bits + // 0x00 - insert into lower 256 bits + // 0x01 - insert into upper 256 bits emit_int8(imm8 & 0x01); } + +// vextracti forms + void Assembler::vextracti128(XMMRegister dst, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_avx(), ""); assert(imm8 <= 0x01, "imm8: %u", imm8); @@ -5920,16 +5834,36 @@ void Assembler::vextracti128(Address dst, XMMRegister src, uint8_t imm8) { emit_int8(imm8 & 0x01); } -void Assembler::vextracti64x4(XMMRegister dst, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_evex(), ""); - assert(imm8 <= 0x01, "imm8: %u", imm8); - InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); +void Assembler::vextracti32x4(XMMRegister dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_avx(), ""); + assert(imm8 <= 0x03, "imm8: %u", imm8); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x3B); + emit_int8(0x39); emit_int8((unsigned char)(0xC0 | encode)); - // 0x00 - extract from lower 256 bits - // 0x01 - extract from upper 256 bits - emit_int8(imm8 & 0x01); + // 0x00 - extract from bits 127:0 + // 0x01 - extract from bits 255:128 + // 0x02 - extract from bits 383:256 + // 0x03 - extract from bits 511:384 + emit_int8(imm8 & 0x03); +} + +void Assembler::vextracti32x4(Address dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); + assert(src != xnoreg, "sanity"); + assert(imm8 <= 0x03, "imm8: %u", imm8); + InstructionMark im(this); + InstructionAttr attributes(AVX_512bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x39); + emit_operand(src, dst); + // 0x00 - extract from bits 127:0 + // 0x01 - extract from bits 255:128 + // 0x02 - extract from bits 383:256 + // 0x03 - extract from bits 511:384 + emit_int8(imm8 & 0x03); } void Assembler::vextracti64x2(XMMRegister dst, XMMRegister src, uint8_t imm8) { @@ -5946,30 +5880,47 @@ void Assembler::vextracti64x2(XMMRegister dst, XMMRegister src, uint8_t imm8) { emit_int8(imm8 & 0x03); } -void Assembler::vextractf64x4(XMMRegister dst, XMMRegister src, uint8_t imm8) { +void Assembler::vextracti64x4(XMMRegister dst, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_evex(), ""); assert(imm8 <= 0x01, "imm8: %u", imm8); InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x1B); + emit_int8(0x3B); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - extract from lower 256 bits // 0x01 - extract from upper 256 bits emit_int8(imm8 & 0x01); } -void Assembler::vextractf64x4(Address dst, XMMRegister src, uint8_t imm8) { - assert(VM_Version::supports_evex(), ""); + +// vextractf forms + +void Assembler::vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_avx(), ""); + assert(imm8 <= 0x01, "imm8: %u", imm8); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x19); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - extract from lower 128 bits + // 0x01 - extract from upper 128 bits + emit_int8(imm8 & 0x01); +} + +void Assembler::vextractf128(Address dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_avx(), ""); assert(src != xnoreg, "sanity"); assert(imm8 <= 0x01, "imm8: %u", imm8); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_256bit; InstructionMark im(this); - InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T4,/* input_size_in_bits */ EVEX_64bit); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); - emit_int8(0x1B); + emit_int8(0x19); emit_operand(src, dst); - // 0x00 - extract from lower 256 bits - // 0x01 - extract from upper 256 bits + // 0x00 - extract from lower 128 bits + // 0x01 - extract from upper 128 bits emit_int8(imm8 & 0x01); } @@ -6019,16 +5970,35 @@ void Assembler::vextractf64x2(XMMRegister dst, XMMRegister src, uint8_t imm8) { emit_int8(imm8 & 0x03); } -// duplicate 4-bytes integer data from src into 8 locations in dest -void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { - assert(VM_Version::supports_avx2(), ""); - InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); - emit_int8(0x58); +void Assembler::vextractf64x4(XMMRegister dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); + assert(imm8 <= 0x01, "imm8: %u", imm8); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x1B); emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - extract from lower 256 bits + // 0x01 - extract from upper 256 bits + emit_int8(imm8 & 0x01); } -// duplicate 2-bytes integer data from src into 16 locations in dest +void Assembler::vextractf64x4(Address dst, XMMRegister src, uint8_t imm8) { + assert(VM_Version::supports_evex(), ""); + assert(src != xnoreg, "sanity"); + assert(imm8 <= 0x01, "imm8: %u", imm8); + InstructionMark im(this); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4,/* input_size_in_bits */ EVEX_64bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x1B); + emit_operand(src, dst); + // 0x00 - extract from lower 256 bits + // 0x01 - extract from upper 256 bits + emit_int8(imm8 & 0x01); +} + + +// legacy word/dword replicate void Assembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -6037,7 +6007,18 @@ void Assembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { emit_int8((unsigned char)(0xC0 | encode)); } -// duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL +void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_avx2(), ""); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); +} + + +// xmm/mem sourced byte/word/dword/qword replicate + +// duplicate 1-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -6053,12 +6034,12 @@ void Assembler::evpbroadcastb(XMMRegister dst, Address src, int vector_len) { InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_8bit); // swap src<->dst for encoding - vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x78); emit_operand(dst, src); } -// duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL +// duplicate 2-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -6074,12 +6055,12 @@ void Assembler::evpbroadcastw(XMMRegister dst, Address src, int vector_len) { InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); // swap src<->dst for encoding - vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_operand(dst, src); } -// duplicate 4-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL +// duplicate 4-byte integer data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6095,12 +6076,12 @@ void Assembler::evpbroadcastd(XMMRegister dst, Address src, int vector_len) { InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x58); emit_operand(dst, src); } -// duplicate 8-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL +// duplicate 8-byte integer data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6116,12 +6097,15 @@ void Assembler::evpbroadcastq(XMMRegister dst, Address src, int vector_len) { InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); // swap src<->dst for encoding - vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x59); emit_operand(dst, src); } -// duplicate single precision fp from src into 4|8|16 locations in dest : requires AVX512VL + +// scalar single/double precision replicate + +// duplicate single precision data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6142,7 +6126,7 @@ void Assembler::evpbroadcastss(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src); } -// duplicate double precision fp from src into 2|4|8 locations in dest : requires AVX512VL +// duplicate double precision data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6163,7 +6147,10 @@ void Assembler::evpbroadcastsd(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src); } -// duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL + +// gpr source broadcast forms + +// duplicate 1-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -6176,7 +6163,7 @@ void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) { emit_int8((unsigned char)(0xC0 | encode)); } -// duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL +// duplicate 2-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -6189,7 +6176,7 @@ void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) { emit_int8((unsigned char)(0xC0 | encode)); } -// duplicate 4-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL +// duplicate 4-byte integer data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastd(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6202,7 +6189,7 @@ void Assembler::evpbroadcastd(XMMRegister dst, Register src, int vector_len) { emit_int8((unsigned char)(0xC0 | encode)); } -// duplicate 8-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL +// duplicate 8-byte integer data from src into programmed locations in dest : requires AVX512VL void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -6215,6 +6202,7 @@ void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { emit_int8((unsigned char)(0xC0 | encode)); } + // Carry-Less Multiplication Quadword void Assembler::pclmulqdq(XMMRegister dst, XMMRegister src, int mask) { assert(VM_Version::supports_clmul(), ""); @@ -6229,8 +6217,7 @@ void Assembler::pclmulqdq(XMMRegister dst, XMMRegister src, int mask) { void Assembler::vpclmulqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int mask) { assert(VM_Version::supports_avx() && VM_Version::supports_clmul(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x44); emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)mask); @@ -6972,8 +6959,7 @@ void Assembler::vpblendd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMM assert(VM_Version::supports_avx(), ""); assert(!VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0x4B); emit_int8((unsigned char)(0xC0 | encode)); int src2_enc = src2->encoding(); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 4423d4a5bde..fd3053d1e6f 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1977,39 +1977,43 @@ private: void vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_len); - // 128bit copy from/to 256bit (YMM) vector registers - void vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); + // vinserti forms void vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); - void vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextracti128(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vinsertf128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); void vinserti128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); - void vextractf128(Address dst, XMMRegister src, uint8_t imm8); - void vextracti128(Address dst, XMMRegister src, uint8_t imm8); - - // 256bit copy from/to 512bit (ZMM) vector registers + void vinserti32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); + void vinserti32x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); void vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); - void vinsertf64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); - void vextracti64x4(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextractf64x4(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextractf64x4(Address dst, XMMRegister src, uint8_t imm8); - void vinsertf64x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); - // 128bit copy from/to 256bit (YMM) or 512bit (ZMM) vector registers - void vextracti64x2(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextractf64x2(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextractf32x4(XMMRegister dst, XMMRegister src, uint8_t imm8); - void vextractf32x4(Address dst, XMMRegister src, uint8_t imm8); + // vinsertf forms + void vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); + void vinsertf128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); void vinsertf32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); void vinsertf32x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); + void vinsertf64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); + void vinsertf64x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); - // duplicate 4-bytes integer data from src into 8 locations in dest + // vextracti forms + void vextracti128(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextracti128(Address dst, XMMRegister src, uint8_t imm8); + void vextracti32x4(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextracti32x4(Address dst, XMMRegister src, uint8_t imm8); + void vextracti64x2(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextracti64x4(XMMRegister dst, XMMRegister src, uint8_t imm8); + + // vextractf forms + void vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextractf128(Address dst, XMMRegister src, uint8_t imm8); + void vextractf32x4(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextractf32x4(Address dst, XMMRegister src, uint8_t imm8); + void vextractf64x2(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextractf64x4(XMMRegister dst, XMMRegister src, uint8_t imm8); + void vextractf64x4(Address dst, XMMRegister src, uint8_t imm8); + + // legacy xmm sourced word/dword replicate + void vpbroadcastw(XMMRegister dst, XMMRegister src); void vpbroadcastd(XMMRegister dst, XMMRegister src); - // duplicate 2-bytes integer data from src into 16 locations in dest - void vpbroadcastw(XMMRegister dst, XMMRegister src); - - // duplicate n-bytes integer data from src into vector_len locations in dest + // xmm/mem sourced byte/word/dword/qword replicate void evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len); void evpbroadcastb(XMMRegister dst, Address src, int vector_len); void evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len); @@ -2019,11 +2023,13 @@ private: void evpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len); void evpbroadcastq(XMMRegister dst, Address src, int vector_len); + // scalar single/double precision replicate void evpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len); void evpbroadcastss(XMMRegister dst, Address src, int vector_len); void evpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len); void evpbroadcastsd(XMMRegister dst, Address src, int vector_len); + // gpr sourced byte/word/dword/qword replicate void evpbroadcastb(XMMRegister dst, Register src, int vector_len); void evpbroadcastw(XMMRegister dst, Register src, int vector_len); void evpbroadcastd(XMMRegister dst, Register src, int vector_len); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index fb36620c19b..c23ebaad86f 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -312,7 +312,7 @@ void LIR_Assembler::osr_entry() { Register OSR_buf = osrBufferPointer()->as_pointer_register(); { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); int monitor_offset = BytesPerWord * method()->max_locals() + - (2 * BytesPerWord) * (number_of_locks - 1); + (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1); // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in // the OSR buffer using 2 word entries: first the lock and then // the oop. diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index 9352d92650c..311ae27c8d0 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -47,6 +47,7 @@ define_pd_global(intx, ConditionalMoveLimit, 3); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); define_pd_global(intx, LoopPercentProfileLimit, 30); +define_pd_global(intx, PostLoopMultiversioning, true); #ifdef AMD64 define_pd_global(intx, INTPRESSURE, 13); define_pd_global(intx, FLOATPRESSURE, 14); diff --git a/hotspot/src/cpu/x86/vm/frame_x86.hpp b/hotspot/src/cpu/x86/vm/frame_x86.hpp index f5df3c9b1e3..6c85be06a81 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,44 +54,6 @@ // <- sender sp // ------------------------------ Asm interpreter ---------------------------------------- -// ------------------------------ C++ interpreter ---------------------------------------- -// -// Layout of C++ interpreter frame: (While executing in BytecodeInterpreter::run) -// -// <- SP (current esp/rsp) -// [local variables ] BytecodeInterpreter::run local variables -// ... BytecodeInterpreter::run local variables -// [local variables ] BytecodeInterpreter::run local variables -// [old frame pointer ] fp [ BytecodeInterpreter::run's ebp/rbp ] -// [return pc ] (return to frame manager) -// [interpreter_state* ] (arg to BytecodeInterpreter::run) -------------- -// [expression stack ] <- last_Java_sp | -// [... ] * <- interpreter_state.stack | -// [expression stack ] * <- interpreter_state.stack_base | -// [monitors ] \ | -// ... | monitor block size | -// [monitors ] / <- interpreter_state.monitor_base | -// [struct interpretState ] <-----------------------------------------| -// [return pc ] (return to callee of frame manager [1] -// [locals and parameters ] -// <- sender sp - -// [1] When the C++ interpreter calls a new method it returns to the frame -// manager which allocates a new frame on the stack. In that case there -// is no real callee of this newly allocated frame. The frame manager is -// aware of the additional frame(s) and will pop them as nested calls -// complete. However, to make it look good in the debugger the frame -// manager actually installs a dummy pc pointing to RecursiveInterpreterActivation -// with a fake interpreter_state* parameter to make it easy to debug -// nested calls. - -// Note that contrary to the layout for the assembly interpreter the -// expression stack allocated for the C++ interpreter is full sized. -// However this is not as bad as it seems as the interpreter frame_manager -// will truncate the unused space on successive method calls. -// -// ------------------------------ C++ interpreter ---------------------------------------- - public: enum { pc_return_offset = 0, diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp index 8cc7b46be13..8dc3084c442 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,7 +296,7 @@ void InterpreterMacroAssembler::call_VM_base(Register oop_result, Label L; cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); jcc(Assembler::equal, L); - stop("InterpreterMacroAssembler::call_VM_leaf_base:" + stop("InterpreterMacroAssembler::call_VM_base:" " last_sp != NULL"); bind(L); } @@ -1099,7 +1099,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { movptr(Address(lock_reg, mark_offset), swap_reg); assert(lock_offset == 0, - "displached header must be first word in BasicObjectLock"); + "displaced header must be first word in BasicObjectLock"); if (os::is_MP()) lock(); cmpxchgptr(lock_reg, Address(obj_reg, 0)); @@ -1154,7 +1154,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { // Kills: // rax // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) -// rscratch1, rscratch2 (scratch regs) +// rscratch1 (scratch reg) // rax, rbx, rcx, rdx void InterpreterMacroAssembler::unlock_object(Register lock_reg) { assert(lock_reg == LP64_ONLY(c_rarg1) NOT_LP64(rdx), @@ -1201,7 +1201,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { if (os::is_MP()) lock(); cmpxchgptr(header_reg, Address(obj_reg, 0)); - // zero for recursive case + // zero for simple unlock of a stack-lock case jcc(Assembler::zero, done); // Call the runtime routine for slow case. diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 8eb6764770f..7d2c73af358 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -1106,7 +1106,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg, assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg); assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout"); Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes()); - Address saved_mark_addr(lock_reg, 0); + NOT_LP64( Address saved_mark_addr(lock_reg, 0); ) if (PrintBiasedLockingStatistics && counters == NULL) { counters = BiasedLocking::counters(); @@ -1695,7 +1695,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg RTMLockingCounters* stack_rtm_counters, Metadata* method_data, bool use_rtm, bool profile_rtm) { - // Ensure the register assignents are disjoint + // Ensure the register assignments are disjoint assert(tmpReg == rax, ""); if (use_rtm) { @@ -2194,8 +2194,8 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::zero, LGoSlowPath); + xorptr(boxReg, boxReg); if ((EmitSync & 16) && os::is_MP()) { - orptr(boxReg, boxReg); xchgptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); } else { movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); @@ -2227,7 +2227,6 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR // box is really RAX -- the following CMPXCHG depends on that binding // cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R) - movptr(boxReg, (int32_t)NULL_WORD); if (os::is_MP()) { lock(); } cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // There's no successor so we tried to regrab the lock. diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index e325bbcdb2d..836f8c4fb45 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1216,7 +1216,10 @@ public: void vpxor(XMMRegister dst, Address src) { Assembler::vpxor(dst, dst, src, true); } void vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) { - if (UseAVX > 1) { // vinserti128 is available only in AVX2 + if (UseAVX > 2) { + Assembler::vinserti32x4(dst, dst, src, imm8); + } else if (UseAVX > 1) { + // vinserti128 is available only in AVX2 Assembler::vinserti128(dst, nds, src, imm8); } else { Assembler::vinsertf128(dst, nds, src, imm8); @@ -1224,7 +1227,10 @@ public: } void vinserti128(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8) { - if (UseAVX > 1) { // vinserti128 is available only in AVX2 + if (UseAVX > 2) { + Assembler::vinserti32x4(dst, dst, src, imm8); + } else if (UseAVX > 1) { + // vinserti128 is available only in AVX2 Assembler::vinserti128(dst, nds, src, imm8); } else { Assembler::vinsertf128(dst, nds, src, imm8); @@ -1232,7 +1238,10 @@ public: } void vextracti128(XMMRegister dst, XMMRegister src, uint8_t imm8) { - if (UseAVX > 1) { // vextracti128 is available only in AVX2 + if (UseAVX > 2) { + Assembler::vextracti32x4(dst, src, imm8); + } else if (UseAVX > 1) { + // vextracti128 is available only in AVX2 Assembler::vextracti128(dst, src, imm8); } else { Assembler::vextractf128(dst, src, imm8); @@ -1240,7 +1249,10 @@ public: } void vextracti128(Address dst, XMMRegister src, uint8_t imm8) { - if (UseAVX > 1) { // vextracti128 is available only in AVX2 + if (UseAVX > 2) { + Assembler::vextracti32x4(dst, src, imm8); + } else if (UseAVX > 1) { + // vextracti128 is available only in AVX2 Assembler::vextracti128(dst, src, imm8); } else { Assembler::vextractf128(dst, src, imm8); @@ -1260,37 +1272,57 @@ public: void vextracti128_high(Address dst, XMMRegister src) { vextracti128(dst, src, 1); } + void vinsertf128_high(XMMRegister dst, XMMRegister src) { - vinsertf128(dst, dst, src, 1); + if (UseAVX > 2) { + Assembler::vinsertf32x4(dst, dst, src, 1); + } else { + Assembler::vinsertf128(dst, dst, src, 1); + } } + void vinsertf128_high(XMMRegister dst, Address src) { - vinsertf128(dst, dst, src, 1); + if (UseAVX > 2) { + Assembler::vinsertf32x4(dst, dst, src, 1); + } else { + Assembler::vinsertf128(dst, dst, src, 1); + } } + void vextractf128_high(XMMRegister dst, XMMRegister src) { - vextractf128(dst, src, 1); + if (UseAVX > 2) { + Assembler::vextractf32x4(dst, src, 1); + } else { + Assembler::vextractf128(dst, src, 1); + } } + void vextractf128_high(Address dst, XMMRegister src) { - vextractf128(dst, src, 1); + if (UseAVX > 2) { + Assembler::vextractf32x4(dst, src, 1); + } else { + Assembler::vextractf128(dst, src, 1); + } } // 256bit copy to/from high 256 bits of 512bit (ZMM) vector registers void vinserti64x4_high(XMMRegister dst, XMMRegister src) { - vinserti64x4(dst, dst, src, 1); + Assembler::vinserti64x4(dst, dst, src, 1); } void vinsertf64x4_high(XMMRegister dst, XMMRegister src) { - vinsertf64x4(dst, dst, src, 1); + Assembler::vinsertf64x4(dst, dst, src, 1); } void vextracti64x4_high(XMMRegister dst, XMMRegister src) { - vextracti64x4(dst, src, 1); + Assembler::vextracti64x4(dst, src, 1); } void vextractf64x4_high(XMMRegister dst, XMMRegister src) { - vextractf64x4(dst, src, 1); + Assembler::vextractf64x4(dst, src, 1); } void vextractf64x4_high(Address dst, XMMRegister src) { - vextractf64x4(dst, src, 1); + Assembler::vextractf64x4(dst, src, 1); } void vinsertf64x4_high(XMMRegister dst, Address src) { - vinsertf64x4(dst, dst, src, 1); + Assembler::vinsertf64x4(dst, dst, src, 1); } // 128bit copy to/from low 128 bits of 256bit (YMM) vector registers @@ -1306,40 +1338,59 @@ public: void vextracti128_low(Address dst, XMMRegister src) { vextracti128(dst, src, 0); } + void vinsertf128_low(XMMRegister dst, XMMRegister src) { - vinsertf128(dst, dst, src, 0); + if (UseAVX > 2) { + Assembler::vinsertf32x4(dst, dst, src, 0); + } else { + Assembler::vinsertf128(dst, dst, src, 0); + } } + void vinsertf128_low(XMMRegister dst, Address src) { - vinsertf128(dst, dst, src, 0); + if (UseAVX > 2) { + Assembler::vinsertf32x4(dst, dst, src, 0); + } else { + Assembler::vinsertf128(dst, dst, src, 0); + } } + void vextractf128_low(XMMRegister dst, XMMRegister src) { - vextractf128(dst, src, 0); + if (UseAVX > 2) { + Assembler::vextractf32x4(dst, src, 0); + } else { + Assembler::vextractf128(dst, src, 0); + } } + void vextractf128_low(Address dst, XMMRegister src) { - vextractf128(dst, src, 0); + if (UseAVX > 2) { + Assembler::vextractf32x4(dst, src, 0); + } else { + Assembler::vextractf128(dst, src, 0); + } } // 256bit copy to/from low 256 bits of 512bit (ZMM) vector registers void vinserti64x4_low(XMMRegister dst, XMMRegister src) { - vinserti64x4(dst, dst, src, 0); + Assembler::vinserti64x4(dst, dst, src, 0); } void vinsertf64x4_low(XMMRegister dst, XMMRegister src) { - vinsertf64x4(dst, dst, src, 0); + Assembler::vinsertf64x4(dst, dst, src, 0); } void vextracti64x4_low(XMMRegister dst, XMMRegister src) { - vextracti64x4(dst, src, 0); + Assembler::vextracti64x4(dst, src, 0); } void vextractf64x4_low(XMMRegister dst, XMMRegister src) { - vextractf64x4(dst, src, 0); + Assembler::vextractf64x4(dst, src, 0); } void vextractf64x4_low(Address dst, XMMRegister src) { - vextractf64x4(dst, src, 0); + Assembler::vextractf64x4(dst, src, 0); } void vinsertf64x4_low(XMMRegister dst, Address src) { - vinsertf64x4(dst, dst, src, 0); + Assembler::vinsertf64x4(dst, dst, src, 0); } - // Carry-Less Multiplication Quadword void vpclmulldq(XMMRegister dst, XMMRegister nds, XMMRegister src) { // 0x00 - multiply lower 64 bits [0:63] diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index 757c263169b..399172b5a15 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" #define __ _masm-> diff --git a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp index 36457cb8178..5ff630145a7 100644 --- a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "classfile/systemDictionary.hpp" #include "code/vmreg.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "opto/runtime.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index b2bc4fce1aa..abe9a369eaa 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -29,6 +29,7 @@ #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 75f248fb1a3..a5c8f82e6ef 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -32,6 +32,7 @@ #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index fc69cb45e5b..84d07960f24 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -1830,7 +1830,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { __ push(state); // save tosca // pass tosca registers as arguments & call tracer - __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), rcx, rax, rdx); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), rcx, rax, rdx); __ mov(rcx, rax); // make sure return address is not destroyed by pop(state) __ pop(state); // restore tosca @@ -1847,7 +1847,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { __ movflt(xmm3, xmm0); // Pass ftos #endif __ call_VM(noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), + CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), c_rarg1, c_rarg2, c_rarg3); __ pop(c_rarg3); __ pop(c_rarg2); diff --git a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp index 0fce3b50b07..8b7beb15547 100644 --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ #include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java index 9c70c9734b9..5374a5a40e6 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java @@ -549,11 +549,9 @@ public class CommandProcessor { }, new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { // This is used to dump jar files of all the classes - // loaded in the core. Everything on the bootclasspath + // loaded in the core. Everything with null classloader // will go in boot.jar and everything else will go in - // app.jar. Then the classes can be loaded by the replay - // jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually - // not needed, unless changed by jvmti. + // app.jar. boot.jar usually not needed, unless changed by jvmti. public void doit(Tokens t) { int tcount = t.countTokens(); if (tcount > 2) { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java index e3a0793abad..3d4ffb0171b 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java @@ -84,7 +84,11 @@ public class SAGetopt { } else { // Mixed style options --file name - extractOptarg(ca[0]); + try { + extractOptarg(ca[0]); + } catch (ArrayIndexOutOfBoundsException e) { + throw new RuntimeException("Argument is expected for '" + ca[0] + "'"); + } } return ca[0]; diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java index 979763fda97..4b1f280a6d7 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java @@ -30,6 +30,7 @@ import java.util.Arrays; import sun.jvm.hotspot.tools.JStack; import sun.jvm.hotspot.tools.JMap; import sun.jvm.hotspot.tools.JInfo; +import sun.jvm.hotspot.tools.JSnap; public class SALauncher { @@ -39,6 +40,7 @@ public class SALauncher { System.out.println(" jstack --help\tto get more information"); System.out.println(" jmap --help\tto get more information"); System.out.println(" jinfo --help\tto get more information"); + System.out.println(" jsnap --help\tto get more information"); return false; } @@ -85,6 +87,11 @@ public class SALauncher { return commonHelp(); } + private static boolean jsnapHelp() { + System.out.println(" --all\tto print all performance counters"); + return commonHelp(); + } + private static boolean toolHelp(String toolName) { if (toolName.equals("jstack")) { return jstackHelp(); @@ -95,24 +102,62 @@ public class SALauncher { if (toolName.equals("jmap")) { return jmapHelp(); } + if (toolName.equals("jsnap")) { + return jsnapHelp(); + } if (toolName.equals("hsdb") || toolName.equals("clhsdb")) { return commonHelp(); } return launcherHelp(); } + private static void buildAttachArgs(ArrayList newArgs, + String pid, String exe, String core) { + if ((pid == null) && (exe == null)) { + throw new IllegalArgumentException( + "You have to set --pid or --exe."); + } + + if (pid != null) { // Attach to live process + if (exe != null) { + throw new IllegalArgumentException( + "Unnecessary argument: --exe"); + } else if (core != null) { + throw new IllegalArgumentException( + "Unnecessary argument: --core"); + } else if (!pid.matches("^\\d+$")) { + throw new IllegalArgumentException("Invalid pid: " + pid); + } + + newArgs.add(pid); + } else { + if (exe.length() == 0) { + throw new IllegalArgumentException("You have to set --exe."); + } + + newArgs.add(exe); + + if ((core == null) || (core.length() == 0)) { + throw new IllegalArgumentException("You have to set --core."); + } + + newArgs.add(core); + } + } + private static void runCLHSDB(String[] oldArgs) { SAGetopt sg = new SAGetopt(oldArgs); String[] longOpts = {"exe=", "core=", "pid="}; ArrayList newArgs = new ArrayList(); - String exeORpid = null; + String pid = null; + String exe = null; String core = null; String s = null; while((s = sg.next(null, longOpts)) != null) { if (s.equals("exe")) { - exeORpid = sg.getOptarg(); + exe = sg.getOptarg(); continue; } if (s.equals("core")) { @@ -120,17 +165,12 @@ public class SALauncher { continue; } if (s.equals("pid")) { - exeORpid = sg.getOptarg(); + pid = sg.getOptarg(); continue; } } - if (exeORpid != null) { - newArgs.add(exeORpid); - if (core != null) { - newArgs.add(core); - } - } + buildAttachArgs(newArgs, pid, exe, core); CLHSDB.main(newArgs.toArray(new String[newArgs.size()])); } @@ -139,13 +179,14 @@ public class SALauncher { String[] longOpts = {"exe=", "core=", "pid="}; ArrayList newArgs = new ArrayList(); - String exeORpid = null; + String pid = null; + String exe = null; String core = null; String s = null; while((s = sg.next(null, longOpts)) != null) { if (s.equals("exe")) { - exeORpid = sg.getOptarg(); + exe = sg.getOptarg(); continue; } if (s.equals("core")) { @@ -153,17 +194,12 @@ public class SALauncher { continue; } if (s.equals("pid")) { - exeORpid = sg.getOptarg(); + pid = sg.getOptarg(); continue; } } - if (exeORpid != null) { - newArgs.add(exeORpid); - if (core != null) { - newArgs.add(core); - } - } + buildAttachArgs(newArgs, pid, exe, core); HSDB.main(newArgs.toArray(new String[newArgs.size()])); } @@ -173,13 +209,14 @@ public class SALauncher { "mixed", "locks"}; ArrayList newArgs = new ArrayList(); - String exeORpid = null; + String pid = null; + String exe = null; String core = null; String s = null; while((s = sg.next(null, longOpts)) != null) { if (s.equals("exe")) { - exeORpid = sg.getOptarg(); + exe = sg.getOptarg(); continue; } if (s.equals("core")) { @@ -187,7 +224,7 @@ public class SALauncher { continue; } if (s.equals("pid")) { - exeORpid = sg.getOptarg(); + pid = sg.getOptarg(); continue; } if (s.equals("mixed")) { @@ -200,13 +237,7 @@ public class SALauncher { } } - if (exeORpid != null) { - newArgs.add(exeORpid); - if (core != null) { - newArgs.add(core); - } - } - + buildAttachArgs(newArgs, pid, exe, core); JStack.main(newArgs.toArray(new String[newArgs.size()])); } @@ -216,13 +247,14 @@ public class SALauncher { "heap", "binaryheap", "histo", "clstats", "finalizerinfo"}; ArrayList newArgs = new ArrayList(); - String exeORpid = null; + String pid = null; + String exe = null; String core = null; String s = null; while((s = sg.next(null, longOpts)) != null) { if (s.equals("exe")) { - exeORpid = sg.getOptarg(); + exe = sg.getOptarg(); continue; } if (s.equals("core")) { @@ -230,7 +262,7 @@ public class SALauncher { continue; } if (s.equals("pid")) { - exeORpid = sg.getOptarg(); + pid = sg.getOptarg(); continue; } if (s.equals("heap")) { @@ -255,13 +287,7 @@ public class SALauncher { } } - if (exeORpid != null) { - newArgs.add(exeORpid); - if (core != null) { - newArgs.add(core); - } - } - + buildAttachArgs(newArgs, pid, exe, core); JMap.main(newArgs.toArray(new String[newArgs.size()])); } @@ -271,13 +297,14 @@ public class SALauncher { "flags", "sysprops"}; ArrayList newArgs = new ArrayList(); - String exeORpid = null; + String exe = null; + String pid = null; String core = null; String s = null; while((s = sg.next(null, longOpts)) != null) { if (s.equals("exe")) { - exeORpid = sg.getOptarg(); + exe = sg.getOptarg(); continue; } if (s.equals("core")) { @@ -285,7 +312,7 @@ public class SALauncher { continue; } if (s.equals("pid")) { - exeORpid = sg.getOptarg(); + pid = sg.getOptarg(); continue; } if (s.equals("flags")) { @@ -298,14 +325,41 @@ public class SALauncher { } } - if (exeORpid != null) { - newArgs.add(exeORpid); - if (core != null) { - newArgs.add(core); + buildAttachArgs(newArgs, pid, exe, core); + JInfo.main(newArgs.toArray(new String[newArgs.size()])); + } + + private static void runJSNAP(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid=", "all"}; + + ArrayList newArgs = new ArrayList(); + String exe = null; + String pid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exe = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + pid = sg.getOptarg(); + continue; + } + if (s.equals("all")) { + newArgs.add("-a"); + continue; } } - JInfo.main(newArgs.toArray(new String[newArgs.size()])); + buildAttachArgs(newArgs, pid, exe, core); + JSnap.main(newArgs.toArray(new String[newArgs.size()])); } public static void main(String[] args) { @@ -329,31 +383,43 @@ public class SALauncher { String[] oldArgs = Arrays.copyOfRange(args, 1, args.length); - // Run SA interactive mode - if (args[0].equals("clhsdb")) { - runCLHSDB(oldArgs); - return; - } + try { + // Run SA interactive mode + if (args[0].equals("clhsdb")) { + runCLHSDB(oldArgs); + return; + } - if (args[0].equals("hsdb")) { - runHSDB(oldArgs); - return; - } + if (args[0].equals("hsdb")) { + runHSDB(oldArgs); + return; + } - // Run SA tmtools mode - if (args[0].equals("jstack")) { - runJSTACK(oldArgs); - return; - } + // Run SA tmtools mode + if (args[0].equals("jstack")) { + runJSTACK(oldArgs); + return; + } - if (args[0].equals("jmap")) { - runJMAP(oldArgs); - return; - } + if (args[0].equals("jmap")) { + runJMAP(oldArgs); + return; + } - if (args[0].equals("jinfo")) { - runJINFO(oldArgs); - return; + if (args[0].equals("jinfo")) { + runJINFO(oldArgs); + return; + } + + if (args[0].equals("jsnap")) { + runJSNAP(oldArgs); + return; + } + + throw new IllegalArgumentException("Unknown tool: " + args[0]); + } catch (Exception e) { + System.err.println(e.getMessage()); + toolHelp(args[0]); } } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java index 3b9655b922c..4f97ff61ebf 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java @@ -35,6 +35,11 @@ public enum GCCause { _gc_locker ("GCLocker Initiated GC"), _heap_inspection ("Heap Inspection Initiated GC"), _heap_dump ("Heap Dump Initiated GC"), + _wb_young_gc ("WhiteBox Initiated Young GC"), + _wb_conc_mark ("WhiteBox Initiated Concurrent Mark"), + _wb_full_gc ("WhiteBox Initiated Full GC"), + _update_allocation_context_stats_inc ("Update Allocation Context Stats"), + _update_allocation_context_stats_full ("Update Allocation Context Stats"), _no_gc ("No GC"), _no_cause_specified ("Unknown GCCause"), @@ -42,6 +47,7 @@ public enum GCCause { _tenured_generation_full ("Tenured Generation Full"), _metadata_GC_threshold ("Metadata GC Threshold"), + _metadata_GC_clear_soft_refs ("Metadata GC Clear Soft References"), _cms_generation_full ("CMS Generation Full"), _cms_initial_mark ("CMS Initial Mark"), @@ -55,7 +61,8 @@ public enum GCCause { _g1_inc_collection_pause ("G1 Evacuation Pause"), _g1_humongous_allocation ("G1 Humongous Allocation"), - _last_ditch_collection ("Last ditch collection"), + _dcmd_gc_run ("Diagnostic Command"), + _last_gc_cause ("ILLEGAL VALUE - last gc cause - ILLEGAL VALUE"); private final String value; diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java index dc99ffd76be..be256c24659 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java @@ -780,8 +780,8 @@ public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtu return getPath("java.class.path"); } - public List bootClassPath() { - return getPath("sun.boot.class.path"); + public List bootClassPath() { + return Collections.emptyList(); } public String baseDirectory() { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java index ec2cbbe9f4b..ce6ba6c8f37 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,10 @@ public class MethodCounters extends Metadata { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("MethodCounters"); - interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0); - interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0); + if (VM.getVM().isServerCompiler()) { + interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0); + interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0); + } if (!VM.getVM().isCore()) { invocationCounter = new CIntField(type.getCIntegerField("_invocation_counter"), 0); backedgeCounter = new CIntField(type.getCIntegerField("_backedge_counter"), 0); @@ -61,11 +63,19 @@ public class MethodCounters extends Metadata { private static CIntField backedgeCounter; public int interpreterInvocationCount() { - return (int) interpreterInvocationCountField.getValue(this); + if (interpreterInvocationCountField != null) { + return (int) interpreterInvocationCountField.getValue(this); + } else { + return 0; + } } public int interpreterThrowoutCount() { - return (int) interpreterThrowoutCountField.getValue(this); + if (interpreterThrowoutCountField != null) { + return (int) interpreterThrowoutCountField.getValue(this); + } else { + return 0; + } } public long getInvocationCounter() { if (Assert.ASSERTS_ENABLED) { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java index cdafa826127..cfcab6b8413 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ public class Threads { virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class); } // for now, use JavaThread itself. fix it later with appropriate class if needed - virtualConstructor.addMapping("SurrogateLockerThread", JavaThread.class); + virtualConstructor.addMapping("ReferencePendingListLockerThread", JavaThread.class); virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class); virtualConstructor.addMapping("ServiceThread", ServiceThread.class); } @@ -172,7 +172,7 @@ public class Threads { return thread; } catch (Exception e) { throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr + - " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, SurrogateLockerThread, or CodeCacheSweeperThread)", e); + " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, ReferencePendingListLockerThread, or CodeCacheSweeperThread)", e); } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java index fc281406d86..876b460051b 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java @@ -25,11 +25,15 @@ package sun.jvm.hotspot.tools; import java.io.*; +import java.util.*; +import java.util.stream.*; import sun.jvm.hotspot.debugger.JVMDebugger; import sun.jvm.hotspot.runtime.*; public class JSnap extends Tool { + private boolean all; + public JSnap() { super(); } @@ -45,7 +49,7 @@ public class JSnap extends Tool { if (prologue.accessible()) { PerfMemory.iterate(new PerfMemory.PerfDataEntryVisitor() { public boolean visit(PerfDataEntry pde) { - if (pde.supported()) { + if (all || pde.supported()) { out.print(pde.name()); out.print('='); out.println(pde.valueAsString()); @@ -62,8 +66,24 @@ public class JSnap extends Tool { } } + @Override + protected void printFlagsUsage() { + System.out.println(" -a\tto print all performance counters"); + super.printFlagsUsage(); + } + public static void main(String[] args) { JSnap js = new JSnap(); + js.all = Arrays.stream(args) + .anyMatch(s -> s.equals("-a")); + + if (js.all) { + args = Arrays.stream(args) + .filter(s -> !s.equals("-a")) + .collect(Collectors.toList()) + .toArray(new String[0]); + } + js.execute(args); } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java index d17c980bc7d..e5eefb0daa6 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java @@ -81,6 +81,12 @@ public class CompactHashTable extends VMObject { } public Symbol probe(byte[] name, long hash) { + + if (bucketCount() == 0) { + // The table is invalid, so don't try to lookup + return null; + } + long symOffset; Symbol sym; Address baseAddress = baseAddressField.getValue(addr); diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java index dbfe8183383..9074970a177 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java @@ -75,8 +75,6 @@ public class JSJavaVM extends DefaultScriptObject { return vm.getVMRelease(); case FIELD_CLASS_PATH: return getClassPath(); - case FIELD_BOOT_CLASS_PATH: - return getBootClassPath(); case FIELD_USER_DIR: return getUserDir(); case FIELD_UNDEFINED: @@ -143,7 +141,6 @@ public class JSJavaVM extends DefaultScriptObject { addField("type", FIELD_TYPE); addField("version", FIELD_VERSION); addField("classPath", FIELD_CLASS_PATH); - addField("bootClassPath", FIELD_BOOT_CLASS_PATH); addField("userDir", FIELD_USER_DIR); } @@ -217,10 +214,6 @@ public class JSJavaVM extends DefaultScriptObject { return vm.getSystemProperty("java.class.path"); } - private String getBootClassPath() { - return vm.getSystemProperty("sun.boot.class.path"); - } - private String getUserDir() { return vm.getSystemProperty("user.dir"); } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js index 58515933a3e..7a7f4501493 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -837,7 +837,7 @@ vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet; vmType2Class["JavaThread"] = sapkg.runtime.JavaThread; vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread; vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread; -vmType2Class["SurrogateLockerThread"] = sapkg.runtime.JavaThread; +vmType2Class["ReferencePendingListLockerThread"] = sapkg.runtime.JavaThread; vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread; // gc diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java index 3a74ac51d0d..b824f0cd8d3 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java @@ -23,7 +23,6 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotVMConfig.CompressEncoding; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -59,7 +58,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, Ho return true; } } else { - throw new JVMCIError("%s", metaspaceObject); + throw new IllegalArgumentException(String.valueOf(metaspaceObject)); } } return false; @@ -75,7 +74,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, Ho return prim.asLong(); } } - throw new JVMCIError("%s", base); + throw new IllegalArgumentException(String.valueOf(base)); } private static long readRawValue(Constant baseConstant, long displacement, int bits) { @@ -91,7 +90,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, Ho case Long.SIZE: return UNSAFE.getLong(base, displacement); default: - throw new JVMCIError("%d", bits); + throw new IllegalArgumentException(String.valueOf(bits)); } } else { long pointer = asRawPointer(baseConstant); @@ -105,7 +104,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, Ho case Long.SIZE: return UNSAFE.getLong(pointer + displacement); default: - throw new JVMCIError("%d", bits); + throw new IllegalArgumentException(String.valueOf(bits)); } } } @@ -178,7 +177,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, Ho case Double: return JavaConstant.forDouble(Double.longBitsToDouble(rawValue)); default: - throw new JVMCIError("Unsupported kind: %s", kind); + throw new IllegalArgumentException("Unsupported kind: " + kind); } } catch (NullPointerException e) { return null; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java index 71b75ecd01a..2f10d1073c6 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java @@ -35,8 +35,10 @@ public interface MemoryAccessProvider { * @param displacement the displacement within the object in bytes * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the * value cannot be read. + * @throws IllegalArgumentException if {@code kind} is {@link JavaKind#Void} or not + * {@linkplain JavaKind#isPrimitive() primitive} kind */ - JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant base, long displacement); + JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant base, long displacement) throws IllegalArgumentException; /** * Reads a primitive value using a base address and a displacement. @@ -46,8 +48,11 @@ public interface MemoryAccessProvider { * @param displacement the displacement within the object in bytes * @param bits the number of bits to read from memory * @return the read value encapsulated in a {@link JavaConstant} object of {@link JavaKind} kind + * @throws IllegalArgumentException if {@code kind} is {@link JavaKind#Void} or not + * {@linkplain JavaKind#isPrimitive() primitive} kind or {@code bits} is not 8, 16, + * 32 or 64 */ - JavaConstant readPrimitiveConstant(JavaKind kind, Constant base, long displacement, int bits); + JavaConstant readPrimitiveConstant(JavaKind kind, Constant base, long displacement, int bits) throws IllegalArgumentException; /** * Reads a Java {@link Object} value using a base address and a displacement. diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java index a6d26e9aeab..c533123ccd8 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java @@ -51,6 +51,8 @@ public interface MethodHandleAccessProvider { /** * Returns the method handle method intrinsic identifier for the provided method, or * {@code null} if the method is not an intrinsic processed by this interface. + * + * @throws NullPointerException if {@code method} is null */ IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method); @@ -58,19 +60,27 @@ public interface MethodHandleAccessProvider { * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns * {@code null} if the invocation target is not available at this time. - *

+ * * The first invocations of a method handle can use an interpreter to lookup the actual invoked * method; frequently executed method handles can use Java bytecode generation to avoid the * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should * try to generate bytecodes before this method returns. + * + * @returns {@code null} if {@code methodHandle} is not a {@link MethodHandle} or the invocation + * target is not available at this time + * @throws NullPointerException if {@code methodHandle} is null */ ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration); /** * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method * with the given constant member name. The member name is the last parameter of the - * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at - * this time. + * {@code linkTo*} method. + * + * @returns {@code null} if the invocation target is not available at this time + * @throws NullPointerException if {@code memberName} is null + * @throws IllegalArgumentException if {@code memberName} is not a + * {@code java.lang.invoke.MemberName} */ ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName); } diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 2193a9611a3..31002c5bd60 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -910,8 +910,8 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { - log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", - strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_warning(os, thread)("Failed to start thread - pthread_create failed (%d=%s) for attributes: %s.", + ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } pthread_attr_destroy(&attr); @@ -1178,7 +1178,7 @@ void os::die() { size_t os::lasterror(char *buf, size_t len) { if (errno == 0) return 0; - const char *s = ::strerror(errno); + const char *s = os::strerror(errno); size_t n = ::strlen(s); if (n >= len) { n = len - 1; @@ -1714,14 +1714,14 @@ static void local_sem_post() { if (os::Aix::on_aix()) { int rc = ::sem_post(&sig_sem); if (rc == -1 && !warn_only_once) { - trcVerbose("sem_post failed (errno = %d, %s)", errno, strerror(errno)); + trcVerbose("sem_post failed (errno = %d, %s)", errno, os::errno_name(errno)); warn_only_once = true; } } else { guarantee0(p_sig_msem != NULL); int rc = ::msem_unlock(p_sig_msem, 0); if (rc == -1 && !warn_only_once) { - trcVerbose("msem_unlock failed (errno = %d, %s)", errno, strerror(errno)); + trcVerbose("msem_unlock failed (errno = %d, %s)", errno, os::errno_name(errno)); warn_only_once = true; } } @@ -1732,14 +1732,14 @@ static void local_sem_wait() { if (os::Aix::on_aix()) { int rc = ::sem_wait(&sig_sem); if (rc == -1 && !warn_only_once) { - trcVerbose("sem_wait failed (errno = %d, %s)", errno, strerror(errno)); + trcVerbose("sem_wait failed (errno = %d, %s)", errno, os::errno_name(errno)); warn_only_once = true; } } else { guarantee0(p_sig_msem != NULL); // must init before use int rc = ::msem_lock(p_sig_msem, 0); if (rc == -1 && !warn_only_once) { - trcVerbose("msem_lock failed (errno = %d, %s)", errno, strerror(errno)); + trcVerbose("msem_lock failed (errno = %d, %s)", errno, os::errno_name(errno)); warn_only_once = true; } } @@ -2203,7 +2203,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, exec, - strerror(err), err); + os::errno_name(err), err); } #endif @@ -2412,7 +2412,7 @@ static bool checked_mprotect(char* addr, size_t size, int prot) { bool rc = ::mprotect(addr, size, prot) == 0 ? true : false; if (!rc) { - const char* const s_errno = strerror(errno); + const char* const s_errno = os::errno_name(errno); warning("mprotect(" PTR_FORMAT "-" PTR_FORMAT ", 0x%X) failed (%s).", addr, addr + size, prot, s_errno); return false; } @@ -2634,7 +2634,7 @@ OSReturn os::set_native_priority(Thread* thread, int newpri) { if (ret != 0) { trcVerbose("Could not change priority for thread %d to %d (error %d, %s)", - (int)thr, newpri, ret, strerror(ret)); + (int)thr, newpri, ret, os::errno_name(ret)); } return (ret == 0) ? OS_OK : OS_ERR; } diff --git a/hotspot/src/os/aix/vm/perfMemory_aix.cpp b/hotspot/src/os/aix/vm/perfMemory_aix.cpp index c2e7c0e4e90..e9621012b7b 100644 --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp @@ -30,6 +30,7 @@ #include "oops/oop.inline.hpp" #include "os_aix.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/os.hpp" #include "runtime/perfMemory.hpp" #include "services/memTracker.hpp" #include "utilities/exceptions.hpp" @@ -101,7 +102,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } } else { int fd = result; @@ -112,7 +113,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } break; } @@ -124,7 +125,7 @@ static void save_memory_to_file(char* addr, size_t size) { result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, strerror(errno)); + warning("Could not close %s: %s\n", destfile, os::strerror(errno)); } } } @@ -397,7 +398,7 @@ static DIR *open_directory_secure(const char* dirname) { if (errno == ELOOP) { warning("directory %s is a symlink and is not secure\n", dirname); } else { - warning("could not open directory %s: %s\n", dirname, strerror(errno)); + warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); } } return dirp; @@ -507,7 +508,7 @@ static bool is_file_secure(int fd, const char *filename) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, strerror(errno)); + warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); } return false; } @@ -543,7 +544,7 @@ static char* get_user_name(uid_t uid) { if (PrintMiscellaneous && Verbose) { if (result != 0) { warning("Could not retrieve passwd entry: %s\n", - strerror(result)); + os::strerror(result)); } else if (p == NULL) { // this check is added to protect against an observed problem @@ -557,7 +558,7 @@ static char* get_user_name(uid_t uid) { // Bug Id 89052 was opened with RedHat. // warning("Could not retrieve passwd entry: %s\n", - strerror(errno)); + os::strerror(errno)); } else { warning("Could not determine user name: %s\n", @@ -593,7 +594,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { "Process not found"); } else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); } } @@ -746,7 +747,7 @@ static void remove_file(const char* path) { if (PrintMiscellaneous && Verbose && result == OS_ERR) { if (errno != ENOENT) { warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, strerror(errno)); + " store file %s : %s\n", path, os::strerror(errno)); } } } @@ -849,7 +850,7 @@ static bool make_user_tmp_dir(const char* dirname) { // if (PrintMiscellaneous && Verbose) { warning("could not create directory %s: %s\n", - dirname, strerror(errno)); + dirname, os::strerror(errno)); } return false; } @@ -900,7 +901,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, if (errno == ELOOP) { warning("file %s is a symlink and is not secure\n", filename); } else { - warning("could not create file %s: %s\n", filename, strerror(errno)); + warning("could not create file %s: %s\n", filename, os::strerror(errno)); } } // Close the directory and reset the current working directory. @@ -924,7 +925,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", strerror(errno)); + warning("could not truncate shared memory file: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -933,7 +934,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", strerror(errno)); + warning("could not set shared memory file size: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -968,7 +969,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { "Permission denied"); } else { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); } } int fd = result; @@ -1041,7 +1042,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", strerror(errno)); + warning("mmap failed - %s\n", os::strerror(errno)); } remove_file(filename); FREE_C_HEAP_ARRAY(char, filename); @@ -1109,7 +1110,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", strerror(errno)); + warning("fstat failed: %s\n", os::strerror(errno)); } THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); @@ -1231,7 +1232,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", strerror(errno)); + warning("mmap failed: %s\n", os::strerror(errno)); } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 3d6f8fd6422..9cf4f74d2cf 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -789,7 +789,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", - strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } pthread_attr_destroy(&attr); @@ -1122,7 +1122,7 @@ void os::die() { size_t os::lasterror(char *buf, size_t len) { if (errno == 0) return 0; - const char *s = ::strerror(errno); + const char *s = os::strerror(errno); size_t n = ::strlen(s); if (n >= len) { n = len - 1; @@ -2141,7 +2141,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, exec, - strerror(err), err); + os::errno_name(err), err); } // NOTE: Bsd kernel does not really reserve the pages for us. @@ -3422,7 +3422,7 @@ void os::init(void) { Bsd::set_page_size(getpagesize()); if (Bsd::page_size() == -1) { - fatal("os_bsd.cpp: os::init: sysconf failed (%s)", strerror(errno)); + fatal("os_bsd.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); } init_page_sizes((size_t) Bsd::page_size()); diff --git a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp index b4c7328914c..f87f81dcabe 100644 --- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp +++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "oops/oop.inline.hpp" #include "os_bsd.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/os.hpp" #include "runtime/perfMemory.hpp" #include "services/memTracker.hpp" #include "utilities/exceptions.hpp" @@ -100,7 +101,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } } else { int fd = result; @@ -111,7 +112,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } break; } @@ -123,7 +124,7 @@ static void save_memory_to_file(char* addr, size_t size) { result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, strerror(errno)); + warning("Could not close %s: %s\n", destfile, os::strerror(errno)); } } } @@ -309,7 +310,7 @@ static DIR *open_directory_secure(const char* dirname) { if (errno == ELOOP) { warning("directory %s is a symlink and is not secure\n", dirname); } else { - warning("could not open directory %s: %s\n", dirname, strerror(errno)); + warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); } } return dirp; @@ -420,7 +421,7 @@ static bool is_file_secure(int fd, const char *filename) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, strerror(errno)); + warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); } return false; } @@ -459,7 +460,7 @@ static char* get_user_name(uid_t uid) { if (PrintMiscellaneous && Verbose) { if (result != 0) { warning("Could not retrieve passwd entry: %s\n", - strerror(result)); + os::strerror(result)); } else if (p == NULL) { // this check is added to protect against an observed problem @@ -473,7 +474,7 @@ static char* get_user_name(uid_t uid) { // Bug Id 89052 was opened with RedHat. // warning("Could not retrieve passwd entry: %s\n", - strerror(errno)); + os::strerror(errno)); } else { warning("Could not determine user name: %s\n", @@ -509,7 +510,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { "Process not found"); } else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); } } @@ -652,7 +653,7 @@ static void remove_file(const char* path) { if (PrintMiscellaneous && Verbose && result == OS_ERR) { if (errno != ENOENT) { warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, strerror(errno)); + " store file %s : %s\n", path, os::strerror(errno)); } } } @@ -762,7 +763,7 @@ static bool make_user_tmp_dir(const char* dirname) { // if (PrintMiscellaneous && Verbose) { warning("could not create directory %s: %s\n", - dirname, strerror(errno)); + dirname, os::strerror(errno)); } return false; } @@ -804,7 +805,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, if (errno == ELOOP) { warning("file %s is a symlink and is not secure\n", filename); } else { - warning("could not create file %s: %s\n", filename, strerror(errno)); + warning("could not create file %s: %s\n", filename, os::strerror(errno)); } } // close the directory and reset the current working directory @@ -828,7 +829,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", strerror(errno)); + warning("could not truncate shared memory file: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -837,7 +838,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", strerror(errno)); + warning("could not set shared memory file size: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -887,7 +888,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { "Permission denied", OS_ERR); } else { - THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); + THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR); } } int fd = result; @@ -961,7 +962,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", strerror(errno)); + warning("mmap failed - %s\n", os::strerror(errno)); } remove_file(filename); FREE_C_HEAP_ARRAY(char, filename); @@ -1025,7 +1026,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", strerror(errno)); + warning("fstat failed: %s\n", os::strerror(errno)); } THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); @@ -1136,7 +1137,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", strerror(errno)); + warning("mmap failed: %s\n", os::strerror(errno)); } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index f3896ed96a0..d8811d46528 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -594,15 +594,7 @@ void os::Linux::libpthread_init() { // _expand_stack_to() assumes its frame size is less than page size, which // should always be true if the function is not inlined. -#if __GNUC__ < 3 // gcc 2.x does not support noinline attribute - #define NOINLINE -#else - #define NOINLINE __attribute__ ((noinline)) -#endif - -static void _expand_stack_to(address bottom) NOINLINE; - -static void _expand_stack_to(address bottom) { +static void NOINLINE _expand_stack_to(address bottom) { address sp; size_t size; volatile char *p; @@ -769,7 +761,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", - strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } pthread_attr_destroy(&attr); @@ -890,6 +882,13 @@ void os::free_thread(OSThread* osthread) { assert(osthread != NULL, "osthread not set"); if (Thread::current()->osthread() == osthread) { +#ifdef ASSERT + sigset_t current; + sigemptyset(¤t); + pthread_sigmask(SIG_SETMASK, NULL, ¤t); + assert(!sigismember(¤t, SR_signum), "SR signal should not be blocked!"); +#endif + // Restore caller's signal mask sigset_t sigmask = osthread->caller_sigmask(); pthread_sigmask(SIG_SETMASK, &sigmask, NULL); @@ -1395,7 +1394,7 @@ void os::die() { size_t os::lasterror(char *buf, size_t len) { if (errno == 0) return 0; - const char *s = ::strerror(errno); + const char *s = os::strerror(errno); size_t n = ::strlen(s); if (n >= len) { n = len - 1; @@ -2601,7 +2600,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, exec, - strerror(err), err); + os::strerror(err), err); } static void warn_fail_commit_memory(char* addr, size_t size, @@ -2609,7 +2608,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, - alignment_hint, exec, strerror(err), err); + alignment_hint, exec, os::strerror(err), err); } // NOTE: Linux kernel does not really reserve the pages for us. @@ -3912,7 +3911,8 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { // after sigsuspend. int old_errno = errno; - Thread* thread = Thread::current(); + Thread* thread = Thread::current_or_null_safe(); + assert(thread != NULL, "Missing current thread in SR_handler"); OSThread* osthread = thread->osthread(); assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); @@ -3924,7 +3924,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { os::SuspendResume::State state = osthread->sr.suspended(); if (state == os::SuspendResume::SR_SUSPENDED) { sigset_t suspend_set; // signals for sigsuspend() - + sigemptyset(&suspend_set); // get current set of blocked signals and unblock resume signal pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); sigdelset(&suspend_set, SR_signum); @@ -4178,6 +4178,7 @@ static bool call_chained_handler(struct sigaction *actp, int sig, // try to honor the signal mask sigset_t oset; + sigemptyset(&oset); pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset); // call into the chained handler @@ -4188,7 +4189,7 @@ static bool call_chained_handler(struct sigaction *actp, int sig, } // restore the signal mask - pthread_sigmask(SIG_SETMASK, &oset, 0); + pthread_sigmask(SIG_SETMASK, &oset, NULL); } // Tell jvm's signal handler the signal is taken care of. return true; @@ -4615,7 +4616,7 @@ void os::init(void) { Linux::set_page_size(sysconf(_SC_PAGESIZE)); if (Linux::page_size() == -1) { fatal("os_linux.cpp: os::init: sysconf failed (%s)", - strerror(errno)); + os::strerror(errno)); } init_page_sizes((size_t) Linux::page_size()); @@ -4633,7 +4634,7 @@ void os::init(void) { int status; pthread_condattr_t* _condattr = os::Linux::condAttr(); if ((status = pthread_condattr_init(_condattr)) != 0) { - fatal("pthread_condattr_init: %s", strerror(status)); + fatal("pthread_condattr_init: %s", os::strerror(status)); } // Only set the clock if CLOCK_MONOTONIC is available if (os::supports_monotonic_clock()) { @@ -4642,7 +4643,7 @@ void os::init(void) { warning("Unable to use monotonic clock with relative timed-waits" \ " - changes to the time-of-day clock may have adverse affects"); } else { - fatal("pthread_condattr_setclock: %s", strerror(status)); + fatal("pthread_condattr_setclock: %s", os::strerror(status)); } } } @@ -4888,7 +4889,7 @@ int os::active_processor_count() { log_trace(os)("active_processor_count: " "CPU_ALLOC failed (%s) - using " "online processor count: %d", - strerror(errno), online_cpus); + os::strerror(errno), online_cpus); return online_cpus; } } @@ -4918,7 +4919,7 @@ int os::active_processor_count() { else { cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN); warning("sched_getaffinity failed (%s)- using online processor count (%d) " - "which may exceed available processors", strerror(errno), cpu_count); + "which may exceed available processors", os::strerror(errno), cpu_count); } if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used @@ -5769,6 +5770,7 @@ void Parker::park(bool isAbsolute, jlong time) { // Don't catch signals while blocked; let the running threads have the signals. // (This allows a debugger to break into the running thread.) sigset_t oldsigs; + sigemptyset(&oldsigs); sigset_t* allowdebug_blocked = os::Linux::allowdebug_blocked_signals(); pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs); #endif diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp index d2f1fab4f6b..610a1a0263e 100644 --- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp +++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "oops/oop.inline.hpp" #include "os_linux.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/os.hpp" #include "runtime/perfMemory.hpp" #include "services/memTracker.hpp" #include "utilities/exceptions.hpp" @@ -100,7 +101,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } } else { int fd = result; @@ -111,7 +112,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } break; } @@ -123,7 +124,7 @@ static void save_memory_to_file(char* addr, size_t size) { result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, strerror(errno)); + warning("Could not close %s: %s\n", destfile, os::strerror(errno)); } } } @@ -308,7 +309,7 @@ static DIR *open_directory_secure(const char* dirname) { if (errno == ELOOP) { warning("directory %s is a symlink and is not secure\n", dirname); } else { - warning("could not open directory %s: %s\n", dirname, strerror(errno)); + warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); } } return dirp; @@ -419,7 +420,7 @@ static bool is_file_secure(int fd, const char *filename) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, strerror(errno)); + warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); } return false; } @@ -459,7 +460,7 @@ static char* get_user_name(uid_t uid) { if (PrintMiscellaneous && Verbose) { if (result != 0) { warning("Could not retrieve passwd entry: %s\n", - strerror(result)); + os::strerror(result)); } else if (p == NULL) { // this check is added to protect against an observed problem @@ -473,7 +474,7 @@ static char* get_user_name(uid_t uid) { // Bug Id 89052 was opened with RedHat. // warning("Could not retrieve passwd entry: %s\n", - strerror(errno)); + os::strerror(errno)); } else { warning("Could not determine user name: %s\n", @@ -509,7 +510,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { "Process not found"); } else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); } } @@ -664,7 +665,7 @@ static void remove_file(const char* path) { if (PrintMiscellaneous && Verbose && result == OS_ERR) { if (errno != ENOENT) { warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, strerror(errno)); + " store file %s : %s\n", path, os::strerror(errno)); } } } @@ -772,7 +773,7 @@ static bool make_user_tmp_dir(const char* dirname) { // if (PrintMiscellaneous && Verbose) { warning("could not create directory %s: %s\n", - dirname, strerror(errno)); + dirname, os::strerror(errno)); } return false; } @@ -814,7 +815,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, if (errno == ELOOP) { warning("file %s is a symlink and is not secure\n", filename); } else { - warning("could not create file %s: %s\n", filename, strerror(errno)); + warning("could not create file %s: %s\n", filename, os::strerror(errno)); } } // close the directory and reset the current working directory @@ -838,7 +839,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", strerror(errno)); + warning("could not truncate shared memory file: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -847,7 +848,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", strerror(errno)); + warning("could not set shared memory file size: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -897,7 +898,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { "Permission denied", OS_ERR); } else { - THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); + THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR); } } int fd = result; @@ -970,7 +971,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", strerror(errno)); + warning("mmap failed - %s\n", os::strerror(errno)); } remove_file(filename); FREE_C_HEAP_ARRAY(char, filename); @@ -1034,7 +1035,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", strerror(errno)); + warning("fstat failed: %s\n", os::strerror(errno)); } THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); @@ -1151,7 +1152,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", strerror(errno)); + warning("mmap failed: %s\n", os::strerror(errno)); } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index d80ada11db9..6d683eec706 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -1144,7 +1144,8 @@ void os::WatcherThreadCrashProtection::check_crash_protection(int sig, #define check_with_errno(check_type, cond, msg) \ do { \ int err = errno; \ - check_type(cond, "%s; error='%s' (errno=%d)", msg, strerror(err), err); \ + check_type(cond, "%s; error='%s' (errno=%s)", msg, os::strerror(err), \ + os::errno_name(err)); \ } while (false) #define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg) diff --git a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp index 1426356dade..b6a4b434940 100644 --- a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp +++ b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -461,7 +461,7 @@ SolarisAttachOperation* SolarisAttachListener::dequeue() { while ((res = ::sema_wait(wakeup())) == EINTR) ; if (res) { - warning("sema_wait failed: %s", strerror(res)); + warning("sema_wait failed: %s", os::strerror(res)); return NULL; } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index bc8138db6ff..d64b56a3a5a 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1009,7 +1009,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); } else { log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", - strerror(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); } if (status != 0) { @@ -1354,7 +1354,7 @@ jlong getTimeMillis() { jlong os::javaTimeMillis() { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal("os::javaTimeMillis: gettimeofday (%s)", strerror(errno)); + fatal("os::javaTimeMillis: gettimeofday (%s)", os::strerror(errno)); } return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000; } @@ -1362,7 +1362,7 @@ jlong os::javaTimeMillis() { void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno)); + fatal("os::javaTimeSystemUTC: gettimeofday (%s)", os::strerror(errno)); } seconds = jlong(t.tv_sec); nanos = jlong(t.tv_usec) * 1000; @@ -1892,21 +1892,39 @@ void os::Solaris::print_libversion_info(outputStream* st) { static bool check_addr0(outputStream* st) { jboolean status = false; + const int read_chunk = 200; + int ret = 0; + int nmap = 0; int fd = ::open("/proc/self/map",O_RDONLY); if (fd >= 0) { - prmap_t p; - while (::read(fd, &p, sizeof(p)) > 0) { - if (p.pr_vaddr == 0x0) { - st->print("Warning: Address: 0x%x, Size: %dK, ",p.pr_vaddr, p.pr_size/1024, p.pr_mapname); - st->print("Mapped file: %s, ", p.pr_mapname[0] == '\0' ? "None" : p.pr_mapname); - st->print("Access:"); - st->print("%s",(p.pr_mflags & MA_READ) ? "r" : "-"); - st->print("%s",(p.pr_mflags & MA_WRITE) ? "w" : "-"); - st->print("%s",(p.pr_mflags & MA_EXEC) ? "x" : "-"); - st->cr(); - status = true; + prmap_t *p = NULL; + char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t)); + if (NULL == mbuff) { + ::close(fd); + return status; + } + while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) { + //check if read() has not read partial data + if( 0 != ret % sizeof(prmap_t)){ + break; + } + nmap = ret / sizeof(prmap_t); + p = (prmap_t *)mbuff; + for(int i = 0; i < nmap; i++){ + if (p->pr_vaddr == 0x0) { + st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024); + st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname); + st->print("Access: "); + st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-"); + st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-"); + st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-"); + st->cr(); + status = true; + } + p++; } } + free(mbuff); ::close(fd); } return status; @@ -2142,7 +2160,7 @@ void os::print_jni_name_suffix_on(outputStream* st, int args_size) { size_t os::lasterror(char *buf, size_t len) { if (errno == 0) return 0; - const char *s = ::strerror(errno); + const char *s = os::strerror(errno); size_t n = ::strlen(s); if (n >= len) { n = len - 1; @@ -2351,7 +2369,7 @@ static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes, exec, - strerror(err), err); + os::strerror(err), err); } static void warn_fail_commit_memory(char* addr, size_t bytes, @@ -2359,7 +2377,7 @@ static void warn_fail_commit_memory(char* addr, size_t bytes, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes, - alignment_hint, exec, strerror(err), err); + alignment_hint, exec, os::strerror(err), err); } int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { @@ -2740,7 +2758,7 @@ char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { char buf[256]; buf[0] = '\0'; if (addr == NULL) { - jio_snprintf(buf, sizeof(buf), ": %s", strerror(err)); + jio_snprintf(buf, sizeof(buf), ": %s", os::strerror(err)); } warning("attempt_reserve_memory_at: couldn't reserve " SIZE_FORMAT " bytes at " PTR_FORMAT ": reserve_memory_helper returned " PTR_FORMAT @@ -4354,7 +4372,7 @@ void os::init(void) { page_size = sysconf(_SC_PAGESIZE); if (page_size == -1) { - fatal("os_solaris.cpp: os::init: sysconf failed (%s)", strerror(errno)); + fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); } init_page_sizes((size_t) page_size); @@ -4366,7 +4384,7 @@ void os::init(void) { int fd = ::open("/dev/zero", O_RDWR); if (fd < 0) { - fatal("os::init: cannot open /dev/zero (%s)", strerror(errno)); + fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno)); } else { Solaris::set_dev_zero_fd(fd); @@ -5607,7 +5625,7 @@ int os::fork_and_exec(char* cmd) { if (pid < 0) { // fork failed - warning("fork failed: %s", strerror(errno)); + warning("fork failed: %s", os::strerror(errno)); return -1; } else if (pid == 0) { diff --git a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp index 72bf36a0a87..a5bfbb7f555 100644 --- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp +++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,7 +102,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } } else { @@ -114,7 +114,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } break; } @@ -125,7 +125,7 @@ static void save_memory_to_file(char* addr, size_t size) { result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, strerror(errno)); + warning("Could not close %s: %s\n", destfile, os::strerror(errno)); } } } @@ -311,7 +311,7 @@ static DIR *open_directory_secure(const char* dirname) { if (errno == ELOOP) { warning("directory %s is a symlink and is not secure\n", dirname); } else { - warning("could not open directory %s: %s\n", dirname, strerror(errno)); + warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); } } return dirp; @@ -422,7 +422,7 @@ static bool is_file_secure(int fd, const char *filename) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, strerror(errno)); + warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); } return false; } @@ -464,7 +464,7 @@ static char* get_user_name(uid_t uid) { if (PrintMiscellaneous && Verbose) { if (p == NULL) { warning("Could not retrieve passwd entry: %s\n", - strerror(errno)); + os::strerror(errno)); } else { warning("Could not determine user name: %s\n", @@ -500,7 +500,7 @@ static char* get_user_name_slow(int vmid, TRAPS) { "Process not found"); } else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); } } @@ -657,7 +657,7 @@ static char* get_user_name(int vmid, TRAPS) { // In this case, the psinfo file for the process id existed, // but we didn't have permission to access it. THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - strerror(errno)); + os::strerror(errno)); } // at this point, we don't know if the process id itself doesn't @@ -703,7 +703,7 @@ static void remove_file(const char* path) { if (PrintMiscellaneous && Verbose && result == OS_ERR) { if (errno != ENOENT) { warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, strerror(errno)); + " store file %s : %s\n", path, os::strerror(errno)); } } } @@ -813,7 +813,7 @@ static bool make_user_tmp_dir(const char* dirname) { // if (PrintMiscellaneous && Verbose) { warning("could not create directory %s: %s\n", - dirname, strerror(errno)); + dirname, os::strerror(errno)); } return false; } @@ -855,7 +855,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, if (errno == ELOOP) { warning("file %s is a symlink and is not secure\n", filename); } else { - warning("could not create file %s: %s\n", filename, strerror(errno)); + warning("could not create file %s: %s\n", filename, os::strerror(errno)); } } // close the directory and reset the current working directory @@ -879,7 +879,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", strerror(errno)); + warning("could not truncate shared memory file: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -888,7 +888,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", strerror(errno)); + warning("could not set shared memory file size: %s\n", os::strerror(errno)); } ::close(fd); return -1; @@ -916,7 +916,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { "Permission denied", OS_ERR); } else { - THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); + THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR); } } int fd = result; @@ -990,7 +990,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", strerror(errno)); + warning("mmap failed - %s\n", os::strerror(errno)); } remove_file(filename); FREE_C_HEAP_ARRAY(char, filename); @@ -1055,7 +1055,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", strerror(errno)); + warning("fstat failed: %s\n", os::strerror(errno)); } THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); @@ -1172,7 +1172,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor if (mapAddress == MAP_FAILED) { if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", strerror(errno)); + warning("mmap failed: %s\n", os::strerror(errno)); } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); diff --git a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp index 509c845636a..53bd865b592 100644 --- a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp +++ b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "runtime/os.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadCritical.hpp" @@ -49,7 +50,7 @@ ThreadCritical::ThreadCritical() { if (global_mut_owner != owner) { if (os::Solaris::mutex_lock(&global_mut)) fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", - strerror(errno)); + os::strerror(errno)); assert(global_mut_count == 0, "must have clean count"); assert(global_mut_owner == -1, "must have clean owner"); } @@ -68,7 +69,7 @@ ThreadCritical::~ThreadCritical() { if (global_mut_count == 0) { global_mut_owner = -1; if (os::Solaris::mutex_unlock(&global_mut)) - fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", strerror(errno)); + fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", os::strerror(errno)); } } else { assert (Threads::number_of_threads() == 0, "valid only during initialization"); diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0e009368a62..f85eb0f273c 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -642,7 +642,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); } else { log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.", - strerror(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); } if (thread_handle == NULL) { @@ -1898,7 +1898,7 @@ size_t os::lasterror(char* buf, size_t len) { if (errno != 0) { // C runtime error that has no corresponding DOS error code - const char* s = strerror(errno); + const char* s = os::strerror(errno); size_t n = strlen(s); if (n >= len) n = len - 1; strncpy(buf, s, n); @@ -2186,13 +2186,6 @@ extern "C" void events(); // Windows Vista/2008 heap corruption check #define EXCEPTION_HEAP_CORRUPTION 0xC0000374 -#define def_excpt(val) #val, val - -struct siglabel { - char *name; - int number; -}; - // All Visual C++ exceptions thrown from code generated by the Microsoft Visual // C++ compiler contain this error code. Because this is a compiler-generated // error, the code is not listed in the Win32 API header files. @@ -2202,8 +2195,9 @@ struct siglabel { #define EXCEPTION_UNCAUGHT_CXX_EXCEPTION 0xE06D7363 +#define def_excpt(val) { #val, (val) } -struct siglabel exceptlabels[] = { +static const struct { char* name; uint number; } exceptlabels[] = { def_excpt(EXCEPTION_ACCESS_VIOLATION), def_excpt(EXCEPTION_DATATYPE_MISALIGNMENT), def_excpt(EXCEPTION_BREAKPOINT), @@ -2228,16 +2222,18 @@ struct siglabel exceptlabels[] = { def_excpt(EXCEPTION_GUARD_PAGE), def_excpt(EXCEPTION_INVALID_HANDLE), def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION), - def_excpt(EXCEPTION_HEAP_CORRUPTION), + def_excpt(EXCEPTION_HEAP_CORRUPTION) #ifdef _M_IA64 - def_excpt(EXCEPTION_REG_NAT_CONSUMPTION), + , def_excpt(EXCEPTION_REG_NAT_CONSUMPTION) #endif - NULL, 0 }; +#undef def_excpt + const char* os::exception_name(int exception_code, char *buf, size_t size) { - for (int i = 0; exceptlabels[i].name != NULL; i++) { - if (exceptlabels[i].number == exception_code) { + uint code = static_cast(exception_code); + for (uint i = 0; i < ARRAY_SIZE(exceptlabels); ++i) { + if (exceptlabels[i].number == code) { jio_snprintf(buf, size, "%s", exceptlabels[i].name); return buf; } @@ -2445,7 +2441,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { jio_snprintf(buf, sizeof(buf), "Execution protection violation " "at " INTPTR_FORMAT ", unguarding " INTPTR_FORMAT ": %s", addr, - page_start, (res ? "success" : strerror(errno))); + page_start, (res ? "success" : os::strerror(errno))); tty->print_raw_cr(buf); } @@ -5638,9 +5634,11 @@ int os::get_signal_number(const char* name) { "TERM", SIGTERM, // software term signal from kill "BREAK", SIGBREAK, // Ctrl-Break sequence "ILL", SIGILL}; // illegal instruction - for(int i=0;i 0;) { @@ -105,7 +105,7 @@ static void save_memory_to_file(char* addr, size_t size) { if (nbytes == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", - destfile, strerror(errno)); + destfile, os::strerror(errno)); } break; } @@ -117,7 +117,7 @@ static void save_memory_to_file(char* addr, size_t size) { int result = ::_close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, strerror(errno)); + warning("Could not close %s: %s\n", destfile, os::strerror(errno)); } } } @@ -497,7 +497,7 @@ static void remove_file(const char* dirname, const char* filename) { if (PrintMiscellaneous && Verbose) { if (errno != ENOENT) { warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, strerror(errno)); + " store file %s : %s\n", path, os::strerror(errno)); } } } @@ -1358,7 +1358,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena if (ret_code == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not get status information from file %s: %s\n", - filename, strerror(errno)); + filename, os::strerror(errno)); } CloseHandle(fmh); CloseHandle(fh); @@ -1553,7 +1553,7 @@ static size_t sharedmem_filesize(const char* filename, TRAPS) { // if (::stat(filename, &statbuf) == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("stat %s failed: %s\n", filename, strerror(errno)); + warning("stat %s failed: %s\n", filename, os::strerror(errno)); } THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 284091dc09c..d71b9a760df 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "interpreter/interpreter.hpp" #include "jvm_windows.h" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "mutex_windows.inline.hpp" #include "nativeInst_x86.hpp" #include "os_share_windows.hpp" diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index 1a102cabe8b..4af0a5f56e1 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,9 @@ #include "code/debugInfoRec.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerDirectives.hpp" +#include "memory/resourceArea.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/timerTrace.hpp" typedef enum { _t_compile, diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index a15a521adaf..172e26eb4d9 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ #include "ci/ciMemberName.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/bytecode.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/compilationPolicy.hpp" diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index 105d27fcc0c..459b377e2ff 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "c1/c1_IR.hpp" #include "c1/c1_InstructionPrinter.hpp" #include "c1/c1_Optimizer.hpp" +#include "memory/resourceArea.hpp" #include "utilities/bitMap.inline.hpp" diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index 7f33a2c4d22..230a7bf0273 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -556,17 +556,16 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) { leal(op->in_opr(), op->result_opr()); break; - case lir_null_check: - if (GenerateCompilerNullChecks) { - ImplicitNullCheckStub* stub = add_debug_info_for_null_check_here(op->info()); + case lir_null_check: { + ImplicitNullCheckStub* stub = add_debug_info_for_null_check_here(op->info()); - if (op->in_opr()->is_single_cpu()) { - _masm->null_check(op->in_opr()->as_register(), stub->entry()); - } else { - Unimplemented(); - } + if (op->in_opr()->is_single_cpu()) { + _masm->null_check(op->in_opr()->as_register(), stub->entry()); + } else { + Unimplemented(); } break; + } case lir_monaddr: monitor_address(op->in_opr()->as_constant_ptr()->as_jint(), op->result_opr()); diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 03438c5ee8e..3c8454e5260 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2041,8 +2041,7 @@ void LIRGenerator::do_Throw(Throw* x) { // to avoid a fixed interval with an oop during the null check. // Use a copy of the CodeEmitInfo because debug information is // different for null_check and throw. - if (GenerateCompilerNullChecks && - (x->exception()->as_NewInstance() == NULL && x->exception()->as_ExceptionObject() == NULL)) { + if (x->exception()->as_NewInstance() == NULL && x->exception()->as_ExceptionObject() == NULL) { // if the exception object wasn't created using new then it might be null. __ null_check(exception_opr, new CodeEmitInfo(info, x->state()->copy(ValueStack::ExceptionState, x->state()->bci()))); } diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index eb49e97d896..82e162c2225 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -32,6 +32,7 @@ #include "c1/c1_LinearScan.hpp" #include "c1/c1_ValueStack.hpp" #include "code/vmreg.inline.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/bitMap.inline.hpp" #ifndef PRODUCT diff --git a/hotspot/src/share/vm/c1/c1_Optimizer.cpp b/hotspot/src/share/vm/c1/c1_Optimizer.cpp index b44d74e12b4..3e61edda30e 100644 --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "c1/c1_ValueMap.hpp" #include "c1/c1_ValueSet.hpp" #include "c1/c1_ValueStack.hpp" +#include "memory/resourceArea.hpp" #include "utilities/bitMap.inline.hpp" #include "compiler/compileLog.hpp" diff --git a/hotspot/src/share/vm/c1/c1_ValueType.cpp b/hotspot/src/share/vm/c1/c1_ValueType.cpp index 5f86a8b9309..7944af8d304 100644 --- a/hotspot/src/share/vm/c1/c1_ValueType.cpp +++ b/hotspot/src/share/vm/c1/c1_ValueType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "ci/ciArray.hpp" #include "ci/ciInstance.hpp" #include "ci/ciNullObject.hpp" +#include "memory/resourceArea.hpp" // predefined types diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index 168262cf20a..ad6548e4928 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -176,7 +176,7 @@ product(bool, InlineSynchronizedMethods, true, \ "Inline synchronized methods") \ \ - diagnostic(bool, InlineNIOCheckIndex, true, \ + develop(bool, InlineNIOCheckIndex, true, \ "Intrinsify java.nio.Buffer.checkIndex") \ \ develop(bool, CanonicalizeNodes, true, \ diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 4170a2375ba..697c559151f 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp index 8ed8fcef211..dbb3b31a741 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "classfile/systemDictionary.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/fieldStreams.hpp" #include "runtime/fieldDescriptor.hpp" diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index 0181836f6cb..65e77c13f8a 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -1,4 +1,5 @@ -/* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +29,7 @@ #include "ci/ciKlass.hpp" #include "ci/ciUtilities.hpp" #include "compiler/compileBroker.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -574,7 +576,7 @@ class CompileReplay : public StackObj { Method* method = parse_method(CHECK); if (had_error()) return; /* just copied from Method, to build interpret data*/ - if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { + if (ReferencePendingListLocker::is_locked_by_self()) { return; } // To be properly initialized, some profiling in the MDO needs the diff --git a/hotspot/src/share/vm/ci/ciSignature.cpp b/hotspot/src/share/vm/ci/ciSignature.cpp index 79f80d2bf81..5b55ca4022c 100644 --- a/hotspot/src/share/vm/ci/ciSignature.cpp +++ b/hotspot/src/share/vm/ci/ciSignature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "ci/ciSignature.hpp" #include "ci/ciUtilities.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/signature.hpp" diff --git a/hotspot/src/share/vm/ci/ciType.cpp b/hotspot/src/share/vm/ci/ciType.cpp index 32ba363ac6d..7c3ffdb4a33 100644 --- a/hotspot/src/share/vm/ci/ciType.cpp +++ b/hotspot/src/share/vm/ci/ciType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "ci/ciType.hpp" #include "ci/ciUtilities.hpp" #include "classfile/systemDictionary.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" ciType* ciType::_basic_types[T_CONFLICT+1]; diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index 2edfa7d4abe..e15db27c3da 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/bytecodes.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "opto/compile.hpp" #include "opto/node.hpp" diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 3be9d2f9b47..cedf1b48509 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1967,7 +1967,7 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, loader_data->is_platform_class_loader_data() || loader_data->is_anonymous(); switch (sid) { - case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): { + case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): { if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_CallerSensitive; @@ -5372,12 +5372,12 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa } } - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { ResourceMark rm; // print out the superclass. const char * from = ik->external_name(); if (ik->java_super() != NULL) { - log_info(classresolve)("%s %s (super)", + log_debug(classresolve)("%s %s (super)", from, ik->java_super()->external_name()); } @@ -5388,7 +5388,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa for (int i = 0; i < length; i++) { const Klass* const k = local_interfaces->at(i); const char * to = k->external_name(); - log_info(classresolve)("%s %s (interface)", from, to); + log_debug(classresolve)("%s %s (interface)", from, to); } } } @@ -5698,15 +5698,16 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, } if (!is_internal()) { - if (TraceClassLoadingPreorder) { - tty->print("[Loading %s", - _class_name->as_klass_external_name()); - + if (log_is_enabled(Debug, classload, preorder)){ + ResourceMark rm(THREAD); + outputStream* log = Log(classload, preorder)::debug_stream(); + log->print("%s", _class_name->as_klass_external_name()); if (stream->source() != NULL) { - tty->print(" from %s", stream->source()); + log->print(" source: %s", stream->source()); } - tty->print_cr("]"); + log->cr(); } + #if INCLUDE_CDS if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) { // Only dump the classes that can be stored into CDS archive diff --git a/hotspot/src/share/vm/classfile/classFileStream.cpp b/hotspot/src/share/vm/classfile/classFileStream.cpp index cbe37f195db..618f307bd38 100644 --- a/hotspot/src/share/vm/classfile/classFileStream.cpp +++ b/hotspot/src/share/vm/classfile/classFileStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classFileStream.hpp" #include "classfile/vmSymbols.hpp" +#include "memory/resourceArea.hpp" const bool ClassFileStream::verify = true; const bool ClassFileStream::no_verification = false; diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 12e256e3d10..bdf18bc55e0 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -44,6 +44,7 @@ #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceRefKlass.hpp" @@ -226,11 +227,12 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { return NULL; } -ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() { +ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append) : ClassPathEntry() { _zip = zip; char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass); strcpy(copy, zip_name); _zip_name = copy; + _is_boot_append = is_boot_append; } ClassPathZipEntry::~ClassPathZipEntry() { @@ -274,11 +276,79 @@ u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_ter return buffer; } +#if INCLUDE_CDS +u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TRAPS) { + u1* buffer = NULL; + if (!_is_boot_append) { + assert(DumpSharedSpaces, "Should be called only for non-boot entries during dump time"); + // We presume default is multi-release enabled + const char* multi_ver = Arguments::get_property("jdk.util.jar.enableMultiRelease"); + const char* verstr = Arguments::get_property("jdk.util.jar.version"); + bool is_multi_ver = (multi_ver == NULL || + strcmp(multi_ver, "true") == 0 || + strcmp(multi_ver, "force") == 0) && + is_multiple_versioned(THREAD); + // command line version setting + int version = 0; + const int base_version = 8; // JDK8 + int cur_ver = JDK_Version::current().major_version(); + if (verstr != NULL) { + version = atoi(verstr); + if (version < base_version || version > cur_ver) { + is_multi_ver = false; + // print out warning, do not use assertion here since it will continue to look + // for proper version. + warning("JDK%d is not supported in multiple version jars", version); + } + } + + if (is_multi_ver) { + int n; + char entry_name[JVM_MAXPATHLEN]; + if (version > 0) { + n = jio_snprintf(entry_name, sizeof(entry_name), "META-INF/versions/%d/%s", version, name); + entry_name[n] = '\0'; + buffer = open_entry((const char*)entry_name, filesize, false, CHECK_NULL); + if (buffer == NULL) { + warning("Could not find %s in %s, try to find highest version instead", entry_name, _zip_name); + } + } + if (buffer == NULL) { + for (int i = cur_ver; i >= base_version; i--) { + n = jio_snprintf(entry_name, sizeof(entry_name), "META-INF/versions/%d/%s", i, name); + entry_name[n] = '\0'; + buffer = open_entry((const char*)entry_name, filesize, false, CHECK_NULL); + if (buffer != NULL) { + break; + } + } + } + } + } + return buffer; +} + +bool ClassPathZipEntry::is_multiple_versioned(TRAPS) { + assert(DumpSharedSpaces, "called only at dump time"); + jint size; + char* buffer = (char*)open_entry("META-INF/MANIFEST.MF", &size, false, CHECK_false); + if (buffer != NULL) { + if (strstr(buffer, "Multi-Release: true") != NULL) { + return true; + } + } + return false; +} +#endif // INCLUDE_CDS + ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { jint filesize; - const u1* buffer = open_entry(name, &filesize, false, CHECK_NULL); + u1* buffer = open_versioned_entry(name, &filesize, CHECK_NULL); if (buffer == NULL) { - return NULL; + buffer = open_entry(name, &filesize, false, CHECK_NULL); + if (buffer == NULL) { + return NULL; + } } if (UsePerfData) { ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize); @@ -466,7 +536,7 @@ void ClassLoader::exit_with_path_failure(const char* error, const char* message) void ClassLoader::trace_class_path(const char* msg, const char* name) { if (log_is_enabled(Info, classpath)) { ResourceMark rm; - outputStream* out = LogHandle(classpath)::info_stream(); + outputStream* out = Log(classpath)::info_stream(); if (msg) { out->print("%s", msg); } @@ -558,7 +628,7 @@ void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_searc char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - update_class_path_entry_list(path, false, mark_append_entry, false); + update_class_path_entry_list(path, false, mark_append_entry, false, bootstrap_search); // Check on the state of the boot loader's append path if (mark_append_entry && (_first_append_entry == NULL)) { @@ -582,7 +652,8 @@ void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_searc } ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st, - bool throw_exception, TRAPS) { + bool throw_exception, + bool is_boot_append, TRAPS) { JavaThread* thread = JavaThread::current(); ClassPathEntry* new_entry = NULL; if ((st->st_mode & S_IFREG) == S_IFREG) { @@ -611,7 +682,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str zip = (*ZipOpen)(canonical_path, &error_msg); } if (zip != NULL && error_msg == NULL) { - new_entry = new ClassPathZipEntry(zip, path); + new_entry = new ClassPathZipEntry(zip, path, is_boot_append); } else { ResourceMark rm(thread); char *msg; @@ -644,7 +715,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str // Create a class path zip entry for a given path (return NULL if not found // or zip/JAR file cannot be opened) -ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { +ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path, bool is_boot_append) { // check for a regular file struct stat st; if (os::stat(path, &st) == 0) { @@ -662,7 +733,7 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { } if (zip != NULL && error_msg == NULL) { // create using canonical path - return new ClassPathZipEntry(zip, canonical_path); + return new ClassPathZipEntry(zip, canonical_path, is_boot_append); } } } @@ -720,11 +791,11 @@ void ClassLoader::prepend_to_list(ClassPathEntry *new_entry) { } void ClassLoader::add_to_list(const char *apath) { - update_class_path_entry_list((char*)apath, false, false, false); + update_class_path_entry_list((char*)apath, false, false, false, false); } void ClassLoader::prepend_to_list(const char *apath) { - update_class_path_entry_list((char*)apath, false, false, true); + update_class_path_entry_list((char*)apath, false, false, true, false); } // Returns true IFF the file/dir exists and the entry was successfully created. @@ -732,13 +803,14 @@ bool ClassLoader::update_class_path_entry_list(const char *path, bool check_for_duplicates, bool mark_append_entry, bool prepend_entry, + bool is_boot_append, bool throw_exception) { struct stat st; if (os::stat(path, &st) == 0) { // File or directory found ClassPathEntry* new_entry = NULL; Thread* THREAD = Thread::current(); - new_entry = create_class_path_entry(path, &st, throw_exception, CHECK_(false)); + new_entry = create_class_path_entry(path, &st, throw_exception, is_boot_append, CHECK_(false)); if (new_entry == NULL) { return false; } diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 4d5d2c9231c..8ac282727d5 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -104,16 +104,19 @@ class ClassPathZipEntry: public ClassPathEntry { private: jzfile* _zip; // The zip archive const char* _zip_name; // Name of zip archive + bool _is_boot_append; // entry coming from -Xbootclasspath/a public: bool is_jrt() { return false; } bool is_jar_file() const { return true; } const char* name() const { return _zip_name; } JImageFile* jimage() const { return NULL; } - ClassPathZipEntry(jzfile* zip, const char* zip_name); + ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append); ~ClassPathZipEntry(); u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS); + u1* open_versioned_entry(const char* name, jint* filesize, TRAPS) NOT_CDS_RETURN_(NULL); ClassFileStream* open_stream(const char* name, TRAPS); void contents_do(void f(const char* name, void* context), void* context); + bool is_multiple_versioned(TRAPS) NOT_CDS_RETURN_(false); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) }; @@ -223,7 +226,8 @@ class ClassLoader: AllStatic { static void load_zip_library(); static void load_jimage_library(); static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, - bool throw_exception, TRAPS); + bool throw_exception, + bool is_boot_append, TRAPS); public: @@ -249,6 +253,7 @@ class ClassLoader: AllStatic { bool check_for_duplicates, bool mark_append_entry, bool prepend_entry, + bool is_boot_append, bool throw_exception=true); static void print_bootclasspath(); @@ -394,7 +399,7 @@ class ClassLoader: AllStatic { static void prepend_to_list(ClassPathEntry* new_entry); // creates a class path zip entry (returns NULL if JAR file cannot be opened) - static ClassPathZipEntry* create_class_path_zip_entry(const char *apath); + static ClassPathZipEntry* create_class_path_zip_entry(const char *apath, bool is_boot_append); // add a path to class path list static void add_to_list(const char* apath); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index f3278a7f8de..0fb7a86af4f 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -60,6 +60,7 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -357,7 +358,7 @@ void ClassLoaderData::unload() { if (log_is_enabled(Debug, classloaderdata)) { ResourceMark rm; - outputStream* log = LogHandle(classloaderdata)::debug_stream(); + outputStream* log = Log(classloaderdata)::debug_stream(); log->print(": unload loader data " INTPTR_FORMAT, p2i(this)); log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()), loader_name()); @@ -717,7 +718,7 @@ void ClassLoaderDataGraph::log_creation(Handle loader, ClassLoaderData* cld, TRA } ResourceMark rm; - outputStream* log = LogHandle(classloaderdata)::debug_stream(); + outputStream* log = Log(classloaderdata)::debug_stream(); log->print("create class loader data " INTPTR_FORMAT, p2i(cld)); log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()), cld->loader_name()); @@ -859,7 +860,7 @@ GrowableArray* ClassLoaderDataGraph::new_clds() { array->push(curr); if (log_is_enabled(Debug, classloaderdata)) { - outputStream* log = LogHandle(classloaderdata)::debug_stream(); + outputStream* log = Log(classloaderdata)::debug_stream(); log->print("found new CLD: "); curr->print_value_on(log); log->cr(); diff --git a/hotspot/src/share/vm/classfile/defaultMethods.cpp b/hotspot/src/share/vm/classfile/defaultMethods.cpp index c1173aff04c..65d546e249c 100644 --- a/hotspot/src/share/vm/classfile/defaultMethods.cpp +++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp @@ -437,7 +437,7 @@ class MethodFamily : public ResourceObj { _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError(); if (log_is_enabled(Debug, defaultmethods)) { ResourceMark rm; - outputStream* logstream = LogHandle(defaultmethods)::debug_stream(); + outputStream* logstream = Log(defaultmethods)::debug_stream(); _exception_message->print_value_on(logstream); logstream->cr(); } @@ -663,7 +663,7 @@ static GrowableArray* find_empty_vtable_slots( if (log_is_enabled(Debug, defaultmethods)) { log_debug(defaultmethods)("Slots that need filling:"); ResourceMark rm; - outputStream* logstream = LogHandle(defaultmethods)::debug_stream(); + outputStream* logstream = Log(defaultmethods)::debug_stream(); streamIndentor si(logstream); for (int i = 0; i < slots->length(); ++i) { logstream->indent(); @@ -799,7 +799,7 @@ void DefaultMethods::generate_default_methods( log_debug(defaultmethods)("%s %s requires default method processing", klass->is_interface() ? "Interface" : "Class", klass->name()->as_klass_external_name()); - PrintHierarchy printer(LogHandle(defaultmethods)::debug_stream()); + PrintHierarchy printer(Log(defaultmethods)::debug_stream()); printer.run(klass); } @@ -809,7 +809,7 @@ void DefaultMethods::generate_default_methods( for (int i = 0; i < empty_slots->length(); ++i) { EmptyVtableSlot* slot = empty_slots->at(i); if (log_is_enabled(Debug, defaultmethods)) { - outputStream* logstream = LogHandle(defaultmethods)::debug_stream(); + outputStream* logstream = Log(defaultmethods)::debug_stream(); streamIndentor si(logstream, 2); logstream->indent().print("Looking for default methods for slot "); slot->print_on(logstream); @@ -917,7 +917,7 @@ static void create_defaults_and_exceptions( if (log_is_enabled(Debug, defaultmethods)) { ResourceMark rm; - outputStream* logstream = LogHandle(defaultmethods)::debug_stream(); + outputStream* logstream = Log(defaultmethods)::debug_stream(); logstream->print("for slot: "); slot->print_on(logstream); logstream->cr(); diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 61c3bad0f8e..ee351942cb5 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -29,6 +29,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/systemDictionaryShared.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/orderAccess.inline.hpp" @@ -137,7 +138,7 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_dom } if (log_is_enabled(Trace, protectiondomain)) { ResourceMark rm; - outputStream* log = LogHandle(protectiondomain)::trace_stream(); + outputStream* log = Log(protectiondomain)::trace_stream(); print_count(log); } } diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index a69b87e22d4..b5230c84485 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -515,22 +515,6 @@ char* java_lang_String::as_quoted_ascii(oop java_string) { return result; } -unsigned int java_lang_String::hash_string(oop java_string) { - int length = java_lang_String::length(java_string); - // Zero length string doesn't necessarily hash to zero. - if (length == 0) { - return StringTable::hash_string((jchar*) NULL, 0); - } - - typeArrayOop value = java_lang_String::value(java_string); - bool is_latin1 = java_lang_String::is_latin1(java_string); - if (is_latin1) { - return StringTable::hash_string(value->byte_at_addr(0), length); - } else { - return StringTable::hash_string(value->char_at_addr(0), length); - } -} - Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) { oop obj = java_string(); typeArrayOop value = java_lang_String::value(obj); @@ -1473,6 +1457,12 @@ void java_lang_ThreadGroup::compute_offsets() { compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature()); } + +void java_lang_Throwable::compute_offsets() { + Klass* k = SystemDictionary::Throwable_klass(); + compute_offset(depth_offset, k, vmSymbols::depth_name(), vmSymbols::int_signature()); +} + oop java_lang_Throwable::unassigned_stacktrace() { InstanceKlass* ik = SystemDictionary::Throwable_klass(); address addr = ik->static_field_addr(static_unassigned_stacktrace_offset); @@ -1492,11 +1482,13 @@ void java_lang_Throwable::set_backtrace(oop throwable, oop value) { throwable->release_obj_field_put(backtrace_offset, value); } - -oop java_lang_Throwable::message(oop throwable) { - return throwable->obj_field(detailMessage_offset); +int java_lang_Throwable::depth(oop throwable) { + return throwable->int_field(depth_offset); } +void java_lang_Throwable::set_depth(oop throwable, int value) { + throwable->int_field_put(depth_offset, value); +} oop java_lang_Throwable::message(Handle throwable) { return throwable->obj_field(detailMessage_offset); @@ -1546,10 +1538,12 @@ static inline bool version_matches(Method* method, int version) { return method != NULL && (method->constants()->version() == version); } + // This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. class BacktraceBuilder: public StackObj { + friend class BacktraceIterator; private: Handle _backtrace; objArrayOop _head; @@ -1560,8 +1554,6 @@ class BacktraceBuilder: public StackObj { int _index; NoSafepointVerifier _nsv; - public: - enum { trace_methods_offset = java_lang_Throwable::trace_methods_offset, trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, @@ -1594,6 +1586,8 @@ class BacktraceBuilder: public StackObj { return cprefs; } + public: + // constructor for new backtrace BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) { expand(CHECK); @@ -1679,9 +1673,68 @@ class BacktraceBuilder: public StackObj { }; +struct BacktraceElement : public StackObj { + int _method_id; + int _bci; + int _version; + int _cpref; + Handle _mirror; + BacktraceElement(Handle mirror, int mid, int version, int bci, int cpref) : + _mirror(mirror), _method_id(mid), _version(version), _bci(bci), _cpref(cpref) {} +}; + +class BacktraceIterator : public StackObj { + int _index; + objArrayHandle _result; + objArrayHandle _mirrors; + typeArrayHandle _methods; + typeArrayHandle _bcis; + typeArrayHandle _cprefs; + + void init(objArrayHandle result, Thread* thread) { + // Get method id, bci, version and mirror from chunk + _result = result; + if (_result.not_null()) { + _methods = typeArrayHandle(thread, BacktraceBuilder::get_methods(_result)); + _bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result)); + _mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result)); + _cprefs = typeArrayHandle(thread, BacktraceBuilder::get_cprefs(_result)); + _index = 0; + } + } + public: + BacktraceIterator(objArrayHandle result, Thread* thread) { + init(result, thread); + assert(_methods.is_null() || _methods->length() == java_lang_Throwable::trace_chunk_size, "lengths don't match"); + } + + BacktraceElement next(Thread* thread) { + BacktraceElement e (Handle(thread, _mirrors->obj_at(_index)), + _methods->short_at(_index), + Backtrace::version_at(_bcis->int_at(_index)), + Backtrace::bci_at(_bcis->int_at(_index)), + _cprefs->short_at(_index)); + _index++; + + if (_index >= java_lang_Throwable::trace_chunk_size) { + int next_offset = java_lang_Throwable::trace_next_offset; + // Get next chunk + objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset))); + init(result, thread); + } + return e; + } + + bool repeat() { + return _result.not_null() && _mirrors->obj_at(_index) != NULL; + } +}; + + // Print stack trace element to resource allocated buffer -char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, - int method_id, int version, int bci, int cpref) { +static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id, + int version, int bci, int cpref) { + ResourceMark rm; // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); @@ -1752,13 +1805,6 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, } } - return buf; -} - -void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, - int method_id, int version, int bci, int cpref) { - ResourceMark rm; - char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref); st->print_cr("%s", buf); } @@ -1767,11 +1813,7 @@ void java_lang_Throwable::print_stack_element(outputStream *st, const methodHand int method_id = method->orig_method_idnum(); int version = method->constants()->version(); int cpref = method->name_index(); - print_stack_element(st, mirror, method_id, version, bci, cpref); -} - -const char* java_lang_Throwable::no_stack_trace_message() { - return "\t<>"; + print_stack_element_to_stream(st, mirror, method_id, version, bci, cpref); } /** @@ -1788,32 +1830,17 @@ void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st) while (throwable.not_null()) { objArrayHandle result (THREAD, objArrayOop(backtrace(throwable()))); if (result.is_null()) { - st->print_raw_cr(no_stack_trace_message()); + st->print_raw_cr("\t<>"); return; } + BacktraceIterator iter(result, THREAD); - while (result.not_null()) { - // Get method id, bci, version and mirror from chunk - typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); - typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); - objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); - typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result)); - - int length = methods()->length(); - for (int index = 0; index < length; index++) { - Handle mirror(THREAD, mirrors->obj_at(index)); - // NULL mirror means end of stack trace - if (mirror.is_null()) goto handle_cause; - int method = methods->short_at(index); - int version = Backtrace::version_at(bcis->int_at(index)); - int bci = Backtrace::bci_at(bcis->int_at(index)); - int cpref = cprefs->short_at(index); - print_stack_element(st, mirror, method, version, bci, cpref); - } - result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); + while (iter.repeat()) { + BacktraceElement bte = iter.next(THREAD); + print_stack_element_to_stream(st, bte._mirror, bte._method_id, bte._version, bte._bci, bte._cpref); } - handle_cause: { + // Call getCause() which doesn't necessarily return the _cause field. EXCEPTION_MARK; JavaValue cause(T_OBJECT); JavaCalls::call_virtual(&cause, @@ -1865,6 +1892,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand int max_depth = MaxJavaStackTraceDepth; JavaThread* thread = (JavaThread*)THREAD; + BacktraceBuilder bt(CHECK); // If there is no Java frame just return the method that was being called @@ -1872,6 +1900,8 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand if (!thread->has_last_Java_frame()) { if (max_depth >= 1 && method() != NULL) { bt.push(method(), 0, CHECK); + log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1); + set_depth(throwable(), 1); set_backtrace(throwable(), bt.backtrace()); } return; @@ -1979,8 +2009,11 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand total_count++; } + log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), total_count); + // Put completed stack trace into throwable object set_backtrace(throwable(), bt.backtrace()); + set_depth(throwable(), total_count); } void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method) { @@ -2034,94 +2067,60 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t // methods as preallocated errors aren't created by "java" code. // fill in as much stack trace as possible - typeArrayOop methods = BacktraceBuilder::get_methods(backtrace); - int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth); int chunk_count = 0; - for (;!st.at_end(); st.next()) { bt.push(st.method(), st.bci(), CHECK); chunk_count++; // Bail-out for deep stacks - if (chunk_count >= max_chunks) break; + if (chunk_count >= trace_chunk_size) break; } + set_depth(throwable(), chunk_count); + log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), chunk_count); // We support the Throwable immutability protocol defined for Java 7. java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace()); assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized"); } +void java_lang_Throwable::get_stack_trace_elements(Handle throwable, + objArrayHandle stack_trace_array_h, TRAPS) { -int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) { - if (throwable == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + if (throwable.is_null() || stack_trace_array_h.is_null()) { + THROW(vmSymbols::java_lang_NullPointerException()); } - objArrayOop chunk = objArrayOop(backtrace(throwable)); - int depth = 0; - if (chunk != NULL) { - // Iterate over chunks and count full ones - while (true) { - objArrayOop next = objArrayOop(chunk->obj_at(trace_next_offset)); - if (next == NULL) break; - depth += trace_chunk_size; - chunk = next; - } - assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check"); - // Count element in remaining partial chunk. NULL value for mirror - // marks the end of the stack trace elements that are saved. - objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); - assert(mirrors != NULL, "sanity check"); - for (int i = 0; i < mirrors->length(); i++) { - if (mirrors->obj_at(i) == NULL) break; - depth++; - } + + assert(stack_trace_array_h->is_objArray(), "Stack trace array should be an array of StackTraceElenent"); + + if (stack_trace_array_h->length() != depth(throwable())) { + THROW(vmSymbols::java_lang_IndexOutOfBoundsException()); + } + + objArrayHandle result(THREAD, objArrayOop(backtrace(throwable()))); + BacktraceIterator iter(result, THREAD); + + int index = 0; + while (iter.repeat()) { + BacktraceElement bte = iter.next(THREAD); + + Handle stack_trace_element(THREAD, stack_trace_array_h->obj_at(index++)); + + if (stack_trace_element.is_null()) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror())); + methodHandle method (THREAD, holder->method_with_orig_idnum(bte._method_id, bte._version)); + + java_lang_StackTraceElement::fill_in(stack_trace_element, holder, + method, + bte._version, + bte._bci, + bte._cpref, CHECK); } - return depth; } - -oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS) { - if (throwable == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); - } - if (index < 0) { - THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); - } - // Compute how many chunks to skip and index into actual chunk - objArrayOop chunk = objArrayOop(backtrace(throwable)); - int skip_chunks = index / trace_chunk_size; - int chunk_index = index % trace_chunk_size; - while (chunk != NULL && skip_chunks > 0) { - chunk = objArrayOop(chunk->obj_at(trace_next_offset)); - skip_chunks--; - } - if (chunk == NULL) { - THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); - } - // Get method id, bci, version, mirror and cpref from chunk - typeArrayOop methods = BacktraceBuilder::get_methods(chunk); - typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); - objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); - typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk); - - assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); - - int method = methods->short_at(chunk_index); - int version = Backtrace::version_at(bcis->int_at(chunk_index)); - int bci = Backtrace::bci_at(bcis->int_at(chunk_index)); - int cpref = cprefs->short_at(chunk_index); - Handle mirror(THREAD, mirrors->obj_at(chunk_index)); - - // Chunk can be partial full - if (mirror.is_null()) { - THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); - } - oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0); - return element; -} - -oop java_lang_StackTraceElement::create(Handle mirror, int method_id, - int version, int bci, int cpref, TRAPS) { +oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -2132,37 +2131,45 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, Handle element = ik->allocate_instance_handle(CHECK_0); + int cpref = method->name_index(); + int version = method->constants()->version(); + fill_in(element, method->method_holder(), method, version, bci, cpref, CHECK_0); + return element(); +} + +void java_lang_StackTraceElement::fill_in(Handle element, + InstanceKlass* holder, const methodHandle& method, + int version, int bci, int cpref, TRAPS) { + assert(element->is_a(SystemDictionary::StackTraceElement_klass()), "sanity check"); + // Fill in class name ResourceMark rm(THREAD); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* str = holder->external_name(); - oop classname = StringTable::intern((char*) str, CHECK_0); + oop classname = StringTable::intern((char*) str, CHECK); java_lang_StackTraceElement::set_declaringClass(element(), classname); - Method* method = holder->method_with_orig_idnum(method_id, version); - // The method can be NULL if the requested class version is gone - Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); + Symbol* sym = !method.is_null() ? method->name() : holder->constants()->symbol_at(cpref); // Fill in method name - oop methodname = StringTable::intern(sym, CHECK_0); + oop methodname = StringTable::intern(sym, CHECK); java_lang_StackTraceElement::set_methodName(element(), methodname); // Fill in module name and version ModuleEntry* module = holder->module(); if (module->is_named()) { - oop module_name = StringTable::intern(module->name(), CHECK_0); + oop module_name = StringTable::intern(module->name(), CHECK); java_lang_StackTraceElement::set_moduleName(element(), module_name); oop module_version; if (module->version() != NULL) { - module_version = StringTable::intern(module->version(), CHECK_0); + module_version = StringTable::intern(module->version(), CHECK); } else { module_version = NULL; } java_lang_StackTraceElement::set_moduleVersion(element(), module_version); } - if (!version_matches(method, version)) { + if (!version_matches(method(), version)) { // The method was redefined, accurate line number information isn't available java_lang_StackTraceElement::set_fileName(element(), NULL); java_lang_StackTraceElement::set_lineNumber(element(), -1); @@ -2171,20 +2178,12 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, Symbol* source = Backtrace::get_source_file_name(holder, version); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); - oop filename = StringTable::intern(source, CHECK_0); + oop filename = StringTable::intern(source, CHECK); java_lang_StackTraceElement::set_fileName(element(), filename); int line_number = Backtrace::get_line_number(method, bci); java_lang_StackTraceElement::set_lineNumber(element(), line_number); } - return element(); -} - -oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) { - Handle mirror (THREAD, method->method_holder()->java_mirror()); - int method_id = method->orig_method_idnum(); - int cpref = method->name_index(); - return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { @@ -2751,7 +2750,7 @@ void java_lang_reflect_Field::set_type_annotations(oop field, oop value) { field->obj_field_put(type_annotations_offset, value); } -void sun_reflect_ConstantPool::compute_offsets() { +void reflect_ConstantPool::compute_offsets() { Klass* k = SystemDictionary::reflect_ConstantPool_klass(); // This null test can be removed post beta if (k != NULL) { @@ -2895,7 +2894,7 @@ void java_lang_reflect_Module::set_module_entry(oop module, ModuleEntry* module_ module->address_field_put(_module_entry_offset, (address)module_entry); } -Handle sun_reflect_ConstantPool::create(TRAPS) { +Handle reflect_ConstantPool::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); Klass* k = SystemDictionary::reflect_ConstantPool_klass(); instanceKlassHandle klass (THREAD, k); @@ -2905,14 +2904,14 @@ Handle sun_reflect_ConstantPool::create(TRAPS) { } -void sun_reflect_ConstantPool::set_cp(oop reflect, ConstantPool* value) { +void reflect_ConstantPool::set_cp(oop reflect, ConstantPool* value) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); oop mirror = value->pool_holder()->java_mirror(); // Save the mirror to get back the constant pool. reflect->obj_field_put(_oop_offset, mirror); } -ConstantPool* sun_reflect_ConstantPool::get_cp(oop reflect) { +ConstantPool* reflect_ConstantPool::get_cp(oop reflect) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); oop mirror = reflect->obj_field(_oop_offset); @@ -2927,7 +2926,7 @@ ConstantPool* sun_reflect_ConstantPool::get_cp(oop reflect) { return InstanceKlass::cast(k)->constants(); } -void sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() { +void reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() { Klass* k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass(); // This null test can be removed post beta if (k != NULL) { @@ -3629,8 +3628,8 @@ GrowableArray* java_lang_Class::_fixup_mirror_list = NULL; GrowableArray* java_lang_Class::_fixup_module_field_list = NULL; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; -int java_lang_Throwable::cause_offset; int java_lang_Throwable::stackTrace_offset; +int java_lang_Throwable::depth_offset; int java_lang_Throwable::static_unassigned_stacktrace_offset; int java_lang_reflect_AccessibleObject::override_offset; int java_lang_reflect_Method::clazz_offset; @@ -3707,8 +3706,8 @@ int java_lang_AssertionStatusDirectives::packageEnabled_offset; int java_lang_AssertionStatusDirectives::deflt_offset; int java_nio_Buffer::_limit_offset; int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset = 0; -int sun_reflect_ConstantPool::_oop_offset; -int sun_reflect_UnsafeStaticFieldAccessorImpl::_base_offset; +int reflect_ConstantPool::_oop_offset; +int reflect_UnsafeStaticFieldAccessorImpl::_base_offset; // Support for java_lang_StackTraceElement @@ -3841,7 +3840,6 @@ void JavaClasses::compute_hard_coded_offsets() { // Throwable Class java_lang_Throwable::backtrace_offset = java_lang_Throwable::hc_backtrace_offset * x + header; java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header; - java_lang_Throwable::cause_offset = java_lang_Throwable::hc_cause_offset * x + header; java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header; java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x; @@ -3894,6 +3892,7 @@ void JavaClasses::compute_hard_coded_offsets() { void JavaClasses::compute_offsets() { // java_lang_Class::compute_offsets was called earlier in bootstrap java_lang_ClassLoader::compute_offsets(); + java_lang_Throwable::compute_offsets(); java_lang_Thread::compute_offsets(); java_lang_ThreadGroup::compute_offsets(); java_lang_invoke_MethodHandle::compute_offsets(); @@ -3913,8 +3912,8 @@ void JavaClasses::compute_offsets() { java_lang_reflect_Constructor::compute_offsets(); java_lang_reflect_Field::compute_offsets(); java_nio_Buffer::compute_offsets(); - sun_reflect_ConstantPool::compute_offsets(); - sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); + reflect_ConstantPool::compute_offsets(); + reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); java_lang_reflect_Module::compute_offsets(); java_lang_StackFrameInfo::compute_offsets(); @@ -4048,8 +4047,8 @@ void JavaClasses::check_offsets() { CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, backtrace, "Ljava/lang/Object;"); CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, detailMessage, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, cause, "Ljava/lang/Throwable;"); CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, stackTrace, "[Ljava/lang/StackTraceElement;"); + CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, depth, "I"); // Boxed primitive objects (java_lang_boxing_object) diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 6c487534018..7245a9f0bb1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -155,11 +155,6 @@ class java_lang_String : AllStatic { } static unsigned int hash_code(oop java_string); - static unsigned int latin1_hash_code(typeArrayOop value, int len); - - // This is the string hash code used by the StringTable, which may be - // the same as String.hashCode or an alternate hash code. - static unsigned int hash_string(oop java_string); static bool equals(oop java_string, jchar* chars, int len); static bool equals(oop str1, oop str2); @@ -456,6 +451,7 @@ class java_lang_ThreadGroup : AllStatic { class java_lang_Throwable: AllStatic { friend class BacktraceBuilder; + friend class BacktraceIterator; private: // Offsets @@ -481,16 +477,12 @@ class java_lang_Throwable: AllStatic { static int backtrace_offset; static int detailMessage_offset; - static int cause_offset; static int stackTrace_offset; + static int depth_offset; static int static_unassigned_stacktrace_offset; - // Printing - static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci, int cpref); // StackTrace (programmatic access, new since 1.4) static void clear_stacktrace(oop throwable); - // No stack trace available - static const char* no_stack_trace_message(); // Stacktrace (post JDK 1.7.0 to allow immutability protocol to be followed) static void set_stacktrace(oop throwable, oop st_element_array); static oop unassigned_stacktrace(); @@ -499,19 +491,20 @@ class java_lang_Throwable: AllStatic { // Backtrace static oop backtrace(oop throwable); static void set_backtrace(oop throwable, oop value); + static int depth(oop throwable); + static void set_depth(oop throwable, int value); // Needed by JVMTI to filter out this internal field. static int get_backtrace_offset() { return backtrace_offset;} static int get_detailMessage_offset() { return detailMessage_offset;} // Message - static oop message(oop throwable); static oop message(Handle throwable); static void set_message(oop throwable, oop value); static Symbol* detail_message(oop throwable); - static void print_stack_element(outputStream *st, Handle mirror, int method, - int version, int bci, int cpref); static void print_stack_element(outputStream *st, const methodHandle& method, int bci); static void print_stack_usage(Handle stream); + static void compute_offsets(); + // Allocate space for backtrace (created but stack trace not filled in) static void allocate_backtrace(Handle throwable, TRAPS); // Fill in current stack trace for throwable with preallocated backtrace (no GC) @@ -520,8 +513,7 @@ class java_lang_Throwable: AllStatic { static void fill_in_stack_trace(Handle throwable, const methodHandle& method, TRAPS); static void fill_in_stack_trace(Handle throwable, const methodHandle& method = methodHandle()); // Programmatic access to stack trace - static oop get_stack_trace_element(oop throwable, int index, TRAPS); - static int get_stack_trace_depth(oop throwable, TRAPS); + static void get_stack_trace_elements(Handle throwable, objArrayHandle stack_trace, TRAPS); // Printing static void print(Handle throwable, outputStream* st); static void print_stack_trace(Handle throwable, outputStream* st); @@ -807,8 +799,8 @@ class java_lang_reflect_Module { friend class JavaClasses; }; -// Interface to sun.reflect.ConstantPool objects -class sun_reflect_ConstantPool { +// Interface to jdk.internal.reflect.ConstantPool objects +class reflect_ConstantPool { private: // Note that to reduce dependencies on the JDK we compute these // offsets at run-time. @@ -832,8 +824,8 @@ class sun_reflect_ConstantPool { friend class JavaClasses; }; -// Interface to sun.reflect.UnsafeStaticFieldAccessorImpl objects -class sun_reflect_UnsafeStaticFieldAccessorImpl { +// Interface to jdk.internal.reflect.UnsafeStaticFieldAccessorImpl objects +class reflect_UnsafeStaticFieldAccessorImpl { private: static int _base_offset; static void compute_offsets(); @@ -1333,7 +1325,6 @@ class java_lang_StackTraceElement: AllStatic { static int fileName_offset; static int lineNumber_offset; - public: // Setters static void set_moduleName(oop element, oop value); static void set_moduleVersion(oop element, oop value); @@ -1342,10 +1333,13 @@ class java_lang_StackTraceElement: AllStatic { static void set_fileName(oop element, oop value); static void set_lineNumber(oop element, int value); + public: // Create an instance of StackTraceElement - static oop create(Handle mirror, int method, int version, int bci, int cpref, TRAPS); static oop create(const methodHandle& method, int bci, TRAPS); + static void fill_in(Handle element, InstanceKlass* holder, const methodHandle& method, + int version, int bci, int cpref, TRAPS); + // Debugging friend class JavaClasses; }; diff --git a/hotspot/src/share/vm/classfile/loaderConstraints.cpp b/hotspot/src/share/vm/classfile/loaderConstraints.cpp index 5780bad832e..3e5b033acb4 100644 --- a/hotspot/src/share/vm/classfile/loaderConstraints.cpp +++ b/hotspot/src/share/vm/classfile/loaderConstraints.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,13 +111,14 @@ void LoaderConstraintTable::purge_loader_constraints() { if (klass != NULL && klass->class_loader_data()->is_unloading()) { probe->set_klass(NULL); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, constraints)) { ResourceMark rm; - tty->print_cr("[Purging class object from constraint for name %s," + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("purging class object from constraint for name %s," " loader list:", probe->name()->as_C_string()); for (int i = 0; i < probe->num_loaders(); i++) { - tty->print_cr("[ [%d]: %s", i, + out->print_cr(" [%d]: %s", i, probe->loader_data(i)->loader_name()); } } @@ -126,9 +127,10 @@ void LoaderConstraintTable::purge_loader_constraints() { int n = 0; while (n < probe->num_loaders()) { if (probe->loader_data(n)->is_unloading()) { - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print_cr("[Purging loader %s from constraint for name %s", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("purging loader %s from constraint for name %s", probe->loader_data(n)->loader_name(), probe->name()->as_C_string() ); @@ -140,11 +142,12 @@ void LoaderConstraintTable::purge_loader_constraints() { probe->set_loader_data(n, probe->loader_data(num)); probe->set_loader_data(num, NULL); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print_cr("[New loader list:"); + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("new loader list:"); for (int i = 0; i < probe->num_loaders(); i++) { - tty->print_cr("[ [%d]: %s", i, + out->print_cr(" [%d]: %s", i, probe->loader_data(i)->loader_name()); } } @@ -156,9 +159,10 @@ void LoaderConstraintTable::purge_loader_constraints() { } // Check whether entry should be purged if (probe->num_loaders() < 2) { - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Purging complete constraint for name %s\n", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("purging complete constraint for name %s", probe->name()->as_C_string()); } @@ -227,10 +231,11 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, p->set_klass(klass); p->set_next(bucket(index)); set_entry(index, p); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Adding new constraint for name: %s, loader[0]: %s," - " loader[1]: %s ]\n", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("adding new constraint for name: %s, loader[0]: %s," + " loader[1]: %s", class_name->as_C_string(), SystemDictionary::loader_name(class_loader1()), SystemDictionary::loader_name(class_loader2()) @@ -240,10 +245,11 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, /* constraint already imposed */ if ((*pp1)->klass() == NULL) { (*pp1)->set_klass(klass); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Setting class object in existing constraint for" - " name: %s and loader %s ]\n", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("setting class object in existing constraint for" + " name: %s and loader %s", class_name->as_C_string(), SystemDictionary::loader_name(class_loader1()) ); @@ -261,8 +267,9 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, } } - if (failure_code != 0 && TraceLoaderConstraints) { + if (failure_code != 0 && log_is_enabled(Info, classload, constraints)) { ResourceMark rm; + outputStream* out = Log(classload, constraints)::info_stream(); const char* reason = ""; switch(failure_code) { case 1: reason = "the class objects presented by loader[0] and loader[1]" @@ -273,8 +280,8 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, " the stored class object in the constraint"; break; default: reason = "unknown reason code"; } - tty->print("[Failed to add constraint for name: %s, loader[0]: %s," - " loader[1]: %s, Reason: %s ]\n", + out->print_cr("failed to add constraint for name: %s, loader[0]: %s," + " loader[1]: %s, Reason: %s", class_name->as_C_string(), SystemDictionary::loader_name(class_loader1()), SystemDictionary::loader_name(class_loader2()), @@ -293,10 +300,11 @@ bool LoaderConstraintTable::check_or_update(instanceKlassHandle k, Symbol* name) { LoaderConstraintEntry* p = *(find_loader_constraint(name, loader)); if (p && p->klass() != NULL && p->klass() != k()) { - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Constraint check failed for name %s, loader %s: " - "the presented class object differs from that stored ]\n", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("constraint check failed for name %s, loader %s: " + "the presented class object differs from that stored", name->as_C_string(), SystemDictionary::loader_name(loader())); } @@ -304,10 +312,11 @@ bool LoaderConstraintTable::check_or_update(instanceKlassHandle k, } else { if (p && p->klass() == NULL) { p->set_klass(k()); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Updating constraint for name %s, loader %s, " - "by setting class object ]\n", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("updating constraint for name %s, loader %s, " + "by setting class object", name->as_C_string(), SystemDictionary::loader_name(loader())); } @@ -353,13 +362,14 @@ void LoaderConstraintTable::extend_loader_constraint(LoaderConstraintEntry* p, int num = p->num_loaders(); p->set_loader(num, loader()); p->set_num_loaders(num + 1); - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print("[Extending constraint for name %s by adding loader[%d]: %s %s", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("extending constraint for name %s by adding loader[%d]: %s %s", p->name()->as_C_string(), num, SystemDictionary::loader_name(loader()), - (p->klass() == NULL ? " and setting class object ]\n" : " ]\n") + (p->klass() == NULL ? " and setting class object" : "") ); } if (p->klass() == NULL) { @@ -392,18 +402,19 @@ void LoaderConstraintTable::merge_loader_constraints( p1->set_num_loaders(num + 1); } - if (TraceLoaderConstraints) { + if (log_is_enabled(Info, classload, constraints)) { ResourceMark rm; - tty->print_cr("[Merged constraints for name %s, new loader list:", + outputStream* out = Log(classload, constraints)::info_stream(); + out->print_cr("merged constraints for name %s, new loader list:", p1->name()->as_C_string() ); for (int i = 0; i < p1->num_loaders(); i++) { - tty->print_cr("[ [%d]: %s", i, + out->print_cr(" [%d]: %s", i, p1->loader_data(i)->loader_name()); } if (p1->klass() == NULL) { - tty->print_cr("[... and setting class object]"); + out->print_cr("... and setting class object"); } } @@ -473,7 +484,6 @@ void LoaderConstraintTable::verify(Dictionary* dictionary, // Called with the system dictionary lock held void LoaderConstraintTable::print() { ResourceMark rm; - assert_locked_or_safepoint(SystemDictionary_lock); tty->print_cr("Java loader constraints (entries=%d)", _loader_constraint_size); for (int cindex = 0; cindex < _loader_constraint_size; cindex++) { diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index a4a23d44e49..6d47db68c7d 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -36,6 +36,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/vmSymbols.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" @@ -480,7 +481,7 @@ void Modules::define_module(jobject module, jstring version, } if (log_is_enabled(Debug, modules)) { - outputStream* logst = LogHandle(modules)::debug_stream(); + outputStream* logst = Log(modules)::debug_stream(); logst->print("define_module(): creation of module: %s, version: %s, location: %s, ", module_name, module_version != NULL ? module_version : "NULL", module_location != NULL ? module_location : "NULL"); @@ -789,7 +790,7 @@ jobject Modules::get_module(jclass clazz, TRAPS) { if (log_is_enabled(Debug, modules)) { ResourceMark rm(THREAD); - outputStream* logst = LogHandle(modules)::debug_stream(); + outputStream* logst = Log(modules)::debug_stream(); Klass* klass = java_lang_Class::as_Klass(mirror); oop module_name = java_lang_reflect_Module::name(module); if (module_name != NULL) { diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp index 939e136de3c..302bb45284f 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -29,6 +29,7 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/resourceArea.hpp" #include "runtime/arguments.hpp" #include "utilities/ostream.hpp" @@ -74,7 +75,7 @@ bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { void SharedPathsMiscInfo::print_path(int type, const char* path) { ResourceMark rm; - outputStream* out = LogHandle(classpath)::info_stream(); + outputStream* out = Log(classpath)::info_stream(); switch (type) { case BOOT: out->print("Expecting BOOT path=%s", path); diff --git a/hotspot/src/share/vm/classfile/stringTable.cpp b/hotspot/src/share/vm/classfile/stringTable.cpp index 167ec28449c..11aa5548cf5 100644 --- a/hotspot/src/share/vm/classfile/stringTable.cpp +++ b/hotspot/src/share/vm/classfile/stringTable.cpp @@ -32,6 +32,7 @@ #include "gc/shared/gcLocker.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -94,15 +95,27 @@ volatile int StringTable::_parallel_claimed_idx = 0; CompactHashtable StringTable::_shared_table; // Pick hashing algorithm -template -unsigned int StringTable::hash_string(const T* s, int len) { +unsigned int StringTable::hash_string(const jchar* s, int len) { return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : java_lang_String::hash_code(s, len); } -// Explicit instantiation for all supported types. -template unsigned int StringTable::hash_string(const jchar* s, int len); -template unsigned int StringTable::hash_string(const jbyte* s, int len); +unsigned int StringTable::hash_string(oop string) { + EXCEPTION_MARK; + if (string == NULL) { + return hash_string((jchar*)NULL, 0); + } + ResourceMark rm(THREAD); + // All String oops are hashed as unicode + int length; + jchar* chars = java_lang_String::as_unicode_string(string, length, THREAD); + if (chars != NULL) { + return hash_string(chars, length); + } else { + vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "unable to create Unicode string for verification"); + return 0; + } +} oop StringTable::lookup_shared(jchar* name, int len) { // java_lang_String::hash_code() was used to compute hash values in the shared table. Don't @@ -398,7 +411,7 @@ void StringTable::verify() { for ( ; p != NULL; p = p->next()) { oop s = p->literal(); guarantee(s != NULL, "interned string is NULL"); - unsigned int h = java_lang_String::hash_string(s); + unsigned int h = hash_string(s); guarantee(p->hash() == h, "broken hash in string table entry"); guarantee(the_table()->hash_to_index(h) == i, "wrong index in string table"); @@ -498,7 +511,7 @@ StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt, return _verify_fail_done; } - unsigned int h = java_lang_String::hash_string(str); + unsigned int h = hash_string(str); if (e_ptr->hash() != h) { if (mesg_mode == _verify_with_mesgs) { tty->print_cr("ERROR: broken hash value in entry @ bucket[%d][%d], " diff --git a/hotspot/src/share/vm/classfile/stringTable.hpp b/hotspot/src/share/vm/classfile/stringTable.hpp index f7dc5967dfc..0840ba28180 100644 --- a/hotspot/src/share/vm/classfile/stringTable.hpp +++ b/hotspot/src/share/vm/classfile/stringTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,8 @@ public: // Hashing algorithm, used as the hash value used by the // StringTable for bucket selection and comparison (stored in the // HashtableEntry structures). This is used in the String.intern() method. - template static unsigned int hash_string(const T* s, int len); + static unsigned int hash_string(const jchar* s, int len); + static unsigned int hash_string(oop string); // Internal test. static void test_alt_hash() PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 7574e85c8f2..56d1dfb8f8a 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -32,6 +32,7 @@ #include "gc/shared/gcLocker.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -160,6 +161,11 @@ void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { // Create a new table and using alternate hash code, populate the new table // with the existing strings. Set flag to use the alternate hash code afterwards. void SymbolTable::rehash_table() { + if (DumpSharedSpaces) { + tty->print_cr("Warning: rehash_table should not be called while dumping archive"); + return; + } + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); // This should never happen with -Xshare:dump but it might in testing mode. if (DumpSharedSpaces) return; @@ -201,6 +207,11 @@ Symbol* SymbolTable::lookup_dynamic(int index, const char* name, Symbol* SymbolTable::lookup_shared(const char* name, int len, unsigned int hash) { + if (use_alternate_hashcode()) { + // hash_code parameter may use alternate hashing algorithm but the shared table + // always uses the same original hash code. + hash = hash_shared_symbol(name, len); + } return _shared_table.lookup(name, hash, len); } @@ -234,6 +245,10 @@ unsigned int SymbolTable::hash_symbol(const char* s, int len) { java_lang_String::hash_code((const jbyte*)s, len); } +unsigned int SymbolTable::hash_shared_symbol(const char* s, int len) { + return java_lang_String::hash_code((const jbyte*)s, len); +} + // We take care not to be blocking while holding the // SymbolTable_lock. Otherwise, the system might deadlock, since the @@ -536,7 +551,7 @@ bool SymbolTable::copy_compact_table(char** top, char*end) { HashtableEntry* p = the_table()->bucket(i); for ( ; p != NULL; p = p->next()) { Symbol* s = (Symbol*)(p->literal()); - unsigned int fixed_hash = hash_symbol((char*)s->bytes(), s->utf8_length()); + unsigned int fixed_hash = hash_shared_symbol((char*)s->bytes(), s->utf8_length()); assert(fixed_hash == p->hash(), "must not rehash during dumping"); ch_table.add(fixed_hash, s); } diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index 364a07a8c75..f29698ad575 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -175,6 +175,7 @@ public: } static unsigned int hash_symbol(const char* s, int len); + static unsigned int hash_shared_symbol(const char* s, int len); static Symbol* lookup(const char* name, int len, TRAPS); // lookup only, won't add. Also calculate hash. diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 2851bccb3be..34c43946e52 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -45,6 +45,7 @@ #include "interpreter/interpreter.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/klass.inline.hpp" @@ -67,6 +68,7 @@ #include "runtime/signature.hpp" #include "services/classLoadingService.hpp" #include "services/threadService.hpp" +#include "trace/traceMacros.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" #if INCLUDE_CDS @@ -435,7 +437,7 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, if (log_is_enabled(Debug, protectiondomain)) { ResourceMark rm; // Print out trace information - outputStream* log = LogHandle(protectiondomain)::debug_stream(); + outputStream* log = Log(protectiondomain)::debug_stream(); log->print_cr("Checking package access"); log->print("class loader: "); class_loader()->print_value_on(log); log->print(" protection domain: "); protection_domain()->print_value_on(log); @@ -1650,6 +1652,8 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { } + TRACE_KLASS_DEFINITION(k, THREAD); + } // Support parallel classloading @@ -2063,7 +2067,18 @@ bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) { int sid = (info >> CEIL_LG_OPTION_LIMIT); Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); InstanceKlass** klassp = &_well_known_klasses[id]; - bool must_load = (init_opt < SystemDictionary::Opt); + + bool must_load; +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // If JVMCI is enabled we require its classes to be found. + must_load = (init_opt < SystemDictionary::Opt) || (init_opt == SystemDictionary::Jvmci); + } else +#endif + { + must_load = (init_opt < SystemDictionary::Opt); + } + if ((*klassp) == NULL) { Klass* k; if (must_load) { diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index aaee2858dc5..ca637011c4d 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -142,13 +142,13 @@ class SymbolPropertyTable; \ /* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ - do_klass(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt ) \ - do_klass(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Pre ) \ - do_klass(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Pre ) \ - do_klass(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt ) \ - do_klass(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt ) \ - do_klass(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt ) \ - do_klass(reflect_CallerSensitive_klass, sun_reflect_CallerSensitive, Opt ) \ + do_klass(reflect_MagicAccessorImpl_klass, reflect_MagicAccessorImpl, Opt ) \ + do_klass(reflect_MethodAccessorImpl_klass, reflect_MethodAccessorImpl, Pre ) \ + do_klass(reflect_ConstructorAccessorImpl_klass, reflect_ConstructorAccessorImpl, Pre ) \ + do_klass(reflect_DelegatingClassLoader_klass, reflect_DelegatingClassLoader, Opt ) \ + do_klass(reflect_ConstantPool_klass, reflect_ConstantPool, Opt ) \ + do_klass(reflect_UnsafeStaticFieldAccessorImpl_klass, reflect_UnsafeStaticFieldAccessorImpl, Opt ) \ + do_klass(reflect_CallerSensitive_klass, reflect_CallerSensitive, Opt ) \ \ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ do_klass(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle, Opt ) \ @@ -241,7 +241,7 @@ class SystemDictionary : AllStatic { Opt, // preload tried; NULL if not present #if INCLUDE_JVMCI - Jvmci, // preload tried; error if not present, use only with JVMCI + Jvmci, // preload tried; error if not present if JVMCI enabled #endif OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 2 // OPTION_LIMIT <= (1<class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { Verifier::trace_class_resolution(obj, klass()); } @@ -80,7 +80,7 @@ bool VerificationType::is_reference_assignable_from( Klass* from_class = SystemDictionary::resolve_or_fail( from.name(), Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { Verifier::trace_class_resolution(from_class, klass()); } return InstanceKlass::cast(from_class)->is_subclass_of(this_class()); diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index b5a827b7c10..600ca8e911f 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -33,6 +33,7 @@ #include "classfile/vmSymbols.hpp" #include "interpreter/bytecodes.hpp" #include "interpreter/bytecodeStream.hpp" +#include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" @@ -106,9 +107,9 @@ void Verifier::trace_class_resolution(Klass* resolve_class, InstanceKlass* verif const char* resolve = resolve_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - log_info(classresolve)("%s %s %s (verification)", verify, resolve, source_file); + log_debug(classresolve)("%s %s %s (verification)", verify, resolve, source_file); } else { - log_info(classresolve)("%s %s (verification)", verify, resolve); + log_debug(classresolve)("%s %s (verification)", verify, resolve); } } @@ -176,9 +177,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul if (can_failover && !HAS_PENDING_EXCEPTION && (exception_name == vmSymbols::java_lang_VerifyError() || exception_name == vmSymbols::java_lang_ClassFormatError())) { - if (VerboseVerification) { - tty->print_cr("Fail over class verification to old verifier for: %s", klassName); - } + log_info(verification)("Fail over class verification to old verifier for: %s", klassName); log_info(classinit)("Fail over class verification to old verifier for: %s", klassName); exception_name = inference_verify( klass, message_buffer, message_buffer_len, THREAD); @@ -192,10 +191,10 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul } if (log_is_enabled(Info, classinit)){ - log_end_verification(LogHandle(classinit)::info_stream(), klassName, exception_name, THREAD); + log_end_verification(Log(classinit)::info_stream(), klassName, exception_name, THREAD); } - if (VerboseVerification){ - log_end_verification(tty, klassName, exception_name, THREAD); + if (log_is_enabled(Info, verification)){ + log_end_verification(Log(verification)::info_stream(), klassName, exception_name, THREAD); } if (HAS_PENDING_EXCEPTION) { @@ -206,7 +205,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul ResourceMark rm(THREAD); instanceKlassHandle kls = SystemDictionary::resolve_or_fail(exception_name, true, CHECK_false); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { Verifier::trace_class_resolution(kls(), klass()); } @@ -249,7 +248,7 @@ bool Verifier::is_eligible_for_verification(instanceKlassHandle klass, bool shou // As of the fix for 4486457 we disable verification for all of the // dynamically-generated bytecodes associated with the 1.4 // reflection implementation, not just those associated with - // sun/reflect/SerializationConstructorAccessor. + // jdk/internal/reflect/SerializationConstructorAccessor. // NOTE: this is called too early in the bootstrapping process to be // guarded by Universe::is_gte_jdk14x_version(). // Also for lambda generated code, gte jdk8 @@ -269,9 +268,7 @@ Symbol* Verifier::inference_verify( } ResourceMark rm(THREAD); - if (VerboseVerification) { - tty->print_cr("Verifying class %s with old format", klass->external_name()); - } + log_info(verification)("Verifying class %s with old format", klass->external_name()); jclass cls = (jclass) JNIHandles::make_local(env, klass->java_mirror()); jint result; @@ -583,10 +580,7 @@ TypeOrigin ClassVerifier::ref_ctx(const char* sig, TRAPS) { } void ClassVerifier::verify_class(TRAPS) { - if (VerboseVerification) { - tty->print_cr("Verifying class %s with new format", - _klass->external_name()); - } + log_info(verification)("Verifying class %s with new format", _klass->external_name()); Array* methods = _klass->methods(); int num_methods = methods->length(); @@ -606,10 +600,7 @@ void ClassVerifier::verify_class(TRAPS) { } if (was_recursively_verified()){ - if (VerboseVerification){ - tty->print_cr("Recursive verification detected for: %s", - _klass->external_name()); - } + log_info(verification)("Recursive verification detected for: %s", _klass->external_name()); log_info(classinit)("Recursive verification detected for: %s", _klass->external_name()); } @@ -618,9 +609,7 @@ void ClassVerifier::verify_class(TRAPS) { void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { HandleMark hm(THREAD); _method = m; // initialize _method - if (VerboseVerification) { - tty->print_cr("Verifying method %s", m->name_and_sig_as_C_string()); - } + log_info(verification)("Verifying method %s", m->name_and_sig_as_C_string()); // For clang, the only good constant format string is a literal constant format string. #define bad_type_msg "Bad type on operand stack in %s" @@ -667,8 +656,9 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { StackMapTable stackmap_table(&reader, ¤t_frame, max_locals, max_stack, code_data, code_length, CHECK_VERIFY(this)); - if (VerboseVerification) { - stackmap_table.print_on(tty); + if (log_is_enabled(Info, verification)) { + ResourceMark rm(THREAD); + stackmap_table.print_on(Log(verification)::info_stream()); } RawBytecodeStream bcs(m); @@ -708,12 +698,11 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { VerificationType type, type2; VerificationType atype; -#ifndef PRODUCT - if (VerboseVerification) { - current_frame.print_on(tty); - tty->print_cr("offset = %d, opcode = %s", bci, Bytecodes::name(opcode)); + if (log_is_enabled(Info, verification)) { + ResourceMark rm(THREAD); + current_frame.print_on(Log(verification)::info_stream()); + log_info(verification)("offset = %d, opcode = %s", bci, Bytecodes::name(opcode)); } -#endif // Make sure wide instruction is in correct format if (bcs.is_wide()) { @@ -2005,7 +1994,7 @@ Klass* ClassVerifier::load_class(Symbol* name, TRAPS) { name, Handle(THREAD, loader), Handle(THREAD, protection_domain), true, THREAD); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { instanceKlassHandle cur_class = current_class(); Verifier::trace_class_resolution(kls, cur_class()); } @@ -2533,11 +2522,10 @@ void ClassVerifier::verify_invoke_init( verify_error(ErrorContext::bad_code(bci), "Bad method call from after the start of a try block"); return; - } else if (VerboseVerification) { - ResourceMark rm; - tty->print_cr( - "Survived call to ends_in_athrow(): %s", - current_class()->name()->as_C_string()); + } else if (log_is_enabled(Info, verification)) { + ResourceMark rm(THREAD); + log_info(verification)("Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); } } } diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 2a3eeba36bb..7586786e6cf 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -102,7 +102,6 @@ template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \ template(java_net_URL, "java/net/URL") \ template(java_util_jar_Manifest, "java/util/jar/Manifest") \ - template(impliesCreateAccessControlContext_name, "impliesCreateAccessControlContext") \ template(java_io_OutputStream, "java/io/OutputStream") \ template(java_io_Reader, "java/io/Reader") \ template(java_io_BufferedReader, "java/io/BufferedReader") \ @@ -228,26 +227,20 @@ \ /* Support for reflection based on dynamic bytecode generation (JDK 1.4 and above) */ \ \ - template(sun_reflect_FieldInfo, "sun/reflect/FieldInfo") \ - template(sun_reflect_MethodInfo, "sun/reflect/MethodInfo") \ - template(sun_reflect_MagicAccessorImpl, "sun/reflect/MagicAccessorImpl") \ - template(sun_reflect_MethodAccessorImpl, "sun/reflect/MethodAccessorImpl") \ - template(sun_reflect_ConstructorAccessorImpl, "sun/reflect/ConstructorAccessorImpl") \ - template(sun_reflect_SerializationConstructorAccessorImpl, "sun/reflect/SerializationConstructorAccessorImpl") \ - template(sun_reflect_DelegatingClassLoader, "sun/reflect/DelegatingClassLoader") \ - template(sun_reflect_Reflection, "sun/reflect/Reflection") \ - template(sun_reflect_CallerSensitive, "sun/reflect/CallerSensitive") \ - template(sun_reflect_CallerSensitive_signature, "Lsun/reflect/CallerSensitive;") \ + template(reflect_MagicAccessorImpl, "jdk/internal/reflect/MagicAccessorImpl") \ + template(reflect_MethodAccessorImpl, "jdk/internal/reflect/MethodAccessorImpl") \ + template(reflect_ConstructorAccessorImpl, "jdk/internal/reflect/ConstructorAccessorImpl") \ + template(reflect_DelegatingClassLoader, "jdk/internal/reflect/DelegatingClassLoader") \ + template(reflect_Reflection, "jdk/internal/reflect/Reflection") \ + template(reflect_CallerSensitive, "jdk/internal/reflect/CallerSensitive") \ + template(reflect_CallerSensitive_signature, "Ljdk/internal/reflect/CallerSensitive;") \ template(checkedExceptions_name, "checkedExceptions") \ template(clazz_name, "clazz") \ template(exceptionTypes_name, "exceptionTypes") \ template(modifiers_name, "modifiers") \ template(newConstructor_name, "newConstructor") \ - template(newConstructor_signature, "(Lsun/reflect/MethodInfo;)Ljava/lang/reflect/Constructor;") \ template(newField_name, "newField") \ - template(newField_signature, "(Lsun/reflect/FieldInfo;)Ljava/lang/reflect/Field;") \ template(newMethod_name, "newMethod") \ - template(newMethod_signature, "(Lsun/reflect/MethodInfo;)Ljava/lang/reflect/Method;") \ template(invokeBasic_name, "invokeBasic") \ template(linkToVirtual_name, "linkToVirtual") \ template(linkToStatic_name, "linkToStatic") \ @@ -269,9 +262,9 @@ template(executable_name, "executable") \ template(parameter_annotations_name, "parameterAnnotations") \ template(annotation_default_name, "annotationDefault") \ - template(sun_reflect_ConstantPool, "sun/reflect/ConstantPool") \ + template(reflect_ConstantPool, "jdk/internal/reflect/ConstantPool") \ template(ConstantPool_name, "constantPoolOop") \ - template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\ + template(reflect_UnsafeStaticFieldAccessorImpl, "jdk/internal/reflect/UnsafeStaticFieldAccessorImpl")\ template(base_name, "base") \ /* Type Annotations (JDK 8 and above) */ \ template(type_annotations_name, "typeAnnotations") \ @@ -327,7 +320,6 @@ template(java_lang_StackFrameInfo, "java/lang/StackFrameInfo") \ template(java_lang_LiveStackFrameInfo, "java/lang/LiveStackFrameInfo") \ template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \ - template(doStackWalk_name, "doStackWalk") \ template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \ template(asPrimitive_name, "asPrimitive") \ template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ @@ -378,14 +370,13 @@ template(type_name, "type") \ template(findNative_name, "findNative") \ template(deadChild_name, "deadChild") \ - template(addClass_name, "addClass") \ - template(throwIllegalAccessError_name, "throwIllegalAccessError") \ template(getFromClass_name, "getFromClass") \ template(dispatch_name, "dispatch") \ template(getSystemClassLoader_name, "getSystemClassLoader") \ template(fillInStackTrace_name, "fillInStackTrace") \ template(getCause_name, "getCause") \ template(initCause_name, "initCause") \ + template(depth_name, "depth") \ template(setProperty_name, "setProperty") \ template(getProperty_name, "getProperty") \ template(context_name, "context") \ @@ -473,10 +464,6 @@ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(module_entry_name, "module_entry") \ \ - /* non-intrinsic name/signature pairs: */ \ - template(register_method_name, "register") \ - do_alias(register_method_signature, object_void_signature) \ - \ /* name symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ \ @@ -877,12 +864,12 @@ do_intrinsic(_Class_cast, java_lang_Class, Class_cast_name, object_object_signature, F_R) \ do_name( Class_cast_name, "cast") \ \ - do_intrinsic(_getClassAccessFlags, sun_reflect_Reflection, getClassAccessFlags_name, class_int_signature, F_SN) \ + do_intrinsic(_getClassAccessFlags, reflect_Reflection, getClassAccessFlags_name, class_int_signature, F_SN) \ do_name( getClassAccessFlags_name, "getClassAccessFlags") \ do_intrinsic(_getLength, java_lang_reflect_Array, getLength_name, object_int_signature, F_SN) \ do_name( getLength_name, "getLength") \ \ - do_intrinsic(_getCallerClass, sun_reflect_Reflection, getCallerClass_name, void_class_signature, F_SN) \ + do_intrinsic(_getCallerClass, reflect_Reflection, getCallerClass_name, void_class_signature, F_SN) \ do_name( getCallerClass_name, "getCallerClass") \ \ do_intrinsic(_newArray, java_lang_reflect_Array, newArray_name, newArray_signature, F_SN) \ diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp index 18a9f086974..38cae60350a 100644 --- a/hotspot/src/share/vm/code/codeBlob.cpp +++ b/hotspot/src/share/vm/code/codeBlob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "interpreter/bytecode.hpp" #include "memory/allocation.inline.hpp" #include "memory/heap.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "prims/forte.hpp" #include "runtime/handles.inline.hpp" diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index dbe48d58ffc..f2dfcee02b5 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -1042,6 +1042,14 @@ void CodeCache::clear_inline_caches() { } } +void CodeCache::cleanup_inline_caches() { + assert_locked_or_safepoint(CodeCache_lock); + NMethodIterator iter; + while(iter.next_alive()) { + iter.method()->cleanup_inline_caches(/*clean_all=*/true); + } +} + // Keeps track of time spent for checking dependencies NOT_PRODUCT(static elapsedTimer dependentCheckTime;) diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 343e41cbf1c..47d2a7f3b1f 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -201,6 +201,7 @@ class CodeCache : AllStatic { static bool needs_cache_clean() { return _needs_cache_clean; } static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } static void clear_inline_caches(); // clear all inline caches + static void cleanup_inline_caches(); // Returns true if an own CodeHeap for the given CodeBlobType is available static bool heap_available(int code_blob_type); diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index b2dde314f54..f3808bd041b 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "interpreter/linkResolver.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index 097d5f75cae..8bcef277d2a 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -30,6 +30,7 @@ #include "classfile/javaClasses.inline.hpp" #include "code/dependencies.hpp" #include "compiler/compileLog.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" #include "runtime/handles.hpp" diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index fb83ce224ed..77939f06e20 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -36,6 +36,7 @@ #include "compiler/directivesParser.hpp" #include "compiler/disassembler.hpp" #include "interpreter/bytecode.hpp" +#include "memory/resourceArea.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" @@ -1138,8 +1139,7 @@ void nmethod::clear_ic_stubs() { } } - -void nmethod::cleanup_inline_caches() { +void nmethod::cleanup_inline_caches(bool clean_all/*=false*/) { assert_locked_or_safepoint(CompiledIC_lock); // If the method is not entrant or zombie then a JMP is plastered over the @@ -1169,7 +1169,7 @@ void nmethod::cleanup_inline_caches() { if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; // Clean inline caches pointing to zombie, non-entrant and unloaded methods - if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive()); + if (clean_all || !nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive()); } break; } @@ -1179,7 +1179,7 @@ void nmethod::cleanup_inline_caches() { if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; // Clean inline caches pointing to zombie, non-entrant and unloaded methods - if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean(); + if (clean_all || !nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean(); } break; } @@ -1321,7 +1321,7 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { // Break cycle between nmethod & method if (log_is_enabled(Trace, classunload)) { - outputStream* log = LogHandle(classunload)::trace_stream(); + outputStream* log = Log(classunload)::trace_stream(); log->print_cr("making nmethod " INTPTR_FORMAT " unloadable, Method*(" INTPTR_FORMAT "), cause(" INTPTR_FORMAT ")", diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 5d18b582c88..1a8c82cc335 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -599,7 +599,7 @@ public: // Inline cache support void clear_inline_caches(); void clear_ic_stubs(); - void cleanup_inline_caches(); + void cleanup_inline_caches(bool clean_all = false); bool inlinecache_check_contains(address addr) const { return (addr >= code_begin() && addr < verified_entry_point()); } diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 08e80cfde6e..c4758b2e183 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -32,8 +32,10 @@ #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/directivesParser.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" @@ -48,6 +50,7 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" +#include "runtime/timerTrace.hpp" #include "trace/tracing.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -386,13 +389,16 @@ CompileTask* CompileQueue::get() { task = CompilationPolicy::policy()->select_task(this); } - // Save method pointers across unlock safepoint. The task is removed from - // the compilation queue, which is walked during RedefineClasses. - save_method = methodHandle(task->method()); - save_hot_method = methodHandle(task->hot_method()); + if (task != NULL) { + // Save method pointers across unlock safepoint. The task is removed from + // the compilation queue, which is walked during RedefineClasses. + save_method = methodHandle(task->method()); + save_hot_method = methodHandle(task->hot_method()); + + remove(task); + purge_stale_tasks(); // may temporarily release MCQ lock + } - remove(task); - purge_stale_tasks(); // may temporarily release MCQ lock return task; } @@ -901,7 +907,7 @@ void CompileBroker::compile_method_base(const methodHandle& method, // the pending list lock or a 3-way deadlock may occur // between the reference handler thread, a GC (instigated // by a compiler thread), and compiled method registration. - if (InstanceRefKlass::owns_pending_list_lock(JavaThread::current())) { + if (ReferencePendingListLocker::is_locked_by_self()) { return; } @@ -1781,7 +1787,8 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { bool is_osr = (osr_bci != standard_entry_bci); bool should_log = (thread->log() != NULL); bool should_break = false; - int task_level = task->comp_level(); + const int task_level = task->comp_level(); + AbstractCompiler* comp = task->compiler(); DirectiveSet* directive; { @@ -1793,7 +1800,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { assert(!method->is_native(), "no longer compile natives"); // Look up matching directives - directive = DirectivesStack::getMatchingDirective(method, compiler(task_level)); + directive = DirectivesStack::getMatchingDirective(method, comp); // Save information about this method in case of failure. set_last_compile(thread, method, is_osr, task_level); @@ -1812,13 +1819,13 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { int compilable = ciEnv::MethodCompilable; const char* failure_reason = NULL; const char* retry_message = NULL; - AbstractCompiler *comp = compiler(task_level); int system_dictionary_modification_counter; { MutexLocker locker(Compile_lock, thread); system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); } + #if INCLUDE_JVMCI if (UseJVMCICompiler && comp != NULL && comp->is_jvmci()) { JVMCICompiler* jvmci = (JVMCICompiler*) comp; diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp index a59aa55c5c4..75dbd83d6a1 100644 --- a/hotspot/src/share/vm/compiler/compileTask.cpp +++ b/hotspot/src/share/vm/compiler/compileTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "compiler/compileLog.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compilerDirectives.hpp" +#include "memory/resourceArea.hpp" CompileTask* CompileTask::_task_free_list = NULL; #ifdef ASSERT @@ -122,6 +123,13 @@ void CompileTask::initialize(int compile_id, _next = NULL; } +/** + * Returns the compiler for this task. + */ +AbstractCompiler* CompileTask::compiler() { + return CompileBroker::compiler(_comp_level); +} + // ------------------------------------------------------------------ // CompileTask::code/set_code // diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp index 92f74dc569b..1725b83fe32 100644 --- a/hotspot/src/share/vm/compiler/compileTask.hpp +++ b/hotspot/src/share/vm/compiler/compileTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,8 @@ class CompileTask : public CHeapObj { int comp_level() { return _comp_level;} void set_comp_level(int comp_level) { _comp_level = comp_level;} + AbstractCompiler* compiler(); + int num_inlined_bytecodes() const { return _num_inlined_bytecodes; } void set_num_inlined_bytecodes(int n) { _num_inlined_bytecodes = n; } diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 22ba721e7f2..3ac14accad3 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -28,6 +28,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compilerDirectives.hpp" #include "compiler/compilerOracle.hpp" +#include "memory/resourceArea.hpp" CompilerDirectives::CompilerDirectives() :_match(NULL), _next(NULL), _ref_count(0) { _c1_store = new DirectiveSet(this); diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp index 9c6d6a0201f..60a935be5a2 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.cpp +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -26,6 +26,7 @@ #include "compiler/compileBroker.hpp" #include "compiler/directivesParser.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 58859784479..44fb2272c00 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "compiler/disassembler.hpp" #include "gc/shared/cardTableModRefBS.hpp" #include "gc/shared/collectedHeap.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/fprofiler.hpp" #include "runtime/handles.inline.hpp" diff --git a/hotspot/src/share/vm/compiler/methodLiveness.cpp b/hotspot/src/share/vm/compiler/methodLiveness.cpp index d3a3f4b13e4..177c72fee9c 100644 --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #include "interpreter/bytecode.hpp" #include "interpreter/bytecodes.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/bitMap.inline.hpp" // The MethodLiveness class performs a simple liveness analysis on a method diff --git a/hotspot/src/share/vm/compiler/methodMatcher.cpp b/hotspot/src/share/vm/compiler/methodMatcher.cpp index 51d38c7caec..8113d859cff 100644 --- a/hotspot/src/share/vm/compiler/methodMatcher.cpp +++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "compiler/methodMatcher.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" // The JVM specification defines the allowed characters. diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp index c1f3ba4acf8..ac9d84e5d12 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp @@ -30,7 +30,6 @@ #include "gc/shared/blockOffsetTable.inline.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/liveRange.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" #include "memory/allocation.inline.hpp" @@ -501,7 +500,7 @@ void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c, out void CompactibleFreeListSpace::reportFreeListStatistics(const char* title) const { assert_lock_strong(&_freelistLock); - LogHandle(gc, freelist, stats) log; + Log(gc, freelist, stats) log; if (!log.is_debug()) { return; } @@ -1931,11 +1930,6 @@ CompactibleFreeListSpace::refillLinearAllocBlockIfNeeded(LinearAllocBlock* blk) if (blk->_ptr == NULL) { refillLinearAllocBlock(blk); } - if (PrintMiscellaneous && Verbose) { - if (blk->_word_size == 0) { - warning("CompactibleFreeListSpace(prologue):: Linear allocation failure"); - } - } } void @@ -2205,7 +2199,7 @@ class VerifyAllBlksClosure: public BlkClosure { } } if (res == 0) { - LogHandle(gc, verify) log; + Log(gc, verify) log; log.error("Livelock: no rank reduction!"); log.error(" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n" " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n", @@ -2379,14 +2373,14 @@ void CompactibleFreeListSpace::check_free_list_consistency() const { void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { assert_lock_strong(&_freelistLock); - LogHandle(gc, freelist, census) log; - if (!log.is_debug()) { + LogTarget(Debug, gc, freelist, census) log; + if (!log.is_enabled()) { return; } AdaptiveFreeList total; - log.debug("end sweep# " SIZE_FORMAT, sweep_count); + log.print("end sweep# " SIZE_FORMAT, sweep_count); ResourceMark rm; - outputStream* out = log.debug_stream(); + outputStream* out = log.stream(); AdaptiveFreeList::print_labels_on(out, "size"); size_t total_free = 0; for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { @@ -2408,8 +2402,8 @@ void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { total.set_split_deaths(total.split_deaths() + fl->split_deaths()); } total.print_on(out, "TOTAL"); - log.debug("Total free in indexed lists " SIZE_FORMAT " words", total_free); - log.debug("growth: %8.5f deficit: %8.5f", + log.print("Total free in indexed lists " SIZE_FORMAT " words", total_free); + log.print("growth: %8.5f deficit: %8.5f", (double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/ (total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0), (double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0)); @@ -2541,7 +2535,7 @@ void CompactibleFreeListSpaceLAB::compute_desired_plab_size() { _blocks_to_claim[i].sample( MAX2(CMSOldPLABMin, MIN2(CMSOldPLABMax, - _global_num_blocks[i]/(_global_num_workers[i]*CMSOldPLABNumRefills)))); + _global_num_blocks[i]/_global_num_workers[i]/CMSOldPLABNumRefills))); } // Reset counters for next round _global_num_workers[i] = 0; diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp index d976492b56e..42fd21dc65d 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp @@ -502,7 +502,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, { MutexLockerEx x(_markBitMap.lock(), Mutex::_no_safepoint_check_flag); if (!_markBitMap.allocate(_span)) { - warning("Failed to allocate CMS Bit Map"); + log_warning(gc)("Failed to allocate CMS Bit Map"); return; } assert(_markBitMap.covers(_span), "_markBitMap inconsistency?"); @@ -513,7 +513,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, } if (!_markStack.allocate(MarkStackSize)) { - warning("Failed to allocate CMS Marking Stack"); + log_warning(gc)("Failed to allocate CMS Marking Stack"); return; } @@ -527,8 +527,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, _conc_workers = new YieldingFlexibleWorkGang("CMS Thread", ConcGCThreads, true); if (_conc_workers == NULL) { - warning("GC/CMS: _conc_workers allocation failure: " - "forcing -CMSConcurrentMTEnabled"); + log_warning(gc)("GC/CMS: _conc_workers allocation failure: forcing -CMSConcurrentMTEnabled"); CMSConcurrentMTEnabled = false; } else { _conc_workers->initialize_workers(); @@ -559,7 +558,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, && num_queues > 0) { _task_queues = new OopTaskQueueSet(num_queues); if (_task_queues == NULL) { - warning("task_queues allocation failure."); + log_warning(gc)("task_queues allocation failure."); return; } _hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC); @@ -567,7 +566,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, for (i = 0; i < num_queues; i++) { PaddedOopTaskQueue *q = new PaddedOopTaskQueue(); if (q == NULL) { - warning("work_queue allocation failure."); + log_warning(gc)("work_queue allocation failure."); return; } _task_queues->register_queue(i, q); @@ -694,7 +693,7 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promoti // At a promotion failure dump information on block layout in heap // (cms old generation). void ConcurrentMarkSweepGeneration::promotion_failure_occurred() { - LogHandle(gc, promotion) log; + Log(gc, promotion) log; if (log.is_trace()) { ResourceMark rm; cmsSpace()->dump_at_safepoint_with_locks(collector(), log.trace_stream()); @@ -753,7 +752,7 @@ void ConcurrentMarkSweepGeneration::compute_new_size_free_list() { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); assert(desired_capacity >= capacity(), "invalid expansion size"); size_t expand_bytes = MAX2(desired_capacity - capacity(), MinHeapDeltaBytes); - LogHandle(gc) log; + Log(gc) log; if (log.is_trace()) { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); log.trace("From compute_new_size: "); @@ -1118,7 +1117,7 @@ bool CMSCollector::shouldConcurrentCollect() { // ------------------------------------------------------------------ // Print out lots of information which affects the initiation of // a collection. - LogHandle(gc) log; + Log(gc) log; if (log.is_trace() && stats().valid()) { log.trace("CMSCollector shouldConcurrentCollect: "); ResourceMark rm; @@ -1413,7 +1412,7 @@ void CMSCollector::acquire_control_and_collect(bool full, if (_foregroundGCShouldWait) { // We are going to be waiting for action for the CMS thread; // it had better not be gone (for instance at shutdown)! - assert(ConcurrentMarkSweepThread::cmst() != NULL, + assert(ConcurrentMarkSweepThread::cmst() != NULL && !ConcurrentMarkSweepThread::cmst()->has_terminated(), "CMS thread must be running"); // Wait here until the background collector gives us the go-ahead ConcurrentMarkSweepThread::clear_CMS_flag( @@ -1519,7 +1518,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { gch->pre_full_gc_dump(gc_timer); - GCTraceTime(Trace, gc) t("CMS:MSC"); + GCTraceTime(Trace, gc, phases) t("CMS:MSC"); // Temporarily widen the span of the weak reference processing to // the entire heap. @@ -1606,7 +1605,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { } void CMSCollector::print_eden_and_survivor_chunk_arrays() { - LogHandle(gc, heap) log; + Log(gc, heap) log; if (!log.is_trace()) { return; } @@ -2222,7 +2221,7 @@ class VerifyMarkedClosure: public BitMapClosure { bool do_bit(size_t offset) { HeapWord* addr = _marks->offsetToHeapWord(offset); if (!_marks->isMarked(addr)) { - LogHandle(gc, verify) log; + Log(gc, verify) log; ResourceMark rm; oop(addr)->print_on(log.error_stream()); log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); @@ -2235,7 +2234,7 @@ class VerifyMarkedClosure: public BitMapClosure { }; bool CMSCollector::verify_after_remark() { - GCTraceTime(Info, gc, verify) tm("Verifying CMS Marking."); + GCTraceTime(Info, gc, phases, verify) tm("Verifying CMS Marking."); MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag); static bool init = false; @@ -2287,17 +2286,16 @@ bool CMSCollector::verify_after_remark() { // all marking, then check if the new marks-vector is // a subset of the CMS marks-vector. verify_after_remark_work_1(); - } else if (CMSRemarkVerifyVariant == 2) { + } else { + guarantee(CMSRemarkVerifyVariant == 2, "Range checking for CMSRemarkVerifyVariant should guarantee 1 or 2"); // In this second variant of verification, we flag an error // (i.e. an object reachable in the new marks-vector not reachable // in the CMS marks-vector) immediately, also indicating the // identify of an object (A) that references the unmarked object (B) -- // presumably, a mutation to A failed to be picked up by preclean/remark? verify_after_remark_work_2(); - } else { - warning("Unrecognized value " UINTX_FORMAT " for CMSRemarkVerifyVariant", - CMSRemarkVerifyVariant); } + return true; } @@ -2349,7 +2347,7 @@ void CMSCollector::verify_after_remark_work_1() { VerifyMarkedClosure vcl(markBitMap()); verification_mark_bm()->iterate(&vcl); if (vcl.failed()) { - LogHandle(gc, verify) log; + Log(gc, verify) log; log.error("Failed marking verification after remark"); ResourceMark rm; gch->print_on(log.error_stream()); @@ -2820,7 +2818,7 @@ void CMSCollector::checkpointRootsInitialWork() { // CMS collection cycle. setup_cms_unloading_and_verification_state(); - GCTraceTime(Trace, gc) ts("checkpointRootsInitialWork", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) ts("checkpointRootsInitialWork", _gc_timer_cm); // Reset all the PLAB chunk arrays if necessary. if (_survivor_plab_array != NULL && !CMSPLABRecordAlways) { @@ -3650,7 +3648,7 @@ void CMSCollector::abortable_preclean() { // XXX FIX ME!!! YSR size_t loops = 0, workdone = 0, cumworkdone = 0, waited = 0; while (!(should_abort_preclean() || - ConcurrentMarkSweepThread::should_terminate())) { + ConcurrentMarkSweepThread::cmst()->should_terminate())) { workdone = preclean_work(CMSPrecleanRefLists2, CMSPrecleanSurvivors2); cumworkdone += workdone; loops++; @@ -4104,8 +4102,6 @@ void CMSCollector::checkpointRootsFinal() { // expect it to be false and set to true FlagSetting fl(gch->_is_gc_active, false); - GCTraceTime(Trace, gc) tm("Pause Scavenge Before Remark", _gc_timer_cm); - gch->do_collection(true, // full (i.e. force, see below) false, // !clear_all_soft_refs 0, // size @@ -4123,7 +4119,7 @@ void CMSCollector::checkpointRootsFinal() { } void CMSCollector::checkpointRootsFinalWork() { - GCTraceTime(Trace, gc) tm("checkpointRootsFinalWork", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) tm("checkpointRootsFinalWork", _gc_timer_cm); assert(haveFreelistLocks(), "must have free list locks"); assert_lock_strong(bitMapLock()); @@ -4173,10 +4169,10 @@ void CMSCollector::checkpointRootsFinalWork() { // the most recent young generation GC, minus those cleaned up by the // concurrent precleaning. if (CMSParallelRemarkEnabled) { - GCTraceTime(Debug, gc) t("Rescan (parallel)", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Rescan (parallel)", _gc_timer_cm); do_remark_parallel(); } else { - GCTraceTime(Debug, gc) t("Rescan (non-parallel)", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Rescan (non-parallel)", _gc_timer_cm); do_remark_non_parallel(); } } @@ -4184,7 +4180,7 @@ void CMSCollector::checkpointRootsFinalWork() { verify_overflow_empty(); { - GCTraceTime(Trace, gc) ts("refProcessingWork", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) ts("refProcessingWork", _gc_timer_cm); refProcessingWork(); } verify_work_stacks_empty(); @@ -4907,7 +4903,7 @@ void CMSCollector::do_remark_non_parallel() { NULL, // space is set further below &_markBitMap, &_markStack, &mrias_cl); { - GCTraceTime(Trace, gc) t("Grey Object Rescan", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) t("Grey Object Rescan", _gc_timer_cm); // Iterate over the dirty cards, setting the corresponding bits in the // mod union table. { @@ -4941,7 +4937,7 @@ void CMSCollector::do_remark_non_parallel() { Universe::verify(); } { - GCTraceTime(Trace, gc) t("Root Rescan", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) t("Root Rescan", _gc_timer_cm); verify_work_stacks_empty(); @@ -4963,7 +4959,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime(Trace, gc) t("Visit Unhandled CLDs", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) t("Visit Unhandled CLDs", _gc_timer_cm); verify_work_stacks_empty(); @@ -4982,7 +4978,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime(Trace, gc) t("Dirty Klass Scan", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) t("Dirty Klass Scan", _gc_timer_cm); verify_work_stacks_empty(); @@ -5186,7 +5182,7 @@ void CMSCollector::refProcessingWork() { _span, &_markBitMap, &_markStack, &cmsKeepAliveClosure, false /* !preclean */); { - GCTraceTime(Debug, gc) t("Weak Refs Processing", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer_cm); ReferenceProcessorStats stats; if (rp->processing_is_mt()) { @@ -5228,7 +5224,7 @@ void CMSCollector::refProcessingWork() { if (should_unload_classes()) { { - GCTraceTime(Debug, gc) t("Class Unloading", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer_cm); // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); @@ -5241,13 +5237,13 @@ void CMSCollector::refProcessingWork() { } { - GCTraceTime(Debug, gc) t("Scrub Symbol Table", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", _gc_timer_cm); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } { - GCTraceTime(Debug, gc) t("Scrub String Table", _gc_timer_cm); + GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer_cm); // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } @@ -5657,13 +5653,13 @@ bool CMSBitMap::allocate(MemRegion mr) { ReservedSpace brs(ReservedSpace::allocation_align_size_up( (_bmWordSize >> (_shifter + LogBitsPerByte)) + 1)); if (!brs.is_reserved()) { - warning("CMS bit map allocation failure"); + log_warning(gc)("CMS bit map allocation failure"); return false; } // For now we'll just commit all of the bit map up front. // Later on we'll try to be more parsimonious with swap. if (!_virtual_space.initialize(brs, brs.size())) { - warning("CMS bit map backing store failure"); + log_warning(gc)("CMS bit map backing store failure"); return false; } assert(_virtual_space.committed_size() == brs.size(), @@ -5749,11 +5745,11 @@ bool CMSMarkStack::allocate(size_t size) { ReservedSpace rs(ReservedSpace::allocation_align_size_up( size * sizeof(oop))); if (!rs.is_reserved()) { - warning("CMSMarkStack allocation failure"); + log_warning(gc)("CMSMarkStack allocation failure"); return false; } if (!_virtual_space.initialize(rs, rs.size())) { - warning("CMSMarkStack backing store failure"); + log_warning(gc)("CMSMarkStack backing store failure"); return false; } assert(_virtual_space.committed_size() == rs.size(), @@ -5878,7 +5874,7 @@ void MarkRefsIntoVerifyClosure::do_oop(oop obj) { if (_span.contains(addr)) { _verification_bm->mark(addr); if (!_cms_bm->isMarked(addr)) { - LogHandle(gc, verify) log; + Log(gc, verify) log; ResourceMark rm; oop(addr)->print_on(log.error_stream()); log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); @@ -6659,7 +6655,7 @@ void PushAndMarkVerifyClosure::do_oop(oop obj) { // Oop lies in _span and isn't yet grey or black _verification_bm->mark(addr); // now grey if (!_cms_bm->isMarked(addr)) { - LogHandle(gc, verify) log; + Log(gc, verify) log; ResourceMark rm; oop(addr)->print_on(log.error_stream()); log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); @@ -7047,13 +7043,13 @@ SweepClosure::SweepClosure(CMSCollector* collector, } void SweepClosure::print_on(outputStream* st) const { - tty->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(_sp->bottom()), p2i(_sp->end())); - tty->print_cr("_limit = " PTR_FORMAT, p2i(_limit)); - tty->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger)); - NOT_PRODUCT(tty->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));) - tty->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d", - _inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced); + st->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(_sp->bottom()), p2i(_sp->end())); + st->print_cr("_limit = " PTR_FORMAT, p2i(_limit)); + st->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger)); + NOT_PRODUCT(st->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));) + st->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d", + _inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced); } #ifndef PRODUCT @@ -7066,8 +7062,10 @@ SweepClosure::~SweepClosure() { assert(_limit >= _sp->bottom() && _limit <= _sp->end(), "sweep _limit out of bounds"); if (inFreeRange()) { - warning("inFreeRange() should have been reset; dumping state of SweepClosure"); - print(); + Log(gc, sweep) log; + log.error("inFreeRange() should have been reset; dumping state of SweepClosure"); + ResourceMark rm; + print_on(log.error_stream()); ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp index bb1ff998d8d..3ea77838462 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "oops/instanceRefKlass.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -42,16 +42,10 @@ ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::_cmst = NULL; CMSCollector* ConcurrentMarkSweepThread::_collector = NULL; -bool ConcurrentMarkSweepThread::_should_terminate = false; int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil; volatile jint ConcurrentMarkSweepThread::_pending_yields = 0; -SurrogateLockerThread* ConcurrentMarkSweepThread::_slt = NULL; -SurrogateLockerThread::SLT_msg_type - ConcurrentMarkSweepThread::_sltBuffer = SurrogateLockerThread::empty; -Monitor* ConcurrentMarkSweepThread::_sltMonitor = NULL; - ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector) : ConcurrentGCThread() { assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); @@ -62,88 +56,58 @@ ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector) set_name("CMS Main Thread"); - if (os::create_thread(this, os::cgc_thread)) { - // An old comment here said: "Priority should be just less - // than that of VMThread". Since the VMThread runs at - // NearMaxPriority, the old comment was inaccurate, but - // changing the default priority to NearMaxPriority-1 - // could change current behavior, so the default of - // NearMaxPriority stays in place. - // - // Note that there's a possibility of the VMThread - // starving if UseCriticalCMSThreadPriority is on. - // That won't happen on Solaris for various reasons, - // but may well happen on non-Solaris platforms. - int native_prio; - if (UseCriticalCMSThreadPriority) { - native_prio = os::java_to_os_priority[CriticalPriority]; - } else { - native_prio = os::java_to_os_priority[NearMaxPriority]; - } - os::set_native_priority(this, native_prio); - - if (!DisableStartThread) { - os::start_thread(this); - } - } - _sltMonitor = SLT_lock; + // An old comment here said: "Priority should be just less + // than that of VMThread". Since the VMThread runs at + // NearMaxPriority, the old comment was inaccurate, but + // changing the default priority to NearMaxPriority-1 + // could change current behavior, so the default of + // NearMaxPriority stays in place. + // + // Note that there's a possibility of the VMThread + // starving if UseCriticalCMSThreadPriority is on. + // That won't happen on Solaris for various reasons, + // but may well happen on non-Solaris platforms. + create_and_start(UseCriticalCMSThreadPriority ? CriticalPriority : NearMaxPriority); } -void ConcurrentMarkSweepThread::run() { +void ConcurrentMarkSweepThread::run_service() { assert(this == cmst(), "just checking"); - initialize_in_thread(); - // From this time Thread::current() should be working. - assert(this == Thread::current(), "just checking"); if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) { - warning("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread); + log_warning(gc)("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread); } - // Wait until Universe::is_fully_initialized() + { - CMSLoopCountWarn loopX("CMS::run", "waiting for " - "Universe::is_fully_initialized()", 2); MutexLockerEx x(CGC_lock, true); set_CMS_flag(CMS_cms_wants_token); - // Wait until Universe is initialized and all initialization is completed. - while (!is_init_completed() && !Universe::is_fully_initialized() && - !_should_terminate) { - CGC_lock->wait(true, 200); - loopX.tick(); - } + assert(is_init_completed() && Universe::is_fully_initialized(), "ConcurrentGCThread::run() should have waited for this."); + // Wait until the surrogate locker thread that will do // pending list locking on our behalf has been created. // We cannot start the SLT thread ourselves since we need // to be a JavaThread to do so. CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2); - while (_slt == NULL && !_should_terminate) { + while (!ReferencePendingListLocker::is_initialized() && !should_terminate()) { CGC_lock->wait(true, 200); loopY.tick(); } clear_CMS_flag(CMS_cms_wants_token); } - while (!_should_terminate) { + while (!should_terminate()) { sleepBeforeNextCycle(); - if (_should_terminate) break; + if (should_terminate()) break; GCIdMark gc_id_mark; GCCause::Cause cause = _collector->_full_gc_requested ? _collector->_full_gc_cause : GCCause::_cms_concurrent_mark; _collector->collect_in_background(cause); } - assert(_should_terminate, "just checking"); + // Check that the state of any protocol for synchronization // between background (CMS) and foreground collector is "clean" // (i.e. will not potentially block the foreground collector, // requiring action by us). verify_ok_to_terminate(); - // Signal that it is terminated - { - MutexLockerEx mu(Terminator_lock, - Mutex::_no_safepoint_check_flag); - assert(_cmst == this, "Weird!"); - _cmst = NULL; - Terminator_lock->notify(); - } } #ifndef PRODUCT @@ -157,39 +121,24 @@ void ConcurrentMarkSweepThread::verify_ok_to_terminate() const { // create and start a new ConcurrentMarkSweep Thread for given CMS generation ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::start(CMSCollector* collector) { - if (!_should_terminate) { - assert(cmst() == NULL, "start() called twice?"); - ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector); - assert(cmst() == th, "Where did the just-created CMS thread go?"); - return th; - } - return NULL; + guarantee(_cmst == NULL, "start() called twice!"); + ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector); + assert(_cmst == th, "Where did the just-created CMS thread go?"); + return th; } -void ConcurrentMarkSweepThread::stop() { - // it is ok to take late safepoints here, if needed - { - MutexLockerEx x(Terminator_lock); - _should_terminate = true; - } - { // Now post a notify on CGC_lock so as to nudge - // CMS thread(s) that might be slumbering in - // sleepBeforeNextCycle. - MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - CGC_lock->notify_all(); - } - { // Now wait until (all) CMS thread(s) have exited - MutexLockerEx x(Terminator_lock); - while(cmst() != NULL) { - Terminator_lock->wait(); - } - } +void ConcurrentMarkSweepThread::stop_service() { + // Now post a notify on CGC_lock so as to nudge + // CMS thread(s) that might be slumbering in + // sleepBeforeNextCycle. + MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); + CGC_lock->notify_all(); } void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) { assert(tc != NULL, "Null ThreadClosure"); - if (_cmst != NULL) { - tc->do_thread(_cmst); + if (cmst() != NULL && !cmst()->has_terminated()) { + tc->do_thread(cmst()); } assert(Universe::is_fully_initialized(), "Called too early, make sure heap is fully initialized"); @@ -202,8 +151,8 @@ void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) { } void ConcurrentMarkSweepThread::print_all_on(outputStream* st) { - if (_cmst != NULL) { - _cmst->print_on(st); + if (cmst() != NULL && !cmst()->has_terminated()) { + cmst()->print_on(st); st->cr(); } if (_collector != NULL) { @@ -278,7 +227,7 @@ void ConcurrentMarkSweepThread::desynchronize(bool is_cms_thread) { void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) { MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - if (_should_terminate || _collector->_full_gc_requested) { + if (should_terminate() || _collector->_full_gc_requested) { return; } set_CMS_flag(CMS_cms_wants_token); // to provoke notifies @@ -307,7 +256,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { unsigned int loop_count = 0; - while(!_should_terminate) { + while(!should_terminate()) { double now_time = os::elapsedTime(); long wait_time_millis; @@ -327,7 +276,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { { MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - if (_should_terminate || _collector->_full_gc_requested) { + if (should_terminate() || _collector->_full_gc_requested) { return; } set_CMS_flag(CMS_cms_wants_token); // to provoke notifies @@ -358,13 +307,13 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { // Too many loops warning if(++loop_count == 0) { - warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1); + log_warning(gc)("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1); } } } void ConcurrentMarkSweepThread::sleepBeforeNextCycle() { - while (!_should_terminate) { + while (!should_terminate()) { if(CMSWaitDuration >= 0) { // Wait until the next synchronous GC, a concurrent full gc // request or a timeout, whichever is earlier. @@ -381,15 +330,3 @@ void ConcurrentMarkSweepThread::sleepBeforeNextCycle() { // and wait some more } } - -// Note: this method, although exported by the ConcurrentMarkSweepThread, -// which is a non-JavaThread, can only be called by a JavaThread. -// Currently this is done at vm creation time (post-vm-init) by the -// main/Primordial (Java)Thread. -// XXX Consider changing this in the future to allow the CMS thread -// itself to create this thread? -void ConcurrentMarkSweepThread::makeSurrogateLockerThread(TRAPS) { - assert(UseConcMarkSweepGC, "SLT thread needed only for CMS GC"); - assert(_slt == NULL, "SLT already created"); - _slt = SurrogateLockerThread::make(THREAD); -} diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp index 82f9e51a6b2..ccb69ea89f4 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,17 +37,10 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread { friend class VMStructs; friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship friend class CMSCollector; - public: - virtual void run(); private: - static ConcurrentMarkSweepThread* _cmst; - static CMSCollector* _collector; - static SurrogateLockerThread* _slt; - static SurrogateLockerThread::SLT_msg_type _sltBuffer; - static Monitor* _sltMonitor; - - static bool _should_terminate; + static ConcurrentMarkSweepThread* _cmst; + static CMSCollector* _collector; enum CMS_flag_type { CMS_nil = NoBits, @@ -72,13 +65,13 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread { // debugging void verify_ok_to_terminate() const PRODUCT_RETURN; + void run_service(); + void stop_service(); + public: // Constructor ConcurrentMarkSweepThread(CMSCollector* collector); - static void makeSurrogateLockerThread(TRAPS); - static SurrogateLockerThread* slt() { return _slt; } - static void threads_do(ThreadClosure* tc); // Printing @@ -91,8 +84,6 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread { // Create and start the CMS Thread, or stop it on shutdown static ConcurrentMarkSweepThread* start(CMSCollector* collector); - static void stop(); - static bool should_terminate() { return _should_terminate; } // Synchronization using CMS token static void synchronize(bool is_cms_thread); @@ -170,7 +161,7 @@ class CMSLoopCountWarn: public StackObj { inline void tick() { _ticks++; if (CMSLoopWarn && _ticks % _threshold == 0) { - warning("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg); + log_warning(gc)("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg); } } }; diff --git a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp index 35fa18f1d88..ccb513d097d 100644 --- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp @@ -161,15 +161,6 @@ process_stride(Space* sp, } } - -// If you want a talkative process_chunk_boundaries, -// then #define NOISY(x) x -#ifdef NOISY -#error "Encountered a global preprocessor flag, NOISY, which might clash with local definition to follow" -#else -#define NOISY(x) -#endif - void CardTableModRefBSForCTRS:: process_chunk_boundaries(Space* sp, @@ -197,10 +188,6 @@ process_chunk_boundaries(Space* sp, assert(start_chunk_index >= lowest_non_clean_base_chunk_index, "Bounds error."); uintptr_t cur_chunk_index = start_chunk_index - lowest_non_clean_base_chunk_index; - NOISY(tty->print_cr("===========================================================================");) - NOISY(tty->print_cr(" process_chunk_boundary: Called with [" PTR_FORMAT "," PTR_FORMAT ")", - chunk_mr.start(), chunk_mr.end());) - // First, set "our" lowest_non_clean entry, which would be // used by the thread scanning an adjoining left chunk with // a non-array object straddling the mutual boundary. @@ -239,36 +226,18 @@ process_chunk_boundaries(Space* sp, } } if (first_dirty_card != NULL) { - NOISY(tty->print_cr(" LNC: Found a dirty card at " PTR_FORMAT " in current chunk", - first_dirty_card);) assert(cur_chunk_index < lowest_non_clean_chunk_size, "Bounds error."); assert(lowest_non_clean[cur_chunk_index] == NULL, "Write exactly once : value should be stable hereafter for this round"); lowest_non_clean[cur_chunk_index] = first_dirty_card; - } NOISY(else { - tty->print_cr(" LNC: Found no dirty card in current chunk; leaving LNC entry NULL"); - // In the future, we could have this thread look for a non-NULL value to copy from its - // right neighbor (up to the end of the first object). - if (last_card_of_cur_chunk < last_card_of_first_obj) { - tty->print_cr(" LNC: BEWARE!!! first obj straddles past right end of chunk:\n" - " might be efficient to get value from right neighbor?"); - } - }) + } } else { // In this case we can help our neighbor by just asking them // to stop at our first card (even though it may not be dirty). - NOISY(tty->print_cr(" LNC: first block is not a non-array object; setting LNC to first card of current chunk");) assert(lowest_non_clean[cur_chunk_index] == NULL, "Write once : value should be stable hereafter"); jbyte* first_card_of_cur_chunk = byte_for(chunk_mr.start()); lowest_non_clean[cur_chunk_index] = first_card_of_cur_chunk; } - NOISY(tty->print_cr(" process_chunk_boundary: lowest_non_clean[" INTPTR_FORMAT "] = " PTR_FORMAT - " which corresponds to the heap address " PTR_FORMAT, - cur_chunk_index, lowest_non_clean[cur_chunk_index], - (lowest_non_clean[cur_chunk_index] != NULL) - ? addr_for(lowest_non_clean[cur_chunk_index]) - : NULL);) - NOISY(tty->print_cr("---------------------------------------------------------------------------");) // Next, set our own max_to_do, which will strictly/exclusively bound // the highest address that we will scan past the right end of our chunk. @@ -285,8 +254,6 @@ process_chunk_boundaries(Space* sp, || oop(last_block)->is_objArray() // last_block is an array (precisely marked) || oop(last_block)->is_typeArray()) { max_to_do = chunk_mr.end(); - NOISY(tty->print_cr(" process_chunk_boundary: Last block on this card is not a non-array object;\n" - " max_to_do left at " PTR_FORMAT, max_to_do);) } else { assert(last_block < chunk_mr.end(), "Tautology"); // It is a non-array object that straddles the right boundary of this chunk. @@ -301,9 +268,6 @@ process_chunk_boundaries(Space* sp, // subsequent cards still in this chunk must have been made // precisely; we can cap processing at the end of our chunk. max_to_do = chunk_mr.end(); - NOISY(tty->print_cr(" process_chunk_boundary: Head of last object on this card is not dirty;\n" - " max_to_do left at " PTR_FORMAT, - max_to_do);) } else { // The last object must be considered dirty, and extends onto the // following chunk. Look for a dirty card in that chunk that will @@ -323,8 +287,6 @@ process_chunk_boundaries(Space* sp, cur <= last_card_of_last_obj; cur++) { const jbyte val = *cur; if (card_will_be_scanned(val)) { - NOISY(tty->print_cr(" Found a non-clean card " PTR_FORMAT " with value 0x%x", - cur, (int)val);) limit_card = cur; break; } else { assert(!card_may_have_been_dirty(val), "Error: card can't be skipped"); @@ -333,10 +295,6 @@ process_chunk_boundaries(Space* sp, if (limit_card != NULL) { max_to_do = addr_for(limit_card); assert(limit_card != NULL && max_to_do != NULL, "Error"); - NOISY(tty->print_cr(" process_chunk_boundary: Found a dirty card at " PTR_FORMAT - " max_to_do set at " PTR_FORMAT " which is before end of last block in chunk: " - PTR_FORMAT " + " PTR_FORMAT " = " PTR_FORMAT, - limit_card, max_to_do, last_block, last_block_size, (last_block+last_block_size));) } else { // The following is a pessimistic value, because it's possible // that a dirty card on a subsequent chunk has been cleared by @@ -346,10 +304,6 @@ process_chunk_boundaries(Space* sp, limit_card = last_card_of_last_obj; max_to_do = last_block + last_block_size; assert(limit_card != NULL && max_to_do != NULL, "Error"); - NOISY(tty->print_cr(" process_chunk_boundary: Found no dirty card before end of last block in chunk\n" - " Setting limit_card to " PTR_FORMAT - " and max_to_do " PTR_FORMAT " + " PTR_FORMAT " = " PTR_FORMAT, - limit_card, last_block, last_block_size, max_to_do);) } assert(0 < cur_chunk_index+1 && cur_chunk_index+1 < lowest_non_clean_chunk_size, "Bounds error."); @@ -382,7 +336,6 @@ process_chunk_boundaries(Space* sp, "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", p2i(sp->used_region().start()), p2i(sp->used_region().end()), p2i(used.start()), p2i(used.end())); - NOISY(tty->print_cr(" process_chunk_boundary: heap expanded; explicitly bounding last_chunk");) last_chunk_index_to_check = last_chunk_index; } for (uintptr_t lnc_index = cur_chunk_index + 1; @@ -392,9 +345,6 @@ process_chunk_boundaries(Space* sp, if (lnc_card != NULL) { // we can stop at the first non-NULL entry we find if (lnc_card <= limit_card) { - NOISY(tty->print_cr(" process_chunk_boundary: LNC card " PTR_FORMAT " is lower than limit_card " PTR_FORMAT, - " max_to_do will be lowered to " PTR_FORMAT " from " PTR_FORMAT, - lnc_card, limit_card, addr_for(lnc_card), max_to_do);) limit_card = lnc_card; max_to_do = addr_for(limit_card); assert(limit_card != NULL && max_to_do != NULL, "Error"); @@ -410,9 +360,6 @@ process_chunk_boundaries(Space* sp, assert(max_to_do != NULL, "OOPS 2!"); } else { max_to_do = used.end(); - NOISY(tty->print_cr(" process_chunk_boundary: Last chunk of this space;\n" - " max_to_do left at " PTR_FORMAT, - max_to_do);) } assert(max_to_do != NULL, "OOPS 3!"); // Now we can set the closure we're using so it doesn't to beyond @@ -421,11 +368,8 @@ process_chunk_boundaries(Space* sp, #ifndef PRODUCT dcto_cl->set_last_bottom(max_to_do); #endif - NOISY(tty->print_cr("===========================================================================\n");) } -#undef NOISY - void CardTableModRefBSForCTRS:: get_LNC_array_for_space(Space* sp, diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index 366bf4671b3..ff88d1541be 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -233,11 +233,15 @@ HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { if (word_sz * 100 < ParallelGCBufferWastePct * plab->word_sz()) { // Is small enough; abandon this buffer and start a new one. plab->retire(); - size_t buf_size = plab->word_sz(); + // The minimum size has to be twice SurvivorAlignmentInBytes to + // allow for padding used in the alignment of 1 word. A padding + // of 1 is too small for a filler word so the padding size will + // be increased by SurvivorAlignmentInBytes. + size_t min_usable_size = 2 * static_cast(SurvivorAlignmentInBytes >> LogHeapWordSize); + size_t buf_size = MAX2(plab->word_sz(), min_usable_size); HeapWord* buf_space = sp->par_allocate(buf_size); if (buf_space == NULL) { - const size_t min_bytes = - PLAB::min_size() << LogHeapWordSize; + const size_t min_bytes = MAX2(PLAB::min_size(), min_usable_size) << LogHeapWordSize; size_t free_bytes = sp->free(); while(buf_space == NULL && free_bytes >= min_bytes) { buf_size = free_bytes >> LogHeapWordSize; @@ -253,7 +257,10 @@ HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { // Note that we cannot compare buf_size < word_sz below // because of AlignmentReserve (see PLAB::allocate()). assert(obj != NULL || plab->words_remaining() < word_sz, - "Else should have been able to allocate"); + "Else should have been able to allocate requested object size " + SIZE_FORMAT ", PLAB size " SIZE_FORMAT ", SurvivorAlignmentInBytes " + SIZE_FORMAT ", words_remaining " SIZE_FORMAT, + word_sz, buf_size, SurvivorAlignmentInBytes, plab->words_remaining()); // It's conceivable that we may be able to use the // buffer we just grabbed for subsequent small requests // even if not for this one. @@ -391,7 +398,7 @@ void ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st) } void ParScanThreadStateSet::print_termination_stats() { - LogHandle(gc, task, stats) log; + Log(gc, task, stats) log; if (!log.is_debug()) { return; } @@ -423,7 +430,7 @@ void ParScanThreadStateSet::print_taskqueue_stats() { if (!log_develop_is_enabled(Trace, gc, task, stats)) { return; } - LogHandle(gc, task, stats) log; + Log(gc, task, stats) log; ResourceMark rm; outputStream* st = log.trace_stream(); print_taskqueue_stats_hdr(st); @@ -901,7 +908,7 @@ void ParNewGeneration::collect(bool full, size_policy->minor_collection_begin(); } - GCTraceTime(Trace, gc) t1("ParNew", NULL, gch->gc_cause()); + GCTraceTime(Trace, gc, phases) t1("ParNew", NULL, gch->gc_cause()); age_table()->clear(); to()->clear(SpaceDecorator::Mangle); diff --git a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp index 6f8011eefd7..c94bdfc80aa 100644 --- a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp @@ -82,18 +82,19 @@ inline void ParScanClosure::do_oop_work(T* p, if ((HeapWord*)obj < _boundary) { #ifndef PRODUCT if (_g->to()->is_in_reserved(obj)) { - tty->print_cr("Scanning field (" PTR_FORMAT ") twice?", p2i(p)); + Log(gc) log; + log.error("Scanning field (" PTR_FORMAT ") twice?", p2i(p)); GenCollectedHeap* gch = GenCollectedHeap::heap(); Space* sp = gch->space_containing(p); oop obj = oop(sp->block_start(p)); assert((HeapWord*)obj < (HeapWord*)p, "Error"); - tty->print_cr("Object: " PTR_FORMAT, p2i((void *)obj)); - tty->print_cr("-------"); - obj->print(); - tty->print_cr("-----"); - tty->print_cr("Heap:"); - tty->print_cr("-----"); - gch->print(); + log.error("Object: " PTR_FORMAT, p2i((void *)obj)); + log.error("-------"); + obj->print_on(log.error_stream()); + log.error("-----"); + log.error("Heap:"); + log.error("-----"); + gch->print_on(log.error_stream()); ShouldNotReachHere(); } #endif diff --git a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp index e26b3842a9a..73f205485db 100644 --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,27 +38,17 @@ // Methods in abstract class VM_CMS_Operation ////////////////////////////////////////////////////////// void VM_CMS_Operation::acquire_pending_list_lock() { - // The caller may block while communicating - // with the SLT thread in order to acquire/release the PLL. - SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt(); - if (slt != NULL) { - slt->manipulatePLL(SurrogateLockerThread::acquirePLL); - } else { - SurrogateLockerThread::report_missing_slt(); - } + _pending_list_locker.lock(); } void VM_CMS_Operation::release_and_notify_pending_list_lock() { - // The caller may block while communicating - // with the SLT thread in order to acquire/release the PLL. - ConcurrentMarkSweepThread::slt()-> - manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); + _pending_list_locker.unlock(); } void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime(Info, gc, verify) tm("Verify Before", _collector->_gc_timer_cm); + GCTraceTime(Info, gc, phases, verify) tm("Verify Before", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -70,7 +60,7 @@ void VM_CMS_Operation::verify_before_gc() { void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime(Info, gc, verify) tm("Verify After", _collector->_gc_timer_cm); + GCTraceTime(Info, gc, phases, verify) tm("Verify After", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -95,7 +85,7 @@ bool VM_CMS_Operation::doit_prologue() { assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), "Possible deadlock"); - if (needs_pll()) { + if (needs_pending_list_lock()) { acquire_pending_list_lock(); } // Get the Heap_lock after the pending_list_lock. @@ -103,7 +93,7 @@ bool VM_CMS_Operation::doit_prologue() { if (lost_race()) { assert(_prologue_succeeded == false, "Initialized in c'tor"); Heap_lock->unlock(); - if (needs_pll()) { + if (needs_pending_list_lock()) { release_and_notify_pending_list_lock(); } } else { @@ -120,7 +110,7 @@ void VM_CMS_Operation::doit_epilogue() { // Release the Heap_lock first. Heap_lock->unlock(); - if (needs_pll()) { + if (needs_pending_list_lock()) { release_and_notify_pending_list_lock(); } } diff --git a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp index dc262c25b7b..e6fe2c2ac25 100644 --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcId.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/vmGCOperations.hpp" #include "runtime/vm_operations.hpp" @@ -51,6 +52,9 @@ class CMSCollector; class VM_CMS_Operation: public VM_Operation { + private: + ReferencePendingListLocker _pending_list_locker; + protected: CMSCollector* _collector; // associated collector bool _prologue_succeeded; // whether doit_prologue succeeded @@ -73,7 +77,7 @@ class VM_CMS_Operation: public VM_Operation { virtual const CMSCollector::CollectorState legal_state() const = 0; // Whether the pending list lock needs to be held - virtual const bool needs_pll() const = 0; + virtual const bool needs_pending_list_lock() const = 0; // Execute operations in the context of the caller, // prior to execution of the vm operation itself. @@ -105,7 +109,7 @@ class VM_CMS_Initial_Mark: public VM_CMS_Operation { return CMSCollector::InitialMarking; } - virtual const bool needs_pll() const { + virtual const bool needs_pending_list_lock() const { return false; } }; @@ -122,7 +126,7 @@ class VM_CMS_Final_Remark: public VM_CMS_Operation { return CMSCollector::FinalMarking; } - virtual const bool needs_pll() const { + virtual const bool needs_pending_list_lock() const { return true; } }; diff --git a/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp b/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp index 0164b4c502c..e312d6b59db 100644 --- a/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp +++ b/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,14 +51,12 @@ declare_type(ConcurrentMarkSweepGeneration,CardGeneration) \ declare_type(CompactibleFreeListSpace, CompactibleSpace) \ declare_type(ConcurrentMarkSweepThread, NamedThread) \ - declare_type(SurrogateLockerThread, JavaThread) \ declare_toplevel_type(CMSCollector) \ declare_toplevel_type(CMSBitMap) \ declare_toplevel_type(FreeChunk) \ declare_toplevel_type(Metablock) \ declare_toplevel_type(ConcurrentMarkSweepThread*) \ declare_toplevel_type(ConcurrentMarkSweepGeneration*) \ - declare_toplevel_type(SurrogateLockerThread*) \ declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CMSCollector*) \ declare_toplevel_type(AFLBinaryTreeDictionary) \ diff --git a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp index fcc1f8e526f..caa45950f62 100644 --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,7 +145,6 @@ void CollectionSetChooser::sort_regions() { verify(); } - void CollectionSetChooser::add_region(HeapRegion* hr) { assert(!hr->is_pinned(), "Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index()); @@ -210,4 +209,67 @@ void CollectionSetChooser::clear() { _front = 0; _end = 0; _remaining_reclaimable_bytes = 0; +} + +class ParKnownGarbageHRClosure: public HeapRegionClosure { + G1CollectedHeap* _g1h; + CSetChooserParUpdater _cset_updater; + +public: + ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted, + uint chunk_size) : + _g1h(G1CollectedHeap::heap()), + _cset_updater(hrSorted, true /* parallel */, chunk_size) { } + + bool doHeapRegion(HeapRegion* r) { + // Do we have any marking information for this region? + if (r->is_marked()) { + // We will skip any region that's currently used as an old GC + // alloc region (we should not consider those for collection + // before we fill them up). + if (_cset_updater.should_add(r) && !_g1h->is_old_gc_alloc_region(r)) { + _cset_updater.add_region(r); + } + } + return false; + } }; + +class ParKnownGarbageTask: public AbstractGangTask { + CollectionSetChooser* _hrSorted; + uint _chunk_size; + G1CollectedHeap* _g1; + HeapRegionClaimer _hrclaimer; + +public: + ParKnownGarbageTask(CollectionSetChooser* hrSorted, uint chunk_size, uint n_workers) : + AbstractGangTask("ParKnownGarbageTask"), + _hrSorted(hrSorted), _chunk_size(chunk_size), + _g1(G1CollectedHeap::heap()), _hrclaimer(n_workers) {} + + void work(uint worker_id) { + ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size); + _g1->heap_region_par_iterate(&parKnownGarbageCl, worker_id, &_hrclaimer); + } +}; + +uint CollectionSetChooser::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const { + assert(n_workers > 0, "Active gc workers should be greater than 0"); + const uint overpartition_factor = 4; + const uint min_chunk_size = MAX2(n_regions / n_workers, 1U); + return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size); +} + +void CollectionSetChooser::rebuild(WorkGang* workers, uint n_regions) { + clear(); + + uint n_workers = workers->active_workers(); + + uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions); + prepare_for_par_region_addition(n_workers, n_regions, chunk_size); + + ParKnownGarbageTask par_known_garbage_task(this, chunk_size, n_workers); + workers->run_task(&par_known_garbage_task); + + sort_regions(); +} diff --git a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp index e24e58ae4c8..ae3f3a6381b 100644 --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,9 @@ class CollectionSetChooser: public CHeapObj { // The sum of reclaimable bytes over all the regions in the CSet chooser. size_t _remaining_reclaimable_bytes; + // Calculate and return chunk size (in number of regions) for parallel + // addition of regions + uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const; public: // Return the current candidate region to be considered for @@ -132,6 +135,8 @@ public: void clear(); + void rebuild(WorkGang* workers, uint n_regions); + // Return the number of candidate regions that remain to be collected. uint remaining_regions() { return _end - _front; } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp index 5edec2775ed..3a4d5ede251 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp @@ -27,11 +27,13 @@ #include "gc/g1/concurrentG1RefineThread.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HotCardCache.hpp" +#include "gc/g1/g1Predictions.hpp" #include "runtime/java.hpp" -ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : +ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h, const G1Predictions* predictor) : _threads(NULL), _sample_thread(NULL), + _predictor_sigma(predictor->sigma()), _hot_card_cache(g1h) { // Ergonomically select initial concurrent refinement parameters @@ -49,10 +51,12 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2); } set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); + } ConcurrentG1Refine* ConcurrentG1Refine::create(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure, jint* ecode) { - ConcurrentG1Refine* cg1r = new ConcurrentG1Refine(g1h); + G1CollectorPolicy* policy = g1h->g1_policy(); + ConcurrentG1Refine* cg1r = new ConcurrentG1Refine(g1h, &policy->predictor()); if (cg1r == NULL) { *ecode = JNI_ENOMEM; vm_shutdown_during_initialization("Could not create ConcurrentG1Refine"); @@ -155,3 +159,43 @@ void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const { _sample_thread->print_on(st); st->cr(); } + +void ConcurrentG1Refine::adjust(double update_rs_time, + double update_rs_processed_buffers, + double goal_ms) { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + + if (G1UseAdaptiveConcRefinement) { + const int k_gy = 3, k_gr = 6; + const double inc_k = 1.1, dec_k = 0.9; + + size_t g = green_zone(); + if (update_rs_time > goal_ms) { + g = (size_t)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. + } else { + if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { + g = (size_t)MAX2(g * inc_k, g + 1.0); + } + } + // Change the refinement threads params + set_green_zone(g); + set_yellow_zone(g * k_gy); + set_red_zone(g * k_gr); + reinitialize_threads(); + + size_t processing_threshold_delta = MAX2(green_zone() * _predictor_sigma, 1); + size_t processing_threshold = MIN2(green_zone() + processing_threshold_delta, + yellow_zone()); + // Change the barrier params + dcqs.set_process_completed_threshold((int)processing_threshold); + dcqs.set_max_completed_queue((int)red_zone()); + } + + size_t curr_queue_size = dcqs.completed_buffers_num(); + if (curr_queue_size >= yellow_zone()) { + dcqs.set_completed_queue_padding(curr_queue_size); + } else { + dcqs.set_completed_queue_padding(0); + } + dcqs.notify_if_necessary(); +} diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp index 2333fea311f..3161f62f2b2 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp @@ -35,6 +35,7 @@ class ConcurrentG1RefineThread; class G1CollectedHeap; class G1HotCardCache; +class G1Predictions; class G1RegionToSpaceMapper; class G1RemSet; class DirtyCardQueue; @@ -67,13 +68,15 @@ class ConcurrentG1Refine: public CHeapObj { size_t _thread_threshold_step; + double _predictor_sigma; + // We delay the refinement of 'hot' cards using the hot card cache. G1HotCardCache _hot_card_cache; // Reset the threshold step value based of the current zone boundaries. void reset_threshold_step(); - ConcurrentG1Refine(G1CollectedHeap* g1h); + ConcurrentG1Refine(G1CollectedHeap* g1h, const G1Predictions* predictions); public: ~ConcurrentG1Refine(); @@ -85,6 +88,8 @@ class ConcurrentG1Refine: public CHeapObj { void init(G1RegionToSpaceMapper* card_counts_storage); void stop(); + void adjust(double update_rs_time, double update_rs_processed_buffers, double goal_ms); + void reinitialize_threads(); // Iterate over all concurrent refinement threads diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index 778b37f058e..78bea91e71b 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -76,9 +76,8 @@ void ConcurrentG1RefineThread::initialize() { } void ConcurrentG1RefineThread::wait_for_completed_buffers() { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); - while (!_should_terminate && !is_active()) { + while (!should_terminate() && !is_active()) { _monitor->wait(Mutex::_no_safepoint_check_flag); } } @@ -109,22 +108,13 @@ void ConcurrentG1RefineThread::deactivate() { } } -void ConcurrentG1RefineThread::run() { - initialize_in_thread(); - wait_for_universe_init(); - - run_service(); - - terminate(); -} - void ConcurrentG1RefineThread::run_service() { _vtime_start = os::elapsedVTime(); - while (!_should_terminate) { + while (!should_terminate()) { // Wait for work wait_for_completed_buffers(); - if (_should_terminate) { + if (should_terminate()) { break; } @@ -135,7 +125,12 @@ void ConcurrentG1RefineThread::run_service() { { SuspendibleThreadSetJoiner sts_join; - do { + while (!should_terminate()) { + if (sts_join.should_yield()) { + sts_join.yield(); + continue; // Re-check for termination after yield delay. + } + size_t curr_buffer_num = dcqs.completed_buffers_num(); // If the number of the buffers falls down into the yellow zone, // that means that the transition period after the evacuation pause has ended. @@ -147,17 +142,23 @@ void ConcurrentG1RefineThread::run_service() { if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) { _next->activate(); } - } while (dcqs.apply_closure_to_completed_buffer(_refine_closure, - _worker_id + _worker_id_offset, - _deactivation_threshold, - false /* during_pause */)); - deactivate(); - log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, - _worker_id, _deactivation_threshold, - dcqs.completed_buffers_num()); + // Process the next buffer, if there are enough left. + if (!dcqs.apply_closure_to_completed_buffer(_refine_closure, + _worker_id + _worker_id_offset, + _deactivation_threshold, + false /* during_pause */)) { + break; // Deactivate, number of buffers fell below threshold. + } + } } + deactivate(); + log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT + ", current: " SIZE_FORMAT, + _worker_id, _deactivation_threshold, + dcqs.completed_buffers_num()); + if (os::supports_vtime()) { _vtime_accum = (os::elapsedVTime() - _vtime_start); } else { @@ -168,23 +169,6 @@ void ConcurrentG1RefineThread::run_service() { log_debug(gc, refine)("Stopping %d", _worker_id); } -void ConcurrentG1RefineThread::stop() { - // it is ok to take late safepoints here, if needed - { - MutexLockerEx mu(Terminator_lock); - _should_terminate = true; - } - - stop_service(); - - { - MutexLockerEx mu(Terminator_lock); - while (!_has_terminated) { - Terminator_lock->wait(); - } - } -} - void ConcurrentG1RefineThread::stop_service() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); _monitor->notify(); diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp index 40071766d6f..9f325599cfc 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp @@ -72,7 +72,6 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { void stop_service(); public: - virtual void run(); // Constructor ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next, CardTableEntryClosure* refine_closure, @@ -84,9 +83,6 @@ public: double vtime_accum() { return _vtime_accum; } ConcurrentG1Refine* cg1r() { return _cg1r; } - - // shutdown - void stop(); }; #endif // SHARE_VM_GC_G1_CONCURRENTG1REFINETHREAD_HPP diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp index 0374f951615..c72cbae1474 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "gc/g1/concurrentMarkThread.inline.hpp" +#include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1MMUTracker.hpp" @@ -41,9 +42,6 @@ // The CM thread is created when the G1 garbage collector is used -SurrogateLockerThread* - ConcurrentMarkThread::_slt = NULL; - ConcurrentMarkThread::ConcurrentMarkThread(G1ConcurrentMark* cm) : ConcurrentGCThread(), _cm(cm), @@ -82,60 +80,59 @@ public: // Marking pauses can be scheduled flexibly, so we might delay marking to meet MMU. void ConcurrentMarkThread::delay_to_keep_mmu(G1CollectorPolicy* g1_policy, bool remark) { + const G1Analytics* analytics = g1_policy->analytics(); if (g1_policy->adaptive_young_list_length()) { double now = os::elapsedTime(); - double prediction_ms = remark ? g1_policy->predict_remark_time_ms() - : g1_policy->predict_cleanup_time_ms(); + double prediction_ms = remark ? analytics->predict_remark_time_ms() + : analytics->predict_cleanup_time_ms(); G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker(); jlong sleep_time_ms = mmu_tracker->when_ms(now, prediction_ms); os::sleep(this, sleep_time_ms, false); } } -class GCConcPhaseTimer : StackObj { +class G1ConcPhaseTimer : public GCTraceConcTimeImpl { G1ConcurrentMark* _cm; public: - GCConcPhaseTimer(G1ConcurrentMark* cm, const char* title) : _cm(cm) { - _cm->register_concurrent_phase_start(title); + G1ConcPhaseTimer(G1ConcurrentMark* cm, const char* title) : + GCTraceConcTimeImpl(title), + _cm(cm) { + _cm->gc_timer_cm()->register_gc_concurrent_start(title); } - ~GCConcPhaseTimer() { - _cm->register_concurrent_phase_end(); + ~G1ConcPhaseTimer() { + _cm->gc_timer_cm()->register_gc_concurrent_end(); } }; -void ConcurrentMarkThread::run() { - initialize_in_thread(); - wait_for_universe_init(); - - run_service(); - - terminate(); -} - void ConcurrentMarkThread::run_service() { _vtime_start = os::elapsedVTime(); G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1_policy = g1h->g1_policy(); - while (!_should_terminate) { + while (!should_terminate()) { // wait until started is set. sleepBeforeNextCycle(); - if (_should_terminate) { - _cm->root_regions()->cancel_scan(); + if (should_terminate()) { break; } + GCIdMark gc_id_mark; + + cm()->concurrent_cycle_start(); + assert(GCId::current() != GCId::undefined(), "GC id should have been set up by the initial mark GC."); + + GCTraceConcTime(Info, gc) tt("Concurrent Cycle"); { ResourceMark rm; HandleMark hm; double cycle_start = os::elapsedVTime(); { - GCConcPhaseTimer(_cm, "Concurrent Clearing of Claimed Marks"); + G1ConcPhaseTimer t(_cm, "Concurrent Clear Claimed Marks"); ClassLoaderDataGraph::clear_claimed_marks(); } @@ -148,22 +145,22 @@ void ConcurrentMarkThread::run_service() { // correctness issue. { - GCConcPhaseTimer(_cm, "Concurrent Root Region Scanning"); - _cm->scanRootRegions(); + G1ConcPhaseTimer t(_cm, "Concurrent Scan Root Regions"); + _cm->scan_root_regions(); } // It would be nice to use the GCTraceConcTime class here but // the "end" logging is inside the loop and not at the end of // a scope. Mimicking the same log output as GCTraceConcTime instead. jlong mark_start = os::elapsed_counter(); - log_info(gc)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start)); + log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start)); int iter = 0; do { iter++; if (!cm()->has_aborted()) { - GCConcPhaseTimer(_cm, "Concurrent Mark"); - _cm->markFromRoots(); + G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots"); + _cm->mark_from_roots(); } double mark_end_time = os::elapsedVTime(); @@ -171,18 +168,18 @@ void ConcurrentMarkThread::run_service() { _vtime_mark_accum += (mark_end_time - cycle_start); if (!cm()->has_aborted()) { delay_to_keep_mmu(g1_policy, true /* remark */); - log_info(gc)("Concurrent Mark (%.3fs, %.3fs) %.3fms", - TimeHelper::counter_to_seconds(mark_start), - TimeHelper::counter_to_seconds(mark_end), - TimeHelper::counter_to_millis(mark_end - mark_start)); + log_info(gc, marking)("Concurrent Mark (%.3fs, %.3fs) %.3fms", + TimeHelper::counter_to_seconds(mark_start), + TimeHelper::counter_to_seconds(mark_end), + TimeHelper::counter_to_millis(mark_end - mark_start)); CMCheckpointRootsFinalClosure final_cl(_cm); VM_CGC_Operation op(&final_cl, "Pause Remark", true /* needs_pll */); VMThread::execute(&op); } if (cm()->restart_for_overflow()) { - log_debug(gc)("Restarting conc marking because of MS overflow in remark (restart #%d).", iter); - log_info(gc)("Concurrent Mark restart for overflow"); + log_debug(gc, marking)("Restarting Concurrent Marking because of Mark Stack Overflow in Remark (Iteration #%d).", iter); + log_info(gc, marking)("Concurrent Mark Restart due to overflow"); } } while (cm()->restart_for_overflow()); @@ -216,11 +213,9 @@ void ConcurrentMarkThread::run_service() { // place, it would wait for us to process the regions // reclaimed by cleanup. - GCTraceConcTime(Info, gc) tt("Concurrent Cleanup"); - GCConcPhaseTimer(_cm, "Concurrent Cleanup"); - + G1ConcPhaseTimer t(_cm, "Concurrent Complete Cleanup"); // Now do the concurrent cleanup operation. - _cm->completeCleanup(); + _cm->complete_cleanup(); // Notify anyone who's waiting that there are no more free // regions coming. We have to do this before we join the STS @@ -265,7 +260,7 @@ void ConcurrentMarkThread::run_service() { if (!cm()->has_aborted()) { g1_policy->record_concurrent_mark_cleanup_completed(); } else { - log_info(gc)("Concurrent Mark abort"); + log_info(gc, marking)("Concurrent Mark Abort"); } } @@ -274,8 +269,8 @@ void ConcurrentMarkThread::run_service() { // We may have aborted just before the remark. Do not bother clearing the // bitmap then, as it has been done during mark abort. if (!cm()->has_aborted()) { - GCConcPhaseTimer(_cm, "Concurrent Bitmap Clearing"); - _cm->clearNextBitmap(); + G1ConcPhaseTimer t(_cm, "Concurrent Cleanup for Next Mark"); + _cm->cleanup_for_next_mark(); } else { assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear"); } @@ -288,25 +283,11 @@ void ConcurrentMarkThread::run_service() { { SuspendibleThreadSetJoiner sts_join; g1h->increment_old_marking_cycles_completed(true /* concurrent */); - g1h->register_concurrent_cycle_end(); - } - } -} - -void ConcurrentMarkThread::stop() { - { - MutexLockerEx ml(Terminator_lock); - _should_terminate = true; - } - - stop_service(); - - { - MutexLockerEx ml(Terminator_lock); - while (!_has_terminated) { - Terminator_lock->wait(); + + cm()->concurrent_cycle_end(); } } + _cm->root_regions()->cancel_scan(); } void ConcurrentMarkThread::stop_service() { @@ -320,7 +301,7 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { assert(!in_progress(), "should have been cleared"); MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - while (!started() && !_should_terminate) { + while (!started() && !should_terminate()) { CGC_lock->wait(Mutex::_no_safepoint_check_flag); } @@ -328,16 +309,3 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { set_in_progress(); } } - -// Note: As is the case with CMS - this method, although exported -// by the ConcurrentMarkThread, which is a non-JavaThread, can only -// be called by a JavaThread. Currently this is done at vm creation -// time (post-vm-init) by the main/Primordial (Java)Thread. -// XXX Consider changing this in the future to allow the CM thread -// itself to create this thread? -void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) { - assert(UseG1GC, "SLT thread needed only for concurrent GC"); - assert(THREAD->is_Java_thread(), "must be a Java thread"); - assert(_slt == NULL, "SLT already created"); - _slt = SurrogateLockerThread::make(THREAD); -} diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp index c75280b8eb3..2bdd7f3116d 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp @@ -38,13 +38,8 @@ class ConcurrentMarkThread: public ConcurrentGCThread { double _vtime_start; // Initial virtual time. double _vtime_accum; // Accumulated virtual time. - double _vtime_mark_accum; - public: - virtual void run(); - - private: G1ConcurrentMark* _cm; enum State { @@ -61,15 +56,10 @@ class ConcurrentMarkThread: public ConcurrentGCThread { void run_service(); void stop_service(); - static SurrogateLockerThread* _slt; - public: // Constructor ConcurrentMarkThread(G1ConcurrentMark* cm); - static void makeSurrogateLockerThread(TRAPS); - static SurrogateLockerThread* slt() { return _slt; } - // Total virtual time so far for this thread and concurrent marking tasks. double vtime_accum(); // Marking virtual time so far this thread and concurrent marking tasks. @@ -93,9 +83,6 @@ class ConcurrentMarkThread: public ConcurrentGCThread { // as the CM thread might take some time to wake up before noticing // that started() is set and set in_progress(). bool during_cycle() { return !idle(); } - - // shutdown - void stop(); }; #endif // SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_HPP diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index d79ac8066b9..f95c29a039e 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -110,44 +110,6 @@ DirtyCardQueue::~DirtyCardQueue() { } } -bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl, - bool consume, - uint worker_i) { - bool res = true; - if (_buf != NULL) { - res = apply_closure_to_buffer(cl, _buf, _index, _sz, - consume, - worker_i); - if (res && consume) { - _index = _sz; - } - } - return res; -} - -bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl, - void** buf, - size_t index, size_t sz, - bool consume, - uint worker_i) { - if (cl == NULL) return true; - size_t limit = byte_index_to_index(sz); - for (size_t i = byte_index_to_index(index); i < limit; ++i) { - jbyte* card_ptr = static_cast(buf[i]); - if (card_ptr != NULL) { - // Set the entry to null, so we don't do it again (via the test - // above) if we reconsider this buffer. - if (consume) { - buf[i] = NULL; - } - if (!cl->do_card_ptr(card_ptr, worker_i)) { - return false; - } - } - } - return true; -} - DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) : PtrQueueSet(notify_when_complete), _mut_process_closure(NULL), @@ -188,22 +150,57 @@ void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { t->dirty_card_queue().handle_zero_index(); } -bool DirtyCardQueueSet::mut_process_buffer(void** buf) { +bool DirtyCardQueueSet::apply_closure_to_buffer(CardTableEntryClosure* cl, + BufferNode* node, + bool consume, + uint worker_i) { + if (cl == NULL) return true; + bool result = true; + void** buf = BufferNode::make_buffer_from_node(node); + size_t limit = DirtyCardQueue::byte_index_to_index(buffer_size()); + size_t i = DirtyCardQueue::byte_index_to_index(node->index()); + for ( ; i < limit; ++i) { + jbyte* card_ptr = static_cast(buf[i]); + assert(card_ptr != NULL, "invariant"); + if (!cl->do_card_ptr(card_ptr, worker_i)) { + result = false; // Incomplete processing. + break; + } + } + if (consume) { + size_t new_index = DirtyCardQueue::index_to_byte_index(i); + assert(new_index <= buffer_size(), "invariant"); + node->set_index(new_index); + } + return result; +} + +#ifndef ASSERT +#define assert_fully_consumed(node, buffer_size) +#else +#define assert_fully_consumed(node, buffer_size) \ + do { \ + size_t _afc_index = (node)->index(); \ + size_t _afc_size = (buffer_size); \ + assert(_afc_index == _afc_size, \ + "Buffer was not fully consumed as claimed: index: " \ + SIZE_FORMAT ", size: " SIZE_FORMAT, \ + _afc_index, _afc_size); \ + } while (0) +#endif // ASSERT + +bool DirtyCardQueueSet::mut_process_buffer(BufferNode* node) { guarantee(_free_ids != NULL, "must be"); - // claim a par id - uint worker_i = _free_ids->claim_par_id(); + uint worker_i = _free_ids->claim_par_id(); // temporarily claim an id + bool result = apply_closure_to_buffer(_mut_process_closure, node, true, worker_i); + _free_ids->release_par_id(worker_i); // release the id - bool b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0, - _sz, true, worker_i); - if (b) { + if (result) { + assert_fully_consumed(node, buffer_size()); Atomic::inc(&_processed_buffers_mut); } - - // release the id - _free_ids->release_par_id(worker_i); - - return b; + return result; } @@ -239,49 +236,31 @@ bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* if (nd == NULL) { return false; } else { - void** buf = BufferNode::make_buffer_from_node(nd); - size_t index = nd->index(); - if (DirtyCardQueue::apply_closure_to_buffer(cl, - buf, index, _sz, - true, worker_i)) { + if (apply_closure_to_buffer(cl, nd, true, worker_i)) { + assert_fully_consumed(nd, buffer_size()); // Done with fully processed buffer. - deallocate_buffer(buf); + deallocate_buffer(nd); Atomic::inc(&_processed_buffers_rs_thread); - return true; } else { // Return partially processed buffer to the queue. - enqueue_complete_buffer(buf, index); - return false; + guarantee(!during_pause, "Should never stop early"); + enqueue_complete_buffer(nd); } - } -} - -void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) { - BufferNode* nd = _completed_buffers_head; - while (nd != NULL) { - bool b = - DirtyCardQueue::apply_closure_to_buffer(cl, - BufferNode::make_buffer_from_node(nd), - 0, _sz, false); - guarantee(b, "Should not stop early."); - nd = nd->next(); + return true; } } void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) { BufferNode* nd = _cur_par_buffer_node; while (nd != NULL) { - BufferNode* next = (BufferNode*)nd->next(); - BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd); + BufferNode* next = nd->next(); + void* actual = Atomic::cmpxchg_ptr(next, &_cur_par_buffer_node, nd); if (actual == nd) { - bool b = - DirtyCardQueue::apply_closure_to_buffer(cl, - BufferNode::make_buffer_from_node(actual), - 0, _sz, false); + bool b = apply_closure_to_buffer(cl, nd, false); guarantee(b, "Should not stop early."); nd = next; } else { - nd = actual; + nd = static_cast(actual); } } } @@ -304,7 +283,7 @@ void DirtyCardQueueSet::clear() { while (buffers_to_delete != NULL) { BufferNode* nd = buffers_to_delete; buffers_to_delete = nd->next(); - deallocate_buffer(BufferNode::make_buffer_from_node(nd)); + deallocate_buffer(nd); } } @@ -320,6 +299,13 @@ void DirtyCardQueueSet::abandon_logs() { shared_dirty_card_queue()->reset(); } +void DirtyCardQueueSet::concatenate_log(DirtyCardQueue& dcq) { + if (!dcq.is_empty()) { + enqueue_complete_buffer( + BufferNode::make_node_from_buffer(dcq.get_buf(), dcq.get_index())); + dcq.reinitialize(); + } +} void DirtyCardQueueSet::concatenate_logs() { // Iterate over all the threads, if we find a partial log add it to @@ -329,23 +315,9 @@ void DirtyCardQueueSet::concatenate_logs() { _max_completed_queue = max_jint; assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); for (JavaThread* t = Threads::first(); t; t = t->next()) { - DirtyCardQueue& dcq = t->dirty_card_queue(); - if (dcq.size() != 0) { - void** buf = dcq.get_buf(); - // We must NULL out the unused entries, then enqueue. - size_t limit = dcq.byte_index_to_index(dcq.get_index()); - for (size_t i = 0; i < limit; ++i) { - buf[i] = NULL; - } - enqueue_complete_buffer(dcq.get_buf(), dcq.get_index()); - dcq.reinitialize(); - } - } - if (_shared_dirty_card_queue.size() != 0) { - enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(), - _shared_dirty_card_queue.get_index()); - _shared_dirty_card_queue.reinitialize(); + concatenate_log(t->dirty_card_queue()); } + concatenate_log(_shared_dirty_card_queue); // Restore the completed buffer queue limit. _max_completed_queue = save_max_completed_queue; } diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 96865a5784b..faaa1bd9d0a 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -37,7 +37,7 @@ class CardTableEntryClosure: public CHeapObj { public: // Process the card whose card table entry is "card_ptr". If returns // "false", terminate the iteration early. - virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i = 0) = 0; + virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i) = 0; }; // A ptrQueue whose elements are "oops", pointers to object heads. @@ -52,23 +52,6 @@ public: // Process queue entries and release resources. void flush() { flush_impl(); } - // Apply the closure to all elements, and reset the index to make the - // buffer empty. If a closure application returns "false", return - // "false" immediately, halting the iteration. If "consume" is true, - // deletes processed entries from logs. - bool apply_closure(CardTableEntryClosure* cl, - bool consume = true, - uint worker_i = 0); - - // Apply the closure to all elements of "buf", down to "index" - // (inclusive.) If returns "false", then a closure application returned - // "false", and we return immediately. If "consume" is true, entries are - // set to NULL as they are processed, so they will not be processed again - // later. - static bool apply_closure_to_buffer(CardTableEntryClosure* cl, - void** buf, size_t index, size_t sz, - bool consume = true, - uint worker_i = 0); void **get_buf() { return _buf;} size_t get_index() { return _index;} void reinitialize() { _buf = 0; _sz = 0; _index = 0;} @@ -94,8 +77,19 @@ class DirtyCardQueueSet: public PtrQueueSet { DirtyCardQueue _shared_dirty_card_queue; - // Override. - bool mut_process_buffer(void** buf); + // Apply the closure to the elements of "node" from it's index to + // buffer_size. If all closure applications return true, then + // returns true. Stops processing after the first closure + // application that returns false, and returns false from this + // function. If "consume" is true, the node's index is updated to + // exclude the processed elements, e.g. up to the element for which + // the closure returned false. + bool apply_closure_to_buffer(CardTableEntryClosure* cl, + BufferNode* node, + bool consume, + uint worker_i = 0); + + bool mut_process_buffer(BufferNode* node); // Protected by the _cbl_mon. FreeIdSet* _free_ids; @@ -107,6 +101,9 @@ class DirtyCardQueueSet: public PtrQueueSet { // Current buffer node used for parallel iteration. BufferNode* volatile _cur_par_buffer_node; + + void concatenate_log(DirtyCardQueue& dcq); + public: DirtyCardQueueSet(bool notify_when_complete = true); @@ -125,13 +122,18 @@ public: static void handle_zero_index_for_thread(JavaThread* t); - // If there exists some completed buffer, pop it, then apply the - // specified closure to all its elements, nulling out those elements - // processed. If all elements are processed, returns "true". If no - // completed buffers exist, returns false. If a completed buffer exists, - // but is only partially completed before a "yield" happens, the - // partially completed buffer (with its processed elements set to NULL) - // is returned to the completed buffer set, and this call returns false. + // If there are more than stop_at completed buffers, pop one, apply + // the specified closure to its active elements, and return true. + // Otherwise return false. + // + // A completely processed buffer is freed. However, if a closure + // invocation returns false, processing is stopped and the partially + // processed buffer (with its index updated to exclude the processed + // elements, e.g. up to the element for which the closure returned + // false) is returned to the completed buffer set. + // + // If during_pause is true, stop_at must be zero, and the closure + // must never return false. bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, size_t stop_at, @@ -139,13 +141,10 @@ public: BufferNode* get_completed_buffer(size_t stop_at); - // Applies the current closure to all completed buffers, - // non-consumptively. - void apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl); - void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; } // Applies the current closure to all completed buffers, non-consumptively. - // Parallel version. + // Can be used in parallel, all callers using the iteration state initialized + // by reset_for_par_iteration. void par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl); DirtyCardQueue* shared_dirty_card_queue() { diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp index f08cd59a059..0e5320413d9 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp @@ -26,6 +26,7 @@ #include "gc/g1/g1AllocRegion.inline.hpp" #include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "memory/resourceArea.hpp" #include "runtime/orderAccess.inline.hpp" G1CollectedHeap* G1AllocRegion::_g1h = NULL; @@ -194,44 +195,53 @@ HeapRegion* G1AllocRegion::release() { return (alloc_region == _dummy_region) ? NULL : alloc_region; } -#if G1_ALLOC_REGION_TRACING +#ifndef PRODUCT void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_word_size, size_t actual_word_size, HeapWord* result) { // All the calls to trace that set either just the size or the size - // and the result are considered part of level 2 tracing and are - // skipped during level 1 tracing. - if ((actual_word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) { - const size_t buffer_length = 128; - char hr_buffer[buffer_length]; - char rest_buffer[buffer_length]; + // and the result are considered part of detailed tracing and are + // skipped during other tracing. - HeapRegion* alloc_region = _alloc_region; - if (alloc_region == NULL) { - jio_snprintf(hr_buffer, buffer_length, "NULL"); - } else if (alloc_region == _dummy_region) { - jio_snprintf(hr_buffer, buffer_length, "DUMMY"); + Log(gc, alloc, region) log; + + if (!log.is_debug()) { + return; + } + + bool detailed_info = log.is_trace(); + + if ((actual_word_size == 0 && result == NULL) || detailed_info) { + ResourceMark rm; + outputStream* out; + if (detailed_info) { + out = log.trace_stream(); } else { - jio_snprintf(hr_buffer, buffer_length, - HR_FORMAT, HR_FORMAT_PARAMS(alloc_region)); + out = log.debug_stream(); } - if (G1_ALLOC_REGION_TRACING > 1) { + out->print("%s: %u ", _name, _count); + + if (_alloc_region == NULL) { + out->print("NULL"); + } else if (_alloc_region == _dummy_region) { + out->print("DUMMY"); + } else { + out->print(HR_FORMAT, HR_FORMAT_PARAMS(_alloc_region)); + } + + out->print(" : %s", str); + + if (detailed_info) { if (result != NULL) { - jio_snprintf(rest_buffer, buffer_length, "min " SIZE_FORMAT " desired " SIZE_FORMAT " actual " SIZE_FORMAT " " PTR_FORMAT, - min_word_size, desired_word_size, actual_word_size, result); + out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT " actual " SIZE_FORMAT " " PTR_FORMAT, + min_word_size, desired_word_size, actual_word_size, p2i(result)); } else if (min_word_size != 0) { - jio_snprintf(rest_buffer, buffer_length, "min " SIZE_FORMAT " desired " SIZE_FORMAT, min_word_size, desired_word_size); - } else { - jio_snprintf(rest_buffer, buffer_length, ""); + out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT, min_word_size, desired_word_size); } - } else { - jio_snprintf(rest_buffer, buffer_length, ""); } - - tty->print_cr("[%s] %u %s : %s %s", - _name, _count, hr_buffer, str, rest_buffer); + out->cr(); } } -#endif // G1_ALLOC_REGION_TRACING +#endif // PRODUCT G1AllocRegion::G1AllocRegion(const char* name, bool bot_updates) @@ -253,7 +263,7 @@ void MutatorAllocRegion::retire_region(HeapRegion* alloc_region, HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size, bool force) { assert(!force, "not supported for GC alloc regions"); - return _g1h->new_gc_alloc_region(word_size, count(), _purpose); + return _g1h->new_gc_alloc_region(word_size, _purpose); } void G1GCAllocRegion::retire_region(HeapRegion* alloc_region, diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp index 9feb295af4a..afcb2a340c8 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp @@ -31,9 +31,6 @@ class G1CollectedHeap; -// 0 -> no tracing, 1 -> basic tracing, 2 -> basic + allocation tracing -#define G1_ALLOC_REGION_TRACING 0 - // A class that holds a region that is active in satisfying allocation // requests, potentially issued in parallel. When the active region is // full it will be retired and replaced with a new one. The @@ -213,19 +210,11 @@ public: // is returned after it's been retired. virtual HeapRegion* release(); -#if G1_ALLOC_REGION_TRACING void trace(const char* str, size_t min_word_size = 0, size_t desired_word_size = 0, size_t actual_word_size = 0, - HeapWord* result = NULL); -#else // G1_ALLOC_REGION_TRACING - void trace(const char* str, - size_t min_word_size = 0, - size_t desired_word_size = 0, - size_t actual_word_size = 0, - HeapWord* result = NULL) { } -#endif // G1_ALLOC_REGION_TRACING + HeapWord* result = NULL) PRODUCT_RETURN; }; class MutatorAllocRegion : public G1AllocRegion { diff --git a/hotspot/src/share/vm/gc/g1/g1Analytics.cpp b/hotspot/src/share/vm/gc/g1/g1Analytics.cpp new file mode 100644 index 00000000000..16d4af949ce --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1Analytics.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1Analytics.hpp" +#include "gc/g1/g1Predictions.hpp" +#include "runtime/os.hpp" +#include "utilities/debug.hpp" +#include "utilities/numberSeq.hpp" + +// Different defaults for different number of GC threads +// They were chosen by running GCOld and SPECjbb on debris with different +// numbers of GC threads and choosing them based on the results + +// all the same +static double rs_length_diff_defaults[] = { + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 +}; + +static double cost_per_card_ms_defaults[] = { + 0.01, 0.005, 0.005, 0.003, 0.003, 0.002, 0.002, 0.0015 +}; + +// all the same +static double young_cards_per_entry_ratio_defaults[] = { + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 +}; + +static double cost_per_entry_ms_defaults[] = { + 0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005 +}; + +static double cost_per_byte_ms_defaults[] = { + 0.00006, 0.00003, 0.00003, 0.000015, 0.000015, 0.00001, 0.00001, 0.000009 +}; + +// these should be pretty consistent +static double constant_other_time_ms_defaults[] = { + 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0 +}; + + +static double young_other_cost_per_region_ms_defaults[] = { + 0.3, 0.2, 0.2, 0.15, 0.15, 0.12, 0.12, 0.1 +}; + +static double non_young_other_cost_per_region_ms_defaults[] = { + 1.0, 0.7, 0.7, 0.5, 0.5, 0.42, 0.42, 0.30 +}; + +G1Analytics::G1Analytics(const G1Predictions* predictor) : + _predictor(predictor), + _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), + _concurrent_mark_remark_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), + _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), + _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _prev_collection_pause_end_ms(0.0), + _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)), + _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_per_byte_ms_during_cm_seq(new TruncatedSeq(TruncatedSeqLength)), + _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _non_young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _pending_cards_seq(new TruncatedSeq(TruncatedSeqLength)), + _rs_lengths_seq(new TruncatedSeq(TruncatedSeqLength)), + _recent_prev_end_times_for_all_gcs_sec(new TruncatedSeq(NumPrevPausesForHeuristics)) { + + // Seed sequences with initial values. + _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime()); + _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0; + + int index = MIN2(ParallelGCThreads - 1, 7u); + + _rs_length_diff_seq->add(rs_length_diff_defaults[index]); + _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]); + _cost_scan_hcc_seq->add(0.0); + _young_cards_per_entry_ratio_seq->add(young_cards_per_entry_ratio_defaults[index]); + _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]); + _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]); + _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]); + _young_other_cost_per_region_ms_seq->add(young_other_cost_per_region_ms_defaults[index]); + _non_young_other_cost_per_region_ms_seq->add(non_young_other_cost_per_region_ms_defaults[index]); + + // start conservatively (around 50ms is about right) + _concurrent_mark_remark_times_ms->add(0.05); + _concurrent_mark_cleanup_times_ms->add(0.20); +} + +double G1Analytics::get_new_prediction(TruncatedSeq const* seq) const { + return _predictor->get_new_prediction(seq); +} + +size_t G1Analytics::get_new_size_prediction(TruncatedSeq const* seq) const { + return (size_t)get_new_prediction(seq); +} + +int G1Analytics::num_alloc_rate_ms() const { + return _alloc_rate_ms_seq->num(); +} + +void G1Analytics::report_concurrent_mark_remark_times_ms(double ms) { + _concurrent_mark_remark_times_ms->add(ms); +} + +void G1Analytics::report_alloc_rate_ms(double alloc_rate) { + _alloc_rate_ms_seq->add(alloc_rate); +} + +void G1Analytics::compute_pause_time_ratio(double interval_ms, double pause_time_ms) { + _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum() / interval_ms; + if (_recent_avg_pause_time_ratio < 0.0 || + (_recent_avg_pause_time_ratio - 1.0 > 0.0)) { + // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in + // CR 6902692 by redoing the manner in which the ratio is incrementally computed. + if (_recent_avg_pause_time_ratio < 0.0) { + _recent_avg_pause_time_ratio = 0.0; + } else { + assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant"); + _recent_avg_pause_time_ratio = 1.0; + } + } + + // Compute the ratio of just this last pause time to the entire time range stored + // in the vectors. Comparing this pause to the entire range, rather than only the + // most recent interval, has the effect of smoothing over a possible transient 'burst' + // of more frequent pauses that don't really reflect a change in heap occupancy. + // This reduces the likelihood of a needless heap expansion being triggered. + _last_pause_time_ratio = + (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms; +} + +void G1Analytics::report_cost_per_card_ms(double cost_per_card_ms) { + _cost_per_card_ms_seq->add(cost_per_card_ms); +} + +void G1Analytics::report_cost_scan_hcc(double cost_scan_hcc) { + _cost_scan_hcc_seq->add(cost_scan_hcc); +} + +void G1Analytics::report_cost_per_entry_ms(double cost_per_entry_ms, bool last_gc_was_young) { + if (last_gc_was_young) { + _cost_per_entry_ms_seq->add(cost_per_entry_ms); + } else { + _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms); + } +} + +void G1Analytics::report_cards_per_entry_ratio(double cards_per_entry_ratio, bool last_gc_was_young) { + if (last_gc_was_young) { + _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + } else { + _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + } +} + +void G1Analytics::report_rs_length_diff(double rs_length_diff) { + _rs_length_diff_seq->add(rs_length_diff); +} + +void G1Analytics::report_cost_per_byte_ms(double cost_per_byte_ms, bool in_marking_window) { + if (in_marking_window) { + _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms); + } else { + _cost_per_byte_ms_seq->add(cost_per_byte_ms); + } +} + +void G1Analytics::report_young_other_cost_per_region_ms(double other_cost_per_region_ms) { + _young_other_cost_per_region_ms_seq->add(other_cost_per_region_ms); +} + +void G1Analytics::report_non_young_other_cost_per_region_ms(double other_cost_per_region_ms) { + _non_young_other_cost_per_region_ms_seq->add(other_cost_per_region_ms); +} + +void G1Analytics::report_constant_other_time_ms(double constant_other_time_ms) { + _constant_other_time_ms_seq->add(constant_other_time_ms); +} + +void G1Analytics::report_pending_cards(double pending_cards) { + _pending_cards_seq->add(pending_cards); +} + +void G1Analytics::report_rs_lengths(double rs_lengths) { + _rs_lengths_seq->add(rs_lengths); +} + +size_t G1Analytics::predict_rs_length_diff() const { + return get_new_size_prediction(_rs_length_diff_seq); +} + +double G1Analytics::predict_alloc_rate_ms() const { + return get_new_prediction(_alloc_rate_ms_seq); +} + +double G1Analytics::predict_cost_per_card_ms() const { + return get_new_prediction(_cost_per_card_ms_seq); +} + +double G1Analytics::predict_scan_hcc_ms() const { + return get_new_prediction(_cost_scan_hcc_seq); +} + +double G1Analytics::predict_rs_update_time_ms(size_t pending_cards) const { + return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms(); +} + +double G1Analytics::predict_young_cards_per_entry_ratio() const { + return get_new_prediction(_young_cards_per_entry_ratio_seq); +} + +double G1Analytics::predict_mixed_cards_per_entry_ratio() const { + if (_mixed_cards_per_entry_ratio_seq->num() < 2) { + return predict_young_cards_per_entry_ratio(); + } else { + return get_new_prediction(_mixed_cards_per_entry_ratio_seq); + } +} + +size_t G1Analytics::predict_card_num(size_t rs_length, bool gcs_are_young) const { + if (gcs_are_young) { + return (size_t) (rs_length * predict_young_cards_per_entry_ratio()); + } else { + return (size_t) (rs_length * predict_mixed_cards_per_entry_ratio()); + } +} + +double G1Analytics::predict_rs_scan_time_ms(size_t card_num, bool gcs_are_young) const { + if (gcs_are_young) { + return card_num * get_new_prediction(_cost_per_entry_ms_seq); + } else { + return predict_mixed_rs_scan_time_ms(card_num); + } +} + +double G1Analytics::predict_mixed_rs_scan_time_ms(size_t card_num) const { + if (_mixed_cost_per_entry_ms_seq->num() < 3) { + return card_num * get_new_prediction(_cost_per_entry_ms_seq); + } else { + return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq); + } +} + +double G1Analytics::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const { + if (_cost_per_byte_ms_during_cm_seq->num() < 3) { + return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq); + } else { + return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq); + } +} + +double G1Analytics::predict_object_copy_time_ms(size_t bytes_to_copy, bool during_concurrent_mark) const { + if (during_concurrent_mark) { + return predict_object_copy_time_ms_during_cm(bytes_to_copy); + } else { + return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq); + } +} + +double G1Analytics::predict_constant_other_time_ms() const { + return get_new_prediction(_constant_other_time_ms_seq); +} + +double G1Analytics::predict_young_other_time_ms(size_t young_num) const { + return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq); +} + +double G1Analytics::predict_non_young_other_time_ms(size_t non_young_num) const { + return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq); +} + +double G1Analytics::predict_remark_time_ms() const { + return get_new_prediction(_concurrent_mark_remark_times_ms); +} + +double G1Analytics::predict_cleanup_time_ms() const { + return get_new_prediction(_concurrent_mark_cleanup_times_ms); +} + +size_t G1Analytics::predict_rs_lengths() const { + return get_new_size_prediction(_rs_lengths_seq); +} + +size_t G1Analytics::predict_pending_cards() const { + return get_new_size_prediction(_pending_cards_seq); +} + +double G1Analytics::last_known_gc_end_time_sec() const { + return _recent_prev_end_times_for_all_gcs_sec->oldest(); +} + +void G1Analytics::update_recent_gc_times(double end_time_sec, + double pause_time_ms) { + _recent_gc_times_ms->add(pause_time_ms); + _recent_prev_end_times_for_all_gcs_sec->add(end_time_sec); + _prev_collection_pause_end_ms = end_time_sec * 1000.0; +} + +void G1Analytics::report_concurrent_mark_cleanup_times_ms(double ms) { + _concurrent_mark_cleanup_times_ms->add(ms); +} + diff --git a/hotspot/src/share/vm/gc/g1/g1Analytics.hpp b/hotspot/src/share/vm/gc/g1/g1Analytics.hpp new file mode 100644 index 00000000000..603a751c198 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1Analytics.hpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1MEASUREMENTS_HPP +#define SHARE_VM_GC_G1_G1MEASUREMENTS_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +class TruncatedSeq; +class G1Predictions; + +class G1Analytics: public CHeapObj { + const static int TruncatedSeqLength = 10; + const static int NumPrevPausesForHeuristics = 10; + const G1Predictions* _predictor; + + // These exclude marking times. + TruncatedSeq* _recent_gc_times_ms; + + TruncatedSeq* _concurrent_mark_remark_times_ms; + TruncatedSeq* _concurrent_mark_cleanup_times_ms; + + TruncatedSeq* _alloc_rate_ms_seq; + double _prev_collection_pause_end_ms; + + TruncatedSeq* _rs_length_diff_seq; + TruncatedSeq* _cost_per_card_ms_seq; + TruncatedSeq* _cost_scan_hcc_seq; + TruncatedSeq* _young_cards_per_entry_ratio_seq; + TruncatedSeq* _mixed_cards_per_entry_ratio_seq; + TruncatedSeq* _cost_per_entry_ms_seq; + TruncatedSeq* _mixed_cost_per_entry_ms_seq; + TruncatedSeq* _cost_per_byte_ms_seq; + TruncatedSeq* _constant_other_time_ms_seq; + TruncatedSeq* _young_other_cost_per_region_ms_seq; + TruncatedSeq* _non_young_other_cost_per_region_ms_seq; + + TruncatedSeq* _pending_cards_seq; + TruncatedSeq* _rs_lengths_seq; + + TruncatedSeq* _cost_per_byte_ms_during_cm_seq; + + // Statistics kept per GC stoppage, pause or full. + TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec; + + // The ratio of gc time to elapsed time, computed over recent pauses, + // and the ratio for just the last pause. + double _recent_avg_pause_time_ratio; + double _last_pause_time_ratio; + + double get_new_prediction(TruncatedSeq const* seq) const; + size_t get_new_size_prediction(TruncatedSeq const* seq) const; + +public: + G1Analytics(const G1Predictions* predictor); + + double prev_collection_pause_end_ms() const { + return _prev_collection_pause_end_ms; + } + + double recent_avg_pause_time_ratio() const { + return _recent_avg_pause_time_ratio; + } + + double last_pause_time_ratio() const { + return _last_pause_time_ratio; + } + + uint number_of_recorded_pause_times() const { + return NumPrevPausesForHeuristics; + } + + void append_prev_collection_pause_end_ms(double ms) { + _prev_collection_pause_end_ms += ms; + } + + void report_concurrent_mark_remark_times_ms(double ms); + void report_concurrent_mark_cleanup_times_ms(double ms); + void report_alloc_rate_ms(double alloc_rate); + void report_cost_per_card_ms(double cost_per_card_ms); + void report_cost_scan_hcc(double cost_scan_hcc); + void report_cost_per_entry_ms(double cost_per_entry_ms, bool last_gc_was_young); + void report_cards_per_entry_ratio(double cards_per_entry_ratio, bool last_gc_was_young); + void report_rs_length_diff(double rs_length_diff); + void report_cost_per_byte_ms(double cost_per_byte_ms, bool in_marking_window); + void report_young_other_cost_per_region_ms(double other_cost_per_region_ms); + void report_non_young_other_cost_per_region_ms(double other_cost_per_region_ms); + void report_constant_other_time_ms(double constant_other_time_ms); + void report_pending_cards(double pending_cards); + void report_rs_lengths(double rs_lengths); + + size_t predict_rs_length_diff() const; + + double predict_alloc_rate_ms() const; + int num_alloc_rate_ms() const; + + double predict_cost_per_card_ms() const; + + double predict_scan_hcc_ms() const; + + double predict_rs_update_time_ms(size_t pending_cards) const; + + double predict_young_cards_per_entry_ratio() const; + + double predict_mixed_cards_per_entry_ratio() const; + + size_t predict_card_num(size_t rs_length, bool gcs_are_young) const; + + double predict_rs_scan_time_ms(size_t card_num, bool gcs_are_young) const; + + double predict_mixed_rs_scan_time_ms(size_t card_num) const; + + double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const; + + double predict_object_copy_time_ms(size_t bytes_to_copy, bool during_concurrent_mark) const; + + double predict_constant_other_time_ms() const; + + double predict_young_other_time_ms(size_t young_num) const; + + double predict_non_young_other_time_ms(size_t non_young_num) const; + + double predict_remark_time_ms() const; + + double predict_cleanup_time_ms() const; + + size_t predict_rs_lengths() const; + size_t predict_pending_cards() const; + + // Add a new GC of the given duration and end time to the record. + void update_recent_gc_times(double end_time_sec, double elapsed_ms); + void compute_pause_time_ratio(double interval_ms, double pause_time_ms); + + double last_known_gc_end_time_sec() const; +}; + +#endif // SHARE_VM_GC_G1_G1MEASUREMENTS_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index e23b8af5e86..03d4e76f3a8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -34,10 +34,12 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" +#include "gc/g1/g1HeapSizingPolicy.hpp" #include "gc/g1/g1HeapTransition.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1MarkSweep.hpp" @@ -67,6 +69,7 @@ #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/init.hpp" @@ -566,7 +569,7 @@ G1CollectedHeap::mem_allocate(size_t word_size, // Give a warning if we seem to be looping forever. if ((QueuedAllocationWarningCount > 0) && (try_count % QueuedAllocationWarningCount == 0)) { - warning("G1CollectedHeap::mem_allocate retries %d times", try_count); + log_warning(gc)("G1CollectedHeap::mem_allocate retries %d times", try_count); } } @@ -675,8 +678,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size, // Give a warning if we seem to be looping forever. if ((QueuedAllocationWarningCount > 0) && (try_count % QueuedAllocationWarningCount == 0)) { - warning("G1CollectedHeap::attempt_allocation_slow() " - "retries %d times", try_count); + log_warning(gc)("G1CollectedHeap::attempt_allocation_slow() " + "retries %d times", try_count); } } @@ -1091,8 +1094,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, if ((QueuedAllocationWarningCount > 0) && (try_count % QueuedAllocationWarningCount == 0)) { - warning("G1CollectedHeap::attempt_allocation_humongous() " - "retries %d times", try_count); + log_warning(gc)("G1CollectedHeap::attempt_allocation_humongous() " + "retries %d times", try_count); } } @@ -1228,6 +1231,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, ResourceMark rm; print_heap_before_gc(); + print_heap_regions(); trace_heap_before_gc(gc_tracer); size_t metadata_prev_used = MetaspaceAux::used_bytes(); @@ -1302,9 +1306,9 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, // set between the last GC or pause and now. We need to clear the // incremental collection set and then start rebuilding it afresh // after this full GC. - abandon_collection_set(g1_policy()->inc_cset_head()); - g1_policy()->clear_incremental_cset(); - g1_policy()->stop_incremental_cset_building(); + abandon_collection_set(collection_set()->inc_head()); + collection_set()->clear_incremental(); + collection_set()->stop_incremental_building(); tear_down_region_sets(false /* free_list_only */); collector_state()->set_gcs_are_young(true); @@ -1421,13 +1425,13 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, // the full GC has compacted objects and updated TAMS but not updated // the prev bitmap. if (G1VerifyBitmaps) { - ((G1CMBitMap*) concurrent_mark()->prevMarkBitMap())->clearAll(); + _cm->clear_prev_bitmap(workers()); } _verifier->check_bitmaps("Full GC End"); // Start a new incremental collection set for the next pause - assert(g1_policy()->collection_set() == NULL, "must be"); - g1_policy()->start_incremental_cset_building(); + assert(collection_set()->head() == NULL, "must be"); + collection_set()->start_incremental_building(); clear_cset_fast_test(); @@ -1446,6 +1450,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, heap_transition.print(); print_heap_after_gc(); + print_heap_regions(); trace_heap_after_gc(gc_tracer); post_full_gc_dump(gc_timer); @@ -1741,6 +1746,7 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) { G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : CollectedHeap(), _g1_policy(policy_), + _collection_set(this), _dirty_card_queue_set(false), _is_alive_closure_cm(this), _is_alive_closure_stw(this), @@ -1765,15 +1771,12 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _expand_heap_after_alloc_failure(true), _old_marking_cycles_started(0), _old_marking_cycles_completed(0), - _heap_summary_sent(false), _in_cset_fast_test(), _dirty_cards_region_list(NULL), _worker_cset_start_region(NULL), _worker_cset_start_region_time_stamp(NULL), _gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()), - _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()), - _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()), - _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) { + _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) { _workers = new WorkGang("GC Thread", ParallelGCThreads, /* are_GC_task_threads */true, @@ -1782,6 +1785,9 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _verifier = new G1HeapVerifier(this); _allocator = G1Allocator::create_allocator(this); + + _heap_sizing_policy = G1HeapSizingPolicy::create(this, _g1_policy->analytics()); + _humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords); // Override the default _filler_array_max_size so that no humongous filler @@ -2314,52 +2320,6 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) { FullGCCount_lock->notify_all(); } -void G1CollectedHeap::register_concurrent_cycle_start(const Ticks& start_time) { - GCIdMarkAndRestore conc_gc_id_mark; - collector_state()->set_concurrent_cycle_started(true); - _gc_timer_cm->register_gc_start(start_time); - - _gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start()); - trace_heap_before_gc(_gc_tracer_cm); - _cmThread->set_gc_id(GCId::current()); -} - -void G1CollectedHeap::register_concurrent_cycle_end() { - if (collector_state()->concurrent_cycle_started()) { - GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); - if (_cm->has_aborted()) { - _gc_tracer_cm->report_concurrent_mode_failure(); - - // ConcurrentGCTimer will be ended as well. - _cm->register_concurrent_gc_end_and_stop_timer(); - } else { - _gc_timer_cm->register_gc_end(); - } - - _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); - - // Clear state variables to prepare for the next concurrent cycle. - collector_state()->set_concurrent_cycle_started(false); - _heap_summary_sent = false; - } -} - -void G1CollectedHeap::trace_heap_after_concurrent_cycle() { - if (collector_state()->concurrent_cycle_started()) { - // This function can be called when: - // the cleanup pause is run - // the concurrent cycle is aborted before the cleanup pause. - // the concurrent cycle is aborted after the cleanup pause, - // but before the concurrent cycle end has been registered. - // Make sure that we only send the heap information once. - if (!_heap_summary_sent) { - GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); - trace_heap_after_gc(_gc_tracer_cm); - _heap_summary_sent = true; - } - } -} - void G1CollectedHeap::collect(GCCause::Cause cause) { assert_heap_not_locked(); @@ -2545,8 +2505,8 @@ HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) { // p threads // Then thread t will start at region floor ((t * n) / p) - result = g1_policy()->collection_set(); - uint cs_size = g1_policy()->cset_region_length(); + result = collection_set()->head(); + uint cs_size = collection_set()->region_length(); uint active_workers = workers()->active_workers(); uint end_ind = (cs_size * worker_i) / active_workers; @@ -2577,7 +2537,7 @@ HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) { } void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { - HeapRegion* r = g1_policy()->collection_set(); + HeapRegion* r = collection_set()->head(); while (r != NULL) { HeapRegion* next = r->next_in_collection_set(); if (cl->doHeapRegion(r)) { @@ -2606,7 +2566,7 @@ void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r, } cur = next; } - cur = g1_policy()->collection_set(); + cur = collection_set()->head(); while (cur != r) { HeapRegion* next = cur->next_in_collection_set(); if (cl->doHeapRegion(cur) && false) { @@ -2716,6 +2676,14 @@ bool G1CollectedHeap::is_obj_dead_cond(const oop obj, return false; // keep some compilers happy } +void G1CollectedHeap::print_heap_regions() const { + Log(gc, heap, region) log; + if (log.is_trace()) { + ResourceMark rm; + print_regions_on(log.trace_stream()); + } +} + void G1CollectedHeap::print_on(outputStream* st) const { st->print(" %-20s", "garbage-first heap"); st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", @@ -2729,18 +2697,14 @@ void G1CollectedHeap::print_on(outputStream* st) const { uint young_regions = _young_list->length(); st->print("%u young (" SIZE_FORMAT "K), ", young_regions, (size_t) young_regions * HeapRegion::GrainBytes / K); - uint survivor_regions = g1_policy()->recorded_survivor_regions(); + uint survivor_regions = _young_list->survivor_length(); st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions, (size_t) survivor_regions * HeapRegion::GrainBytes / K); st->cr(); MetaspaceAux::print_on(st); } -void G1CollectedHeap::print_extended_on(outputStream* st) const { - print_on(st); - - // Print the per-region information. - st->cr(); +void G1CollectedHeap::print_regions_on(outputStream* st) const { st->print_cr("Heap Regions: E=young(eden), S=young(survivor), O=old, " "HS=humongous(starts), HC=humongous(continues), " "CS=collection set, F=free, A=archive, TS=gc time stamp, " @@ -2750,6 +2714,13 @@ void G1CollectedHeap::print_extended_on(outputStream* st) const { heap_region_iterate(&blk); } +void G1CollectedHeap::print_extended_on(outputStream* st) const { + print_on(st); + + // Print the per-region information. + print_regions_on(st); +} + void G1CollectedHeap::print_on_error(outputStream* st) const { this->CollectedHeap::print_on_error(st); @@ -2839,12 +2810,14 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() { size_t eden_used_bytes = young_list->eden_used_bytes(); size_t survivor_used_bytes = young_list->survivor_used_bytes(); + size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); size_t eden_capacity_bytes = (g1_policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes; VirtualSpaceSummary heap_summary = create_heap_space_summary(); - return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes, num_regions()); + return G1HeapSummary(heap_summary, heap_used, eden_used_bytes, + eden_capacity_bytes, survivor_used_bytes, num_regions()); } G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) { @@ -2862,7 +2835,6 @@ void G1CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) { gc_tracer->report_metaspace_summary(when, metaspace_summary); } - G1CollectedHeap* G1CollectedHeap::heap() { CollectedHeap* heap = Universe::heap(); assert(heap != NULL, "Uninitialized access to G1CollectedHeap::heap()"); @@ -3138,10 +3110,10 @@ void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) { } void G1CollectedHeap::print_taskqueue_stats() const { - if (!log_develop_is_enabled(Trace, gc, task, stats)) { + if (!log_is_enabled(Trace, gc, task, stats)) { return; } - LogHandle(gc, task, stats) log; + Log(gc, task, stats) log; ResourceMark rm; outputStream* st = log.trace_stream(); @@ -3201,15 +3173,19 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { wait_for_root_region_scanning(); print_heap_before_gc(); + print_heap_regions(); trace_heap_before_gc(_gc_tracer_stw); _verifier->verify_region_sets_optional(); _verifier->verify_dirty_young_regions(); - // This call will decide whether this pause is an initial-mark - // pause. If it is, during_initial_mark_pause() will return true - // for the duration of this pause. - g1_policy()->decide_on_conc_mark_initiation(); + // We should not be doing initial mark unless the conc mark thread is running + if (!_cmThread->should_terminate()) { + // This call will decide whether this pause is an initial-mark + // pause. If it is, during_initial_mark_pause() will return true + // for the duration of this pause. + g1_policy()->decide_on_conc_mark_initiation(); + } // We do not allow initial-mark to be piggy-backed on a mixed GC. assert(!collector_state()->during_initial_mark_pause() || @@ -3231,7 +3207,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // We are about to start a marking cycle, so we increment the // full collection counter. increment_old_marking_cycles_started(); - register_concurrent_cycle_start(_gc_timer_stw->gc_start()); + _cm->gc_tracer_cm()->set_gc_cause(gc_cause()); } _gc_tracer_stw->report_yc_type(collector_state()->yc_type()); @@ -3253,7 +3229,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { Threads::number_of_non_daemon_threads()); workers()->set_active_workers(active_workers); - g1_policy()->note_gc_start(active_workers); + g1_policy()->note_gc_start(); TraceCollectorStats tcs(g1mm()->incremental_collection_counters()); TraceMemoryManagerStats tms(false /* fullGC */, gc_cause()); @@ -3336,10 +3312,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { concurrent_mark()->checkpointRootsInitialPre(); } - double time_remaining_ms = g1_policy()->finalize_young_cset_part(target_pause_time_ms); - g1_policy()->finalize_old_cset_part(time_remaining_ms); + g1_policy()->finalize_collection_set(target_pause_time_ms); - evacuation_info.set_collectionset_regions(g1_policy()->cset_region_length()); + evacuation_info.set_collectionset_regions(collection_set()->region_length()); // Make sure the remembered sets are up to date. This needs to be // done before register_humongous_regions_with_cset(), because the @@ -3358,7 +3333,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { _cm->verify_no_cset_oops(); if (_hr_printer.is_active()) { - HeapRegion* hr = g1_policy()->collection_set(); + HeapRegion* hr = collection_set()->head(); while (hr != NULL) { _hr_printer.cset(hr); hr = hr->next_in_collection_set(); @@ -3373,7 +3348,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // Initialize the GC alloc regions. _allocator->init_gc_alloc_regions(evacuation_info); - G1ParScanThreadStateSet per_thread_states(this, workers()->active_workers(), g1_policy()->young_cset_region_length()); + G1ParScanThreadStateSet per_thread_states(this, workers()->active_workers(), collection_set()->young_region_length()); pre_evacuate_collection_set(); // Actually do the work... @@ -3382,18 +3357,18 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { post_evacuate_collection_set(evacuation_info, &per_thread_states); const size_t* surviving_young_words = per_thread_states.surviving_young_words(); - free_collection_set(g1_policy()->collection_set(), evacuation_info, surviving_young_words); + free_collection_set(collection_set()->head(), evacuation_info, surviving_young_words); eagerly_reclaim_humongous_regions(); - g1_policy()->clear_collection_set(); + collection_set()->clear_head(); record_obj_copy_mem_stats(); _survivor_evac_stats.adjust_desired_plab_sz(); _old_evac_stats.adjust_desired_plab_sz(); // Start a new incremental collection set for the next pause. - g1_policy()->start_incremental_cset_building(); + collection_set()->start_incremental_building(); clear_cset_fast_test(); @@ -3404,10 +3379,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { assert(check_young_list_empty(false /* check_heap */), "young list should be empty"); - g1_policy()->record_survivor_regions(_young_list->survivor_length(), - _young_list->first_survivor_region(), - _young_list->last_survivor_region()); - _young_list->reset_auxilary_lists(); if (evacuation_failed()) { @@ -3442,7 +3413,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { _allocator->init_mutator_alloc_region(); { - size_t expand_bytes = g1_policy()->expansion_amount(); + size_t expand_bytes = _heap_sizing_policy->expansion_amount(); if (expand_bytes > 0) { size_t bytes_before = capacity(); // No need for an ergo logging here, @@ -3468,7 +3439,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { size_t total_cards_scanned = per_thread_states.total_cards_scanned(); g1_policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc); - evacuation_info.set_collectionset_used_before(g1_policy()->collection_set_bytes_used_before()); + evacuation_info.set_collectionset_used_before(collection_set()->bytes_used_before()); evacuation_info.set_bytes_copied(g1_policy()->bytes_copied_during_gc()); MemoryService::track_memory_usage(); @@ -3538,6 +3509,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); print_heap_after_gc(); + print_heap_regions(); trace_heap_after_gc(_gc_tracer_stw); // We must call G1MonitoringSupport::update_sizes() in the same scoping level @@ -3776,11 +3748,12 @@ public: "claim value %d after unlink less than initial symbol table size %d", SymbolTable::parallel_claimed_index(), _initial_symbol_table_size); - log_debug(gc, stringdedup)("Cleaned string and symbol table, " - "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, " - "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed", - strings_processed(), strings_removed(), - symbols_processed(), symbols_removed()); + log_info(gc, stringtable)( + "Cleaned string and symbol table, " + "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, " + "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed", + strings_processed(), strings_removed(), + symbols_processed(), symbols_removed()); } void work(uint worker_id) { @@ -4083,14 +4056,10 @@ void G1CollectedHeap::parallel_cleaning(BoolObjectClosure* is_alive, void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive, bool process_strings, bool process_symbols) { - { + { // Timing scope G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols); workers()->run_task(&g1_unlink_task); } - - if (G1StringDedup::is_enabled()) { - G1StringDedup::unlink(is_alive); - } } class G1RedirtyLoggedCardsTask : public AbstractGangTask { @@ -4279,7 +4248,7 @@ public: _workers(workers), _active_workers(n_workers) { - assert(n_workers > 0, "shouldn't call this otherwise"); + g1h->ref_processor_stw()->set_active_mt_degree(n_workers); } // Executes the given task using concurrent marking worker threads. @@ -4400,7 +4369,9 @@ public: _queues(task_queues), _terminator(workers, _queues), _n_workers(workers) - { } + { + g1h->ref_processor_cm()->set_active_mt_degree(workers); + } void work(uint worker_id) { G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id); @@ -4543,8 +4514,9 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per uint no_of_gc_workers = workers()->active_workers(); // Parallel reference processing - assert(rp->num_q() == no_of_gc_workers, "sanity"); - assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); + assert(no_of_gc_workers <= rp->max_num_q(), + "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u", + no_of_gc_workers, rp->max_num_q()); G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, no_of_gc_workers); stats = rp->process_discovered_references(&is_alive, @@ -4580,8 +4552,9 @@ void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadStateSet* per uint n_workers = workers()->active_workers(); - assert(rp->num_q() == n_workers, "sanity"); - assert(n_workers <= rp->max_num_q(), "sanity"); + assert(n_workers <= rp->max_num_q(), + "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u", + n_workers, rp->max_num_q()); G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, n_workers); rp->enqueue_discovered_references(&par_task_executor); @@ -4909,7 +4882,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e if (cur->is_young()) { int index = cur->young_index_in_cset(); assert(index != -1, "invariant"); - assert((uint) index < policy->young_cset_region_length(), "invariant"); + assert((uint) index < collection_set()->young_region_length(), "invariant"); size_t words_survived = surviving_young_words[index]; cur->record_surv_words_in_group(words_survived); @@ -5382,7 +5355,7 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region, assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); assert(alloc_region->is_eden(), "all mutator alloc regions should be eden"); - g1_policy()->add_region_to_incremental_cset_lhs(alloc_region); + collection_set()->add_eden_region(alloc_region); increase_used(allocated_bytes); _hr_printer.retire(alloc_region); // We update the eden sizes here, when the region is retired, @@ -5393,33 +5366,43 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region, // Methods for the GC alloc regions -HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, - uint count, - InCSetState dest) { +bool G1CollectedHeap::has_more_regions(InCSetState dest) { + if (dest.is_old()) { + return true; + } else { + return young_list()->survivor_length() < g1_policy()->max_survivor_regions(); + } +} + +HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, InCSetState dest) { assert(FreeList_lock->owned_by_self(), "pre-condition"); - if (count < g1_policy()->max_regions(dest)) { - const bool is_survivor = (dest.is_young()); - HeapRegion* new_alloc_region = new_region(word_size, - !is_survivor, - true /* do_expand */); - if (new_alloc_region != NULL) { - // We really only need to do this for old regions given that we - // should never scan survivors. But it doesn't hurt to do it - // for survivors too. - new_alloc_region->record_timestamp(); - if (is_survivor) { - new_alloc_region->set_survivor(); - _verifier->check_bitmaps("Survivor Region Allocation", new_alloc_region); - } else { - new_alloc_region->set_old(); - _verifier->check_bitmaps("Old Region Allocation", new_alloc_region); - } - _hr_printer.alloc(new_alloc_region); - bool during_im = collector_state()->during_initial_mark_pause(); - new_alloc_region->note_start_of_copying(during_im); - return new_alloc_region; + if (!has_more_regions(dest)) { + return NULL; + } + + const bool is_survivor = dest.is_young(); + + HeapRegion* new_alloc_region = new_region(word_size, + !is_survivor, + true /* do_expand */); + if (new_alloc_region != NULL) { + // We really only need to do this for old regions given that we + // should never scan survivors. But it doesn't hurt to do it + // for survivors too. + new_alloc_region->record_timestamp(); + if (is_survivor) { + new_alloc_region->set_survivor(); + young_list()->add_survivor_region(new_alloc_region); + _verifier->check_bitmaps("Survivor Region Allocation", new_alloc_region); + } else { + new_alloc_region->set_old(); + _verifier->check_bitmaps("Old Region Allocation", new_alloc_region); } + _hr_printer.alloc(new_alloc_region); + bool during_im = collector_state()->during_initial_mark_pause(); + new_alloc_region->note_start_of_copying(during_im); + return new_alloc_region; } return NULL; } @@ -5430,9 +5413,7 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, bool during_im = collector_state()->during_initial_mark_pause(); alloc_region->note_end_of_copying(during_im); g1_policy()->record_bytes_copied_during_gc(allocated_bytes); - if (dest.is_young()) { - young_list()->add_survivor_region(alloc_region); - } else { + if (dest.is_old()) { _old_set.add(alloc_region); } _hr_printer.retire(alloc_region); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index adbf7a20ef8..4bde7c70d04 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -28,6 +28,7 @@ #include "gc/g1/evacuationInfo.hpp" #include "gc/g1/g1AllocationContext.hpp" #include "gc/g1/g1BiasedArray.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1HRPrinter.hpp" @@ -65,17 +66,16 @@ class ObjectClosure; class SpaceClosure; class CompactibleSpaceClosure; class Space; +class G1CollectionSet; class G1CollectorPolicy; class G1RemSet; class HeapRegionRemSetIterator; class G1ConcurrentMark; class ConcurrentMarkThread; class ConcurrentG1Refine; -class ConcurrentGCTimer; class GenerationCounters; class STWGCTimer; class G1NewTracer; -class G1OldTracer; class EvacuationFailedInfo; class nmethod; class Ticks; @@ -83,6 +83,7 @@ class WorkGang; class G1Allocator; class G1ArchiveAllocator; class G1HeapVerifier; +class G1HeapSizingPolicy; typedef OverflowTaskQueue RefToScanQueue; typedef GenericTaskQueueSet RefToScanQueueSet; @@ -268,8 +269,6 @@ private: // concurrent cycles) we have completed. volatile uint _old_marking_cycles_completed; - bool _heap_summary_sent; - // This is a non-product method that is helpful for testing. It is // called at the end of a GC and artificially expands the heap by // allocating a number of dead regions. This way we can induce very @@ -362,6 +361,9 @@ protected: // The current policy object for the collector. G1CollectorPolicy* _g1_policy; + G1HeapSizingPolicy* _heap_sizing_policy; + + G1CollectionSet _collection_set; // This is the second level of trying to allocate a new region. If // new_region() didn't find a region on the free_list, this call will @@ -469,8 +471,8 @@ protected: size_t allocated_bytes); // For GC alloc regions. - HeapRegion* new_gc_alloc_region(size_t word_size, uint count, - InCSetState dest); + bool has_more_regions(InCSetState dest); + HeapRegion* new_gc_alloc_region(size_t word_size, InCSetState dest); void retire_gc_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes, InCSetState dest); @@ -618,10 +620,6 @@ public: return _old_marking_cycles_completed; } - void register_concurrent_cycle_start(const Ticks& start_time); - void register_concurrent_cycle_end(); - void trace_heap_after_concurrent_cycle(); - G1HRPrinter* hr_printer() { return &_hr_printer; } // Allocates a new heap region instance. @@ -896,9 +894,7 @@ protected: ReferenceProcessor* _ref_processor_stw; STWGCTimer* _gc_timer_stw; - ConcurrentGCTimer* _gc_timer_cm; - G1OldTracer* _gc_tracer_cm; G1NewTracer* _gc_tracer_stw; // During reference object discovery, the _is_alive_non_header @@ -985,6 +981,9 @@ public: // The current policy object for the collector. G1CollectorPolicy* g1_policy() const { return _g1_policy; } + const G1CollectionSet* collection_set() const { return &_collection_set; } + G1CollectionSet* collection_set() { return &_collection_set; } + virtual CollectorPolicy* collector_policy() const; // Adaptive size policy. No such thing for g1. @@ -1029,9 +1028,6 @@ public: // The Concurrent Marking reference processor... ReferenceProcessor* ref_processor_cm() const { return _ref_processor_cm; } - ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; } - G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; } - virtual size_t capacity() const; virtual size_t used() const; // This should be called when we're not holding the heap lock. The @@ -1285,6 +1281,12 @@ public: return true; } + // The reference pending list lock is acquired from from the + // ConcurrentMarkThread. + virtual bool needs_reference_pending_list_locker_thread() const { + return true; + } + inline bool is_in_young(const oop obj); virtual bool is_scavengable(const void* addr); @@ -1463,7 +1465,11 @@ public: G1EvacSummary create_g1_evac_summary(G1EvacStats* stats); // Printing +private: + void print_heap_regions() const; + void print_regions_on(outputStream* st) const; +public: virtual void print_on(outputStream* st) const; virtual void print_extended_on(outputStream* st) const; virtual void print_on_error(outputStream* st) const; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp b/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp new file mode 100644 index 00000000000..720c828d1bc --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectionSet.hpp" +#include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/g1/heapRegionRemSet.hpp" +#include "gc/g1/heapRegionSet.hpp" +#include "utilities/debug.hpp" + +G1CollectorState* G1CollectionSet::collector_state() { + return _g1->collector_state(); +} + +G1GCPhaseTimes* G1CollectionSet::phase_times() { + return _policy->phase_times(); +} + +CollectionSetChooser* G1CollectionSet::cset_chooser() { + return _cset_chooser; +} + +double G1CollectionSet::predict_region_elapsed_time_ms(HeapRegion* hr) { + return _policy->predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); +} + + +G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h) : + _g1(g1h), + _policy(NULL), + _cset_chooser(new CollectionSetChooser()), + _eden_region_length(0), + _survivor_region_length(0), + _old_region_length(0), + + _head(NULL), + _bytes_used_before(0), + _recorded_rs_lengths(0), + // Incremental CSet attributes + _inc_build_state(Inactive), + _inc_head(NULL), + _inc_tail(NULL), + _inc_bytes_used_before(0), + _inc_recorded_rs_lengths(0), + _inc_recorded_rs_lengths_diffs(0), + _inc_predicted_elapsed_time_ms(0.0), + _inc_predicted_elapsed_time_ms_diffs(0.0) {} + +G1CollectionSet::~G1CollectionSet() { + delete _cset_chooser; +} + +void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, + uint survivor_cset_region_length) { + _eden_region_length = eden_cset_region_length; + _survivor_region_length = survivor_cset_region_length; + _old_region_length = 0; +} + +void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) { + _recorded_rs_lengths = rs_lengths; +} + +// Add the heap region at the head of the non-incremental collection set +void G1CollectionSet::add_old_region(HeapRegion* hr) { + assert(_inc_build_state == Active, "Precondition"); + assert(hr->is_old(), "the region should be old"); + + assert(!hr->in_collection_set(), "should not already be in the CSet"); + _g1->register_old_region_with_cset(hr); + hr->set_next_in_collection_set(_head); + _head = hr; + _bytes_used_before += hr->used(); + size_t rs_length = hr->rem_set()->occupied(); + _recorded_rs_lengths += rs_length; + _old_region_length += 1; +} + +// Initialize the per-collection-set information +void G1CollectionSet::start_incremental_building() { + assert(_inc_build_state == Inactive, "Precondition"); + + _inc_head = NULL; + _inc_tail = NULL; + _inc_bytes_used_before = 0; + + _inc_recorded_rs_lengths = 0; + _inc_recorded_rs_lengths_diffs = 0; + _inc_predicted_elapsed_time_ms = 0.0; + _inc_predicted_elapsed_time_ms_diffs = 0.0; + _inc_build_state = Active; +} + +void G1CollectionSet::finalize_incremental_building() { + assert(_inc_build_state == Active, "Precondition"); + assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); + + // The two "main" fields, _inc_recorded_rs_lengths and + // _inc_predicted_elapsed_time_ms, are updated by the thread + // that adds a new region to the CSet. Further updates by the + // concurrent refinement thread that samples the young RSet lengths + // are accumulated in the *_diffs fields. Here we add the diffs to + // the "main" fields. + + if (_inc_recorded_rs_lengths_diffs >= 0) { + _inc_recorded_rs_lengths += _inc_recorded_rs_lengths_diffs; + } else { + // This is defensive. The diff should in theory be always positive + // as RSets can only grow between GCs. However, given that we + // sample their size concurrently with other threads updating them + // it's possible that we might get the wrong size back, which + // could make the calculations somewhat inaccurate. + size_t diffs = (size_t) (-_inc_recorded_rs_lengths_diffs); + if (_inc_recorded_rs_lengths >= diffs) { + _inc_recorded_rs_lengths -= diffs; + } else { + _inc_recorded_rs_lengths = 0; + } + } + _inc_predicted_elapsed_time_ms += _inc_predicted_elapsed_time_ms_diffs; + + _inc_recorded_rs_lengths_diffs = 0; + _inc_predicted_elapsed_time_ms_diffs = 0.0; +} + +void G1CollectionSet::update_young_region_prediction(HeapRegion* hr, + size_t new_rs_length) { + // Update the CSet information that is dependent on the new RS length + assert(hr->is_young(), "Precondition"); + assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint"); + + // We could have updated _inc_recorded_rs_lengths and + // _inc_predicted_elapsed_time_ms directly but we'd need to do + // that atomically, as this code is executed by a concurrent + // refinement thread, potentially concurrently with a mutator thread + // allocating a new region and also updating the same fields. To + // avoid the atomic operations we accumulate these updates on two + // separate fields (*_diffs) and we'll just add them to the "main" + // fields at the start of a GC. + + ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); + ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length; + _inc_recorded_rs_lengths_diffs += rs_lengths_diff; + + double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); + double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr); + double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; + _inc_predicted_elapsed_time_ms_diffs += elapsed_ms_diff; + + hr->set_recorded_rs_length(new_rs_length); + hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); +} + +void G1CollectionSet::add_young_region_common(HeapRegion* hr) { + assert(hr->is_young(), "invariant"); + assert(hr->young_index_in_cset() > -1, "should have already been set"); + assert(_inc_build_state == Active, "Precondition"); + + // This routine is used when: + // * adding survivor regions to the incremental cset at the end of an + // evacuation pause or + // * adding the current allocation region to the incremental cset + // when it is retired. + // Therefore this routine may be called at a safepoint by the + // VM thread, or in-between safepoints by mutator threads (when + // retiring the current allocation region) + // We need to clear and set the cached recorded/cached collection set + // information in the heap region here (before the region gets added + // to the collection set). An individual heap region's cached values + // are calculated, aggregated with the policy collection set info, + // and cached in the heap region here (initially) and (subsequently) + // by the Young List sampling code. + + size_t rs_length = hr->rem_set()->occupied(); + double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr); + + // Cache the values we have added to the aggregated information + // in the heap region in case we have to remove this region from + // the incremental collection set, or it is updated by the + // rset sampling code + hr->set_recorded_rs_length(rs_length); + hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); + + size_t used_bytes = hr->used(); + _inc_recorded_rs_lengths += rs_length; + _inc_predicted_elapsed_time_ms += region_elapsed_time_ms; + _inc_bytes_used_before += used_bytes; + + assert(!hr->in_collection_set(), "invariant"); + _g1->register_young_region_with_cset(hr); + assert(hr->next_in_collection_set() == NULL, "invariant"); +} + +// Add the region at the RHS of the incremental cset +void G1CollectionSet::add_survivor_regions(HeapRegion* hr) { + // We should only ever be appending survivors at the end of a pause + assert(hr->is_survivor(), "Logic"); + + // Do the 'common' stuff + add_young_region_common(hr); + + // Now add the region at the right hand side + if (_inc_tail == NULL) { + assert(_inc_head == NULL, "invariant"); + _inc_head = hr; + } else { + _inc_tail->set_next_in_collection_set(hr); + } + _inc_tail = hr; +} + +// Add the region to the LHS of the incremental cset +void G1CollectionSet::add_eden_region(HeapRegion* hr) { + // Survivors should be added to the RHS at the end of a pause + assert(hr->is_eden(), "Logic"); + + // Do the 'common' stuff + add_young_region_common(hr); + + // Add the region at the left hand side + hr->set_next_in_collection_set(_inc_head); + if (_inc_head == NULL) { + assert(_inc_tail == NULL, "Invariant"); + _inc_tail = hr; + } + _inc_head = hr; +} + +#ifndef PRODUCT +void G1CollectionSet::print(HeapRegion* list_head, outputStream* st) { + assert(list_head == inc_head() || list_head == head(), "must be"); + + st->print_cr("\nCollection_set:"); + HeapRegion* csr = list_head; + while (csr != NULL) { + HeapRegion* next = csr->next_in_collection_set(); + assert(csr->in_collection_set(), "bad CS"); + st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d", + HR_FORMAT_PARAMS(csr), + p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()), + csr->age_in_surv_rate_group_cond()); + csr = next; + } +} +#endif // !PRODUCT + +double G1CollectionSet::finalize_young_part(double target_pause_time_ms) { + double young_start_time_sec = os::elapsedTime(); + + YoungList* young_list = _g1->young_list(); + finalize_incremental_building(); + + guarantee(target_pause_time_ms > 0.0, + "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); + guarantee(_head == NULL, "Precondition"); + + size_t pending_cards = _policy->pending_cards(); + double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards); + double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); + + log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms", + pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); + + collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young()); + + // The young list is laid with the survivor regions from the previous + // pause are appended to the RHS of the young list, i.e. + // [Newly Young Regions ++ Survivors from last pause]. + + uint survivor_region_length = young_list->survivor_length(); + uint eden_region_length = young_list->eden_length(); + init_region_lengths(eden_region_length, survivor_region_length); + + HeapRegion* hr = young_list->first_survivor_region(); + while (hr != NULL) { + assert(hr->is_survivor(), "badly formed young list"); + // There is a convention that all the young regions in the CSet + // are tagged as "eden", so we do this for the survivors here. We + // use the special set_eden_pre_gc() as it doesn't check that the + // region is free (which is not the case here). + hr->set_eden_pre_gc(); + hr = hr->get_next_young_region(); + } + + // Clear the fields that point to the survivor list - they are all young now. + young_list->clear_survivors(); + + _head = _inc_head; + _bytes_used_before = _inc_bytes_used_before; + time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0); + + log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms", + eden_region_length, survivor_region_length, _inc_predicted_elapsed_time_ms, target_pause_time_ms); + + // The number of recorded young regions is the incremental + // collection set's current size + set_recorded_rs_lengths(_inc_recorded_rs_lengths); + + double young_end_time_sec = os::elapsedTime(); + phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0); + + return time_remaining_ms; +} + +void G1CollectionSet::finalize_old_part(double time_remaining_ms) { + double non_young_start_time_sec = os::elapsedTime(); + double predicted_old_time_ms = 0.0; + + if (!collector_state()->gcs_are_young()) { + cset_chooser()->verify(); + const uint min_old_cset_length = _policy->calc_min_old_cset_length(); + const uint max_old_cset_length = _policy->calc_max_old_cset_length(); + + uint expensive_region_num = 0; + bool check_time_remaining = _policy->adaptive_young_list_length(); + + HeapRegion* hr = cset_chooser()->peek(); + while (hr != NULL) { + if (old_region_length() >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions", + old_region_length(), max_old_cset_length); + break; + } + + // Stop adding regions if the remaining reclaimable space is + // not above G1HeapWastePercent. + size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); + double reclaimable_perc = _policy->reclaimable_bytes_perc(reclaimable_bytes); + double threshold = (double) G1HeapWastePercent; + if (reclaimable_perc <= threshold) { + // We've added enough old regions that the amount of uncollected + // reclaimable space is at or below the waste threshold. Stop + // adding old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " + "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%", + old_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); + break; + } + + double predicted_time_ms = predict_region_elapsed_time_ms(hr); + if (check_time_remaining) { + if (predicted_time_ms > time_remaining_ms) { + // Too expensive for the current CSet. + + if (old_region_length() >= min_old_cset_length) { + // We have added the minimum number of old regions to the CSet, + // we are done with this CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). " + "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions", + predicted_time_ms, time_remaining_ms, old_region_length(), min_old_cset_length); + break; + } + + // We'll add it anyway given that we haven't reached the + // minimum number of old regions. + expensive_region_num += 1; + } + } else { + if (old_region_length() >= min_old_cset_length) { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions", + old_region_length(), min_old_cset_length); + break; + } + } + + // We will add this region to the CSet. + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + predicted_old_time_ms += predicted_time_ms; + cset_chooser()->pop(); // already have region via peek() + _g1->old_set_remove(hr); + add_old_region(hr); + + hr = cset_chooser()->peek(); + } + if (hr == NULL) { + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); + } + + if (expensive_region_num > 0) { + // We print the information once here at the end, predicated on + // whether we added any apparently expensive regions or not, to + // avoid generating output per region. + log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)." + "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms", + old_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms); + } + + cset_chooser()->verify(); + } + + stop_incremental_building(); + + log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f", + old_region_length(), predicted_old_time_ms, time_remaining_ms); + + double non_young_end_time_sec = os::elapsedTime(); + phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); +} diff --git a/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp b/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp new file mode 100644 index 00000000000..75f93071624 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1COLLECTIONSET_HPP +#define SHARE_VM_GC_G1_G1COLLECTIONSET_HPP + +#include "gc/g1/collectionSetChooser.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +class G1CollectedHeap; +class G1CollectorPolicy; +class G1CollectorState; +class G1GCPhaseTimes; +class HeapRegion; + +class G1CollectionSet VALUE_OBJ_CLASS_SPEC { + G1CollectedHeap* _g1; + G1CollectorPolicy* _policy; + + CollectionSetChooser* _cset_chooser; + + uint _eden_region_length; + uint _survivor_region_length; + uint _old_region_length; + + // The head of the list (via "next_in_collection_set()") representing the + // current collection set. Set from the incrementally built collection + // set at the start of the pause. + HeapRegion* _head; + + // The number of bytes in the collection set before the pause. Set from + // the incrementally built collection set at the start of an evacuation + // pause, and incremented in finalize_old_part() when adding old regions + // (if any) to the collection set. + size_t _bytes_used_before; + + size_t _recorded_rs_lengths; + + // The associated information that is maintained while the incremental + // collection set is being built with young regions. Used to populate + // the recorded info for the evacuation pause. + + enum CSetBuildType { + Active, // We are actively building the collection set + Inactive // We are not actively building the collection set + }; + + CSetBuildType _inc_build_state; + + // The head of the incrementally built collection set. + HeapRegion* _inc_head; + + // The tail of the incrementally built collection set. + HeapRegion* _inc_tail; + + // The number of bytes in the incrementally built collection set. + // Used to set _collection_set_bytes_used_before at the start of + // an evacuation pause. + size_t _inc_bytes_used_before; + + // The RSet lengths recorded for regions in the CSet. It is updated + // by the thread that adds a new region to the CSet. We assume that + // only one thread can be allocating a new CSet region (currently, + // it does so after taking the Heap_lock) hence no need to + // synchronize updates to this field. + size_t _inc_recorded_rs_lengths; + + // A concurrent refinement thread periodically samples the young + // region RSets and needs to update _inc_recorded_rs_lengths as + // the RSets grow. Instead of having to synchronize updates to that + // field we accumulate them in this field and add it to + // _inc_recorded_rs_lengths_diffs at the start of a GC. + ssize_t _inc_recorded_rs_lengths_diffs; + + // The predicted elapsed time it will take to collect the regions in + // the CSet. This is updated by the thread that adds a new region to + // the CSet. See the comment for _inc_recorded_rs_lengths about + // MT-safety assumptions. + double _inc_predicted_elapsed_time_ms; + + // See the comment for _inc_recorded_rs_lengths_diffs. + double _inc_predicted_elapsed_time_ms_diffs; + + G1CollectorState* collector_state(); + G1GCPhaseTimes* phase_times(); + + double predict_region_elapsed_time_ms(HeapRegion* hr); + +public: + G1CollectionSet(G1CollectedHeap* g1h); + ~G1CollectionSet(); + + void set_policy(G1CollectorPolicy* g1p) { + assert(_policy == NULL, "should only initialize once"); + _policy = g1p; + } + + CollectionSetChooser* cset_chooser(); + + void init_region_lengths(uint eden_cset_region_length, + uint survivor_cset_region_length); + + void set_recorded_rs_lengths(size_t rs_lengths); + + uint region_length() const { return young_region_length() + + old_region_length(); } + uint young_region_length() const { return eden_region_length() + + survivor_region_length(); } + + uint eden_region_length() const { return _eden_region_length; } + uint survivor_region_length() const { return _survivor_region_length; } + uint old_region_length() const { return _old_region_length; } + + // Incremental CSet Support + + // The head of the incrementally built collection set. + HeapRegion* inc_head() { return _inc_head; } + + // The tail of the incrementally built collection set. + HeapRegion* inc_tail() { return _inc_tail; } + + // Initialize incremental collection set info. + void start_incremental_building(); + + // Perform any final calculations on the incremental CSet fields + // before we can use them. + void finalize_incremental_building(); + + void clear_incremental() { + _inc_head = NULL; + _inc_tail = NULL; + } + + // Stop adding regions to the incremental collection set + void stop_incremental_building() { _inc_build_state = Inactive; } + + // The head of the list (via "next_in_collection_set()") representing the + // current collection set. + HeapRegion* head() { return _head; } + + void clear_head() { _head = NULL; } + + size_t recorded_rs_lengths() { return _recorded_rs_lengths; } + + size_t bytes_used_before() const { + return _bytes_used_before; + } + + void reset_bytes_used_before() { + _bytes_used_before = 0; + } + + // Choose a new collection set. Marks the chosen regions as being + // "in_collection_set", and links them together. The head and number of + // the collection set are available via access methods. + double finalize_young_part(double target_pause_time_ms); + void finalize_old_part(double time_remaining_ms); + + // Add old region "hr" to the CSet. + void add_old_region(HeapRegion* hr); + + // Update information about hr in the aggregated information for + // the incrementally built collection set. + void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length); + + // Add hr to the LHS of the incremental collection set. + void add_eden_region(HeapRegion* hr); + + // Add hr to the RHS of the incremental collection set. + void add_survivor_regions(HeapRegion* hr); + +#ifndef PRODUCT + void print(HeapRegion* list_head, outputStream* st); +#endif // !PRODUCT + +private: + // Update the incremental cset information when adding a region + // (should not be called directly). + void add_young_region_common(HeapRegion* hr); + +}; + +#endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP + diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 17b61751b63..75c75ded31c 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -25,11 +25,14 @@ #include "precompiled.hpp" #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentMarkThread.inline.hpp" +#include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1IHOPControl.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" +#include "gc/g1/g1YoungGenSizer.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcPolicyCounters.hpp" @@ -39,107 +42,14 @@ #include "utilities/debug.hpp" #include "utilities/pair.hpp" -// Different defaults for different number of GC threads -// They were chosen by running GCOld and SPECjbb on debris with different -// numbers of GC threads and choosing them based on the results - -// all the same -static double rs_length_diff_defaults[] = { - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 -}; - -static double cost_per_card_ms_defaults[] = { - 0.01, 0.005, 0.005, 0.003, 0.003, 0.002, 0.002, 0.0015 -}; - -// all the same -static double young_cards_per_entry_ratio_defaults[] = { - 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 -}; - -static double cost_per_entry_ms_defaults[] = { - 0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005 -}; - -static double cost_per_byte_ms_defaults[] = { - 0.00006, 0.00003, 0.00003, 0.000015, 0.000015, 0.00001, 0.00001, 0.000009 -}; - -// these should be pretty consistent -static double constant_other_time_ms_defaults[] = { - 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0 -}; - - -static double young_other_cost_per_region_ms_defaults[] = { - 0.3, 0.2, 0.2, 0.15, 0.15, 0.12, 0.12, 0.1 -}; - -static double non_young_other_cost_per_region_ms_defaults[] = { - 1.0, 0.7, 0.7, 0.5, 0.5, 0.42, 0.42, 0.30 -}; - G1CollectorPolicy::G1CollectorPolicy() : _predictor(G1ConfidencePercent / 100.0), - - _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), - - _concurrent_mark_remark_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), - _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), - - _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _prev_collection_pause_end_ms(0.0), - _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)), - _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), - _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_byte_ms_during_cm_seq(new TruncatedSeq(TruncatedSeqLength)), - _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _non_young_other_cost_per_region_ms_seq( - new TruncatedSeq(TruncatedSeqLength)), - - _pending_cards_seq(new TruncatedSeq(TruncatedSeqLength)), - _rs_lengths_seq(new TruncatedSeq(TruncatedSeqLength)), - + _analytics(new G1Analytics(&_predictor)), _pause_time_target_ms((double) MaxGCPauseMillis), - - _recent_prev_end_times_for_all_gcs_sec( - new TruncatedSeq(NumPrevPausesForHeuristics)), - - _recent_avg_pause_time_ratio(0.0), _rs_lengths_prediction(0), _max_survivor_regions(0), - - _eden_cset_region_length(0), - _survivor_cset_region_length(0), - _old_cset_region_length(0), - - _collection_set(NULL), - _collection_set_bytes_used_before(0), - - // Incremental CSet attributes - _inc_cset_build_state(Inactive), - _inc_cset_head(NULL), - _inc_cset_tail(NULL), - _inc_cset_bytes_used_before(0), - _inc_cset_recorded_rs_lengths(0), - _inc_cset_recorded_rs_lengths_diffs(0), - _inc_cset_predicted_elapsed_time_ms(0.0), - _inc_cset_predicted_elapsed_time_ms_diffs(0.0), - - // add here any more surv rate groups - _recorded_survivor_regions(0), - _recorded_survivor_head(NULL), - _recorded_survivor_tail(NULL), _survivors_age_table(true), - _gc_overhead_perc(0.0), - _bytes_allocated_in_old_since_last_gc(0), _ihop_control(NULL), _initial_mark_to_mixed() { @@ -165,27 +75,8 @@ G1CollectorPolicy::G1CollectorPolicy() : HeapRegion::setup_heap_region_size(InitialHeapSize, MaxHeapSize); HeapRegionRemSet::setup_remset_size(); - _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime()); - _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0; - clear_ratio_check_data(); - _phase_times = new G1GCPhaseTimes(ParallelGCThreads); - int index = MIN2(ParallelGCThreads - 1, 7u); - - _rs_length_diff_seq->add(rs_length_diff_defaults[index]); - _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]); - _cost_scan_hcc_seq->add(0.0); - _young_cards_per_entry_ratio_seq->add( - young_cards_per_entry_ratio_defaults[index]); - _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]); - _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]); - _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]); - _young_other_cost_per_region_ms_seq->add( - young_other_cost_per_region_ms_defaults[index]); - _non_young_other_cost_per_region_ms_seq->add( - non_young_other_cost_per_region_ms_defaults[index]); - // Below, we might need to calculate the pause time target based on // the pause interval. When we do so we are going to give G1 maximum // flexibility and allow it to do pauses when it needs to. So, we'll @@ -198,18 +89,7 @@ G1CollectorPolicy::G1CollectorPolicy() : // First make sure that, if either parameter is set, its value is // reasonable. - if (!FLAG_IS_DEFAULT(MaxGCPauseMillis)) { - if (MaxGCPauseMillis < 1) { - vm_exit_during_initialization("MaxGCPauseMillis should be " - "greater than 0"); - } - } - if (!FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { - if (GCPauseIntervalMillis < 1) { - vm_exit_during_initialization("GCPauseIntervalMillis should be " - "greater than 0"); - } - } + guarantee(MaxGCPauseMillis >= 1, "Range checking for MaxGCPauseMillis should guarantee that value is >= 1"); // Then, if the pause time target parameter was not set, set it to // the default value. @@ -231,45 +111,22 @@ G1CollectorPolicy::G1CollectorPolicy() : if (FLAG_IS_DEFAULT(GCPauseIntervalMillis)) { FLAG_SET_DEFAULT(GCPauseIntervalMillis, MaxGCPauseMillis + 1); } - - // Finally, make sure that the two parameters are consistent. - if (MaxGCPauseMillis >= GCPauseIntervalMillis) { - char buffer[256]; - jio_snprintf(buffer, 256, - "MaxGCPauseMillis (%u) should be less than " - "GCPauseIntervalMillis (%u)", - MaxGCPauseMillis, GCPauseIntervalMillis); - vm_exit_during_initialization(buffer); - } + guarantee(GCPauseIntervalMillis >= 1, "Constraint for GCPauseIntervalMillis should guarantee that value is >= 1"); + guarantee(GCPauseIntervalMillis > MaxGCPauseMillis, "Constraint for GCPauseIntervalMillis should guarantee that GCPauseIntervalMillis > MaxGCPauseMillis"); double max_gc_time = (double) MaxGCPauseMillis / 1000.0; double time_slice = (double) GCPauseIntervalMillis / 1000.0; _mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time); - // start conservatively (around 50ms is about right) - _concurrent_mark_remark_times_ms->add(0.05); - _concurrent_mark_cleanup_times_ms->add(0.20); _tenuring_threshold = MaxTenuringThreshold; - assert(GCTimeRatio > 0, - "we should have set it to a default value set_g1_gc_flags() " - "if a user set it to 0"); - _gc_overhead_perc = 100.0 * (1.0 / (1.0 + GCTimeRatio)); - uintx reserve_perc = G1ReservePercent; - // Put an artificial ceiling on this so that it's not set to a silly value. - if (reserve_perc > 50) { - reserve_perc = 50; - warning("G1ReservePercent is set to a value that is too large, " - "it's been updated to " UINTX_FORMAT, reserve_perc); - } - _reserve_factor = (double) reserve_perc / 100.0; + guarantee(G1ReservePercent <= 50, "Range checking should not allow values over 50."); + _reserve_factor = (double) G1ReservePercent / 100.0; // This will be set when the heap is expanded // for the first time during initialization. _reserve_regions = 0; - _cset_chooser = new CollectionSetChooser(); - _ihop_control = create_ihop_control(); } @@ -277,14 +134,6 @@ G1CollectorPolicy::~G1CollectorPolicy() { delete _ihop_control; } -double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const { - return _predictor.get_new_prediction(seq); -} - -size_t G1CollectorPolicy::get_new_size_prediction(TruncatedSeq const* seq) const { - return (size_t)get_new_prediction(seq); -} - void G1CollectorPolicy::initialize_alignments() { _space_alignment = HeapRegion::GrainBytes; size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint(); @@ -294,177 +143,6 @@ void G1CollectorPolicy::initialize_alignments() { G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); } -// There are three command line options related to the young gen size: -// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is -// just a short form for NewSize==MaxNewSize). G1 will use its internal -// heuristics to calculate the actual young gen size, so these options -// basically only limit the range within which G1 can pick a young gen -// size. Also, these are general options taking byte sizes. G1 will -// internally work with a number of regions instead. So, some rounding -// will occur. -// -// If nothing related to the the young gen size is set on the command -// line we should allow the young gen to be between G1NewSizePercent -// and G1MaxNewSizePercent of the heap size. This means that every time -// the heap size changes, the limits for the young gen size will be -// recalculated. -// -// If only -XX:NewSize is set we should use the specified value as the -// minimum size for young gen. Still using G1MaxNewSizePercent of the -// heap as maximum. -// -// If only -XX:MaxNewSize is set we should use the specified value as the -// maximum size for young gen. Still using G1NewSizePercent of the heap -// as minimum. -// -// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values. -// No updates when the heap size changes. There is a special case when -// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a -// different heuristic for calculating the collection set when we do mixed -// collection. -// -// If only -XX:NewRatio is set we should use the specified ratio of the heap -// as both min and max. This will be interpreted as "fixed" just like the -// NewSize==MaxNewSize case above. But we will update the min and max -// every time the heap size changes. -// -// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is -// combined with either NewSize or MaxNewSize. (A warning message is printed.) -class G1YoungGenSizer : public CHeapObj { -private: - enum SizerKind { - SizerDefaults, - SizerNewSizeOnly, - SizerMaxNewSizeOnly, - SizerMaxAndNewSize, - SizerNewRatio - }; - SizerKind _sizer_kind; - uint _min_desired_young_length; - uint _max_desired_young_length; - bool _adaptive_size; - uint calculate_default_min_length(uint new_number_of_heap_regions); - uint calculate_default_max_length(uint new_number_of_heap_regions); - - // Update the given values for minimum and maximum young gen length in regions - // given the number of heap regions depending on the kind of sizing algorithm. - void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length); - -public: - G1YoungGenSizer(); - // Calculate the maximum length of the young gen given the number of regions - // depending on the sizing algorithm. - uint max_young_length(uint number_of_heap_regions); - - void heap_size_changed(uint new_number_of_heap_regions); - uint min_desired_young_length() { - return _min_desired_young_length; - } - uint max_desired_young_length() { - return _max_desired_young_length; - } - - bool adaptive_young_list_length() const { - return _adaptive_size; - } -}; - - -G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), - _min_desired_young_length(0), _max_desired_young_length(0) { - if (FLAG_IS_CMDLINE(NewRatio)) { - if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { - warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); - } else { - _sizer_kind = SizerNewRatio; - _adaptive_size = false; - return; - } - } - - if (NewSize > MaxNewSize) { - if (FLAG_IS_CMDLINE(MaxNewSize)) { - warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " - "A new max generation size of " SIZE_FORMAT "k will be used.", - NewSize/K, MaxNewSize/K, NewSize/K); - } - MaxNewSize = NewSize; - } - - if (FLAG_IS_CMDLINE(NewSize)) { - _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes), - 1U); - if (FLAG_IS_CMDLINE(MaxNewSize)) { - _max_desired_young_length = - MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), - 1U); - _sizer_kind = SizerMaxAndNewSize; - _adaptive_size = _min_desired_young_length == _max_desired_young_length; - } else { - _sizer_kind = SizerNewSizeOnly; - } - } else if (FLAG_IS_CMDLINE(MaxNewSize)) { - _max_desired_young_length = - MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), - 1U); - _sizer_kind = SizerMaxNewSizeOnly; - } -} - -uint G1YoungGenSizer::calculate_default_min_length(uint new_number_of_heap_regions) { - uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100; - return MAX2(1U, default_value); -} - -uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regions) { - uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100; - return MAX2(1U, default_value); -} - -void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) { - assert(number_of_heap_regions > 0, "Heap must be initialized"); - - switch (_sizer_kind) { - case SizerDefaults: - *min_young_length = calculate_default_min_length(number_of_heap_regions); - *max_young_length = calculate_default_max_length(number_of_heap_regions); - break; - case SizerNewSizeOnly: - *max_young_length = calculate_default_max_length(number_of_heap_regions); - *max_young_length = MAX2(*min_young_length, *max_young_length); - break; - case SizerMaxNewSizeOnly: - *min_young_length = calculate_default_min_length(number_of_heap_regions); - *min_young_length = MIN2(*min_young_length, *max_young_length); - break; - case SizerMaxAndNewSize: - // Do nothing. Values set on the command line, don't update them at runtime. - break; - case SizerNewRatio: - *min_young_length = number_of_heap_regions / (NewRatio + 1); - *max_young_length = *min_young_length; - break; - default: - ShouldNotReachHere(); - } - - assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values"); -} - -uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) { - // We need to pass the desired values because recalculation may not update these - // values in some cases. - uint temp = _min_desired_young_length; - uint result = _max_desired_young_length; - recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); - return result; -} - -void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { - recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, - &_max_desired_young_length); -} - void G1CollectorPolicy::post_heap_initialize() { uintx max_regions = G1CollectedHeap::heap()->max_regions(); size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes; @@ -478,9 +156,8 @@ void G1CollectorPolicy::initialize_flags() { FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes); } - if (SurvivorRatio < 1) { - vm_exit_during_initialization("Invalid survivor ratio specified"); - } + guarantee(SurvivorRatio >= 1, "Range checking for SurvivorRatio should guarantee that value is >= 1"); + CollectorPolicy::initialize_flags(); _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags } @@ -489,6 +166,8 @@ void G1CollectorPolicy::initialize_flags() { void G1CollectorPolicy::init() { // Set aside an initial future to_space. _g1 = G1CollectedHeap::heap(); + _collection_set = _g1->collection_set(); + _collection_set->set_policy(this); assert(Heap_lock->owned_by_self(), "Locking discipline."); @@ -504,11 +183,11 @@ void G1CollectorPolicy::init() { update_young_list_max_and_target_length(); // We may immediately start allocating regions and placing them on the // collection set list. Initialize the per-collection set info - start_incremental_cset_building(); + _collection_set->start_incremental_building(); } -void G1CollectorPolicy::note_gc_start(uint num_active_workers) { - phase_times()->note_gc_start(num_active_workers); +void G1CollectorPolicy::note_gc_start() { + phase_times()->note_gc_start(); } // Create the jstat counters for the policy. @@ -528,8 +207,9 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, double accum_surv_rate = accum_yg_surv_rate_pred((int) young_length - 1); size_t bytes_to_copy = (size_t) (accum_surv_rate * (double) HeapRegion::GrainBytes); - double copy_time_ms = predict_object_copy_time_ms(bytes_to_copy); - double young_other_time_ms = predict_young_other_time_ms(young_length); + double copy_time_ms = _analytics->predict_object_copy_time_ms(bytes_to_copy, + collector_state()->during_concurrent_mark()); + double young_other_time_ms = _analytics->predict_young_other_time_ms(young_length); double pause_time_ms = base_time_ms + copy_time_ms + young_other_time_ms; if (pause_time_ms > target_pause_time_ms) { // end condition 2: prediction is over the target pause time @@ -573,10 +253,10 @@ uint G1CollectorPolicy::calculate_young_list_desired_min_length( uint base_min_length) const { uint desired_min_length = 0; if (adaptive_young_list_length()) { - if (_alloc_rate_ms_seq->num() > 3) { + if (_analytics->num_alloc_rate_ms() > 3) { double now_sec = os::elapsedTime(); double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0; - double alloc_rate_ms = predict_alloc_rate_ms(); + double alloc_rate_ms = _analytics->predict_alloc_rate_ms(); desired_min_length = (uint) ceil(alloc_rate_ms * when_ms); } else { // otherwise we don't have enough info to make the prediction @@ -595,7 +275,7 @@ uint G1CollectorPolicy::calculate_young_list_desired_max_length() const { } uint G1CollectorPolicy::update_young_list_max_and_target_length() { - return update_young_list_max_and_target_length(get_new_size_prediction(_rs_lengths_seq)); + return update_young_list_max_and_target_length(_analytics->predict_rs_lengths()); } uint G1CollectorPolicy::update_young_list_max_and_target_length(size_t rs_lengths) { @@ -616,7 +296,7 @@ G1CollectorPolicy::YoungTargetLengths G1CollectorPolicy::young_list_target_lengt // Calculate the absolute and desired min bounds first. // This is how many young regions we already have (currently: the survivors). - uint base_min_length = recorded_survivor_regions(); + const uint base_min_length = _g1->young_list()->survivor_length(); uint desired_min_length = calculate_young_list_desired_min_length(base_min_length); // This is the absolute minimum young length. Ensure that we // will at least have one eden region available for allocation. @@ -667,7 +347,7 @@ G1CollectorPolicy::YoungTargetLengths G1CollectorPolicy::young_list_target_lengt young_list_target_length = desired_min_length; } - assert(young_list_target_length > recorded_survivor_regions(), + assert(young_list_target_length > base_min_length, "we should be able to allocate at least one eden region"); assert(young_list_target_length >= absolute_min_length, "post-condition"); @@ -700,9 +380,9 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; double survivor_regions_evac_time = predict_survivor_regions_evac_time(); - size_t pending_cards = get_new_size_prediction(_pending_cards_seq); - size_t adj_rs_lengths = rs_lengths + predict_rs_length_diff(); - size_t scanned_cards = predict_young_card_num(adj_rs_lengths); + size_t pending_cards = _analytics->predict_pending_cards(); + size_t adj_rs_lengths = rs_lengths + _analytics->predict_rs_length_diff(); + size_t scanned_cards = _analytics->predict_card_num(adj_rs_lengths, /* gcs_are_young */ true); double base_time_ms = predict_base_elapsed_time_ms(pending_cards, scanned_cards) + survivor_regions_evac_time; @@ -781,8 +461,8 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, double G1CollectorPolicy::predict_survivor_regions_evac_time() const { double survivor_regions_evac_time = 0.0; - for (HeapRegion * r = _recorded_survivor_head; - r != NULL && r != _recorded_survivor_tail->get_next_young_region(); + for (HeapRegion * r = _g1->young_list()->first_survivor_region(); + r != NULL && r != _g1->young_list()->last_survivor_region()->get_next_young_region(); r = r->get_next_young_region()) { survivor_regions_evac_time += predict_region_elapsed_time_ms(r, collector_state()->gcs_are_young()); } @@ -802,7 +482,7 @@ void G1CollectorPolicy::revise_young_list_target_length_if_necessary(size_t rs_l } void G1CollectorPolicy::update_rs_lengths_prediction() { - update_rs_lengths_prediction(get_new_size_prediction(_rs_lengths_seq)); + update_rs_lengths_prediction(_analytics->predict_rs_lengths()); } void G1CollectorPolicy::update_rs_lengths_prediction(size_t prediction) { @@ -870,7 +550,7 @@ void G1CollectorPolicy::record_full_collection_end() { double full_gc_time_sec = end_sec - _full_collection_start_sec; double full_gc_time_ms = full_gc_time_sec * 1000.0; - update_recent_gc_times(end_sec, full_gc_time_ms); + _analytics->update_recent_gc_times(end_sec, full_gc_time_ms); collector_state()->set_full_collection(false); @@ -886,8 +566,6 @@ void G1CollectorPolicy::record_full_collection_end() { _short_lived_surv_rate_group->start_adding_regions(); // also call this on any additional surv rate groups - record_survivor_regions(0, NULL, NULL); - _free_regions_at_end_of_collection = _g1->num_free_regions(); // Reset survivors SurvRateGroup. _survivor_surv_rate_group->reset(); @@ -913,7 +591,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec) { phase_times()->record_cur_collection_start_sec(start_time_sec); _pending_cards = _g1->pending_card_num(); - _collection_set_bytes_used_before = 0; + _collection_set->reset_bytes_used_before(); _bytes_copied_during_gc = 0; collector_state()->set_last_gc_was_young(false); @@ -940,8 +618,8 @@ void G1CollectorPolicy::record_concurrent_mark_remark_start() { void G1CollectorPolicy::record_concurrent_mark_remark_end() { double end_time_sec = os::elapsedTime(); double elapsed_time_ms = (end_time_sec - _mark_remark_start_sec)*1000.0; - _concurrent_mark_remark_times_ms->add(elapsed_time_ms); - _prev_collection_pause_end_ms += elapsed_time_ms; + _analytics->report_concurrent_mark_remark_times_ms(elapsed_time_ms); + _analytics->append_prev_collection_pause_end_ms(elapsed_time_ms); record_pause(Remark, _mark_remark_start_sec, end_time_sec); } @@ -988,6 +666,10 @@ double G1CollectorPolicy::constant_other_time_ms(double pause_time_ms) const { return other_time_ms(pause_time_ms) - young_other_time_ms() - non_young_other_time_ms(); } +CollectionSetChooser* G1CollectorPolicy::cset_chooser() const { + return _collection_set->cset_chooser(); +} + bool G1CollectorPolicy::about_to_start_mixed_phase() const { return _g1->concurrent_mark()->cmThread()->during_cycle() || collector_state()->last_young_gc(); } @@ -1036,7 +718,7 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t maybe_start_marking(); } - double app_time_ms = (phase_times()->cur_collection_start_sec() * 1000.0 - _prev_collection_pause_end_ms); + double app_time_ms = (phase_times()->cur_collection_start_sec() * 1000.0 - _analytics->prev_collection_pause_end_ms()); if (app_time_ms < MIN_TIMER_GRANULARITY) { // This usually happens due to the timer not having the required // granularity. Some Linuxes are the usual culprits. @@ -1053,33 +735,14 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // given that humongous object allocations do not really affect // either the pause's duration nor when the next pause will take // place we can safely ignore them here. - uint regions_allocated = eden_cset_region_length(); + uint regions_allocated = _collection_set->eden_region_length(); double alloc_rate_ms = (double) regions_allocated / app_time_ms; - _alloc_rate_ms_seq->add(alloc_rate_ms); + _analytics->report_alloc_rate_ms(alloc_rate_ms); double interval_ms = - (end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0; - update_recent_gc_times(end_time_sec, pause_time_ms); - _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms; - if (recent_avg_pause_time_ratio() < 0.0 || - (recent_avg_pause_time_ratio() - 1.0 > 0.0)) { - // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in - // CR 6902692 by redoing the manner in which the ratio is incrementally computed. - if (_recent_avg_pause_time_ratio < 0.0) { - _recent_avg_pause_time_ratio = 0.0; - } else { - assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant"); - _recent_avg_pause_time_ratio = 1.0; - } - } - - // Compute the ratio of just this last pause time to the entire time range stored - // in the vectors. Comparing this pause to the entire range, rather than only the - // most recent interval, has the effect of smoothing over a possible transient 'burst' - // of more frequent pauses that don't really reflect a change in heap occupancy. - // This reduces the likelihood of a needless heap expansion being triggered. - _last_pause_time_ratio = - (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms; + (end_time_sec - _analytics->last_known_gc_end_time_sec()) * 1000.0; + _analytics->update_recent_gc_times(end_time_sec, pause_time_ms); + _analytics->compute_pause_time_ratio(interval_ms, pause_time_ms); } bool new_in_marking_window = collector_state()->in_marking_window(); @@ -1125,28 +788,20 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t double cost_per_card_ms = 0.0; if (_pending_cards > 0) { cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards; - _cost_per_card_ms_seq->add(cost_per_card_ms); + _analytics->report_cost_per_card_ms(cost_per_card_ms); } - _cost_scan_hcc_seq->add(scan_hcc_time_ms); + _analytics->report_cost_scan_hcc(scan_hcc_time_ms); double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { cost_per_entry_ms = average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned; - if (collector_state()->last_gc_was_young()) { - _cost_per_entry_ms_seq->add(cost_per_entry_ms); - } else { - _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms); - } + _analytics->report_cost_per_entry_ms(cost_per_entry_ms, collector_state()->last_gc_was_young()); } if (_max_rs_lengths > 0) { double cards_per_entry_ratio = (double) cards_scanned / (double) _max_rs_lengths; - if (collector_state()->last_gc_was_young()) { - _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); - } else { - _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); - } + _analytics->report_cards_per_entry_ratio(cards_per_entry_ratio, collector_state()->last_gc_was_young()); } // This is defensive. For a while _max_rs_lengths could get @@ -1163,38 +818,35 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // say, it's in mid-coarsening). So I'll leave in the defensive // conditional below just in case. size_t rs_length_diff = 0; - if (_max_rs_lengths > _recorded_rs_lengths) { - rs_length_diff = _max_rs_lengths - _recorded_rs_lengths; + size_t recorded_rs_lengths = _collection_set->recorded_rs_lengths(); + if (_max_rs_lengths > recorded_rs_lengths) { + rs_length_diff = _max_rs_lengths - recorded_rs_lengths; } - _rs_length_diff_seq->add((double) rs_length_diff); + _analytics->report_rs_length_diff((double) rs_length_diff); size_t freed_bytes = heap_used_bytes_before_gc - cur_used_bytes; - size_t copied_bytes = _collection_set_bytes_used_before - freed_bytes; + size_t copied_bytes = _collection_set->bytes_used_before() - freed_bytes; double cost_per_byte_ms = 0.0; if (copied_bytes > 0) { cost_per_byte_ms = average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes; - if (collector_state()->in_marking_window()) { - _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms); - } else { - _cost_per_byte_ms_seq->add(cost_per_byte_ms); - } + _analytics->report_cost_per_byte_ms(cost_per_byte_ms, collector_state()->in_marking_window()); } - if (young_cset_region_length() > 0) { - _young_other_cost_per_region_ms_seq->add(young_other_time_ms() / - young_cset_region_length()); + if (_collection_set->young_region_length() > 0) { + _analytics->report_young_other_cost_per_region_ms(young_other_time_ms() / + _collection_set->young_region_length()); } - if (old_cset_region_length() > 0) { - _non_young_other_cost_per_region_ms_seq->add(non_young_other_time_ms() / - old_cset_region_length()); + if (_collection_set->old_region_length() > 0) { + _analytics->report_non_young_other_cost_per_region_ms(non_young_other_time_ms() / + _collection_set->old_region_length()); } - _constant_other_time_ms_seq->add(constant_other_time_ms(pause_time_ms)); + _analytics->report_constant_other_time_ms(constant_other_time_ms(pause_time_ms)); - _pending_cards_seq->add((double) _pending_cards); - _rs_lengths_seq->add((double) _max_rs_lengths); + _analytics->report_pending_cards((double) _pending_cards); + _analytics->report_rs_lengths((double) _max_rs_lengths); } collector_state()->set_in_marking_window(new_in_marking_window); @@ -1226,9 +878,9 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t } else { update_rs_time_goal_ms -= scan_hcc_time_ms; } - adjust_concurrent_refinement(average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms, - phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), - update_rs_time_goal_ms); + _g1->concurrent_g1_refine()->adjust(average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms, + phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), + update_rs_time_goal_ms); cset_chooser()->verify(); } @@ -1290,143 +942,10 @@ void G1CollectorPolicy::print_phases() { phase_times()->print(); } -void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, - double update_rs_processed_buffers, - double goal_ms) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - ConcurrentG1Refine *cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); - - if (G1UseAdaptiveConcRefinement) { - const int k_gy = 3, k_gr = 6; - const double inc_k = 1.1, dec_k = 0.9; - - size_t g = cg1r->green_zone(); - if (update_rs_time > goal_ms) { - g = (size_t)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. - } else { - if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { - g = (size_t)MAX2(g * inc_k, g + 1.0); - } - } - // Change the refinement threads params - cg1r->set_green_zone(g); - cg1r->set_yellow_zone(g * k_gy); - cg1r->set_red_zone(g * k_gr); - cg1r->reinitialize_threads(); - - size_t processing_threshold_delta = MAX2(cg1r->green_zone() * _predictor.sigma(), 1); - size_t processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, - cg1r->yellow_zone()); - // Change the barrier params - dcqs.set_process_completed_threshold((int)processing_threshold); - dcqs.set_max_completed_queue((int)cg1r->red_zone()); - } - - size_t curr_queue_size = dcqs.completed_buffers_num(); - if (curr_queue_size >= cg1r->yellow_zone()) { - dcqs.set_completed_queue_padding(curr_queue_size); - } else { - dcqs.set_completed_queue_padding(0); - } - dcqs.notify_if_necessary(); -} - -size_t G1CollectorPolicy::predict_rs_length_diff() const { - return get_new_size_prediction(_rs_length_diff_seq); -} - -double G1CollectorPolicy::predict_alloc_rate_ms() const { - return get_new_prediction(_alloc_rate_ms_seq); -} - -double G1CollectorPolicy::predict_cost_per_card_ms() const { - return get_new_prediction(_cost_per_card_ms_seq); -} - -double G1CollectorPolicy::predict_scan_hcc_ms() const { - return get_new_prediction(_cost_scan_hcc_seq); -} - -double G1CollectorPolicy::predict_rs_update_time_ms(size_t pending_cards) const { - return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms(); -} - -double G1CollectorPolicy::predict_young_cards_per_entry_ratio() const { - return get_new_prediction(_young_cards_per_entry_ratio_seq); -} - -double G1CollectorPolicy::predict_mixed_cards_per_entry_ratio() const { - if (_mixed_cards_per_entry_ratio_seq->num() < 2) { - return predict_young_cards_per_entry_ratio(); - } else { - return get_new_prediction(_mixed_cards_per_entry_ratio_seq); - } -} - -size_t G1CollectorPolicy::predict_young_card_num(size_t rs_length) const { - return (size_t) (rs_length * predict_young_cards_per_entry_ratio()); -} - -size_t G1CollectorPolicy::predict_non_young_card_num(size_t rs_length) const { - return (size_t)(rs_length * predict_mixed_cards_per_entry_ratio()); -} - -double G1CollectorPolicy::predict_rs_scan_time_ms(size_t card_num) const { - if (collector_state()->gcs_are_young()) { - return card_num * get_new_prediction(_cost_per_entry_ms_seq); - } else { - return predict_mixed_rs_scan_time_ms(card_num); - } -} - -double G1CollectorPolicy::predict_mixed_rs_scan_time_ms(size_t card_num) const { - if (_mixed_cost_per_entry_ms_seq->num() < 3) { - return card_num * get_new_prediction(_cost_per_entry_ms_seq); - } else { - return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq); - } -} - -double G1CollectorPolicy::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const { - if (_cost_per_byte_ms_during_cm_seq->num() < 3) { - return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq); - } else { - return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq); - } -} - -double G1CollectorPolicy::predict_object_copy_time_ms(size_t bytes_to_copy) const { - if (collector_state()->during_concurrent_mark()) { - return predict_object_copy_time_ms_during_cm(bytes_to_copy); - } else { - return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq); - } -} - -double G1CollectorPolicy::predict_constant_other_time_ms() const { - return get_new_prediction(_constant_other_time_ms_seq); -} - -double G1CollectorPolicy::predict_young_other_time_ms(size_t young_num) const { - return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq); -} - -double G1CollectorPolicy::predict_non_young_other_time_ms(size_t non_young_num) const { - return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq); -} - -double G1CollectorPolicy::predict_remark_time_ms() const { - return get_new_prediction(_concurrent_mark_remark_times_ms); -} - -double G1CollectorPolicy::predict_cleanup_time_ms() const { - return get_new_prediction(_concurrent_mark_cleanup_times_ms); -} - double G1CollectorPolicy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const { TruncatedSeq* seq = surv_rate_group->get_seq(age); guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age); - double pred = get_new_prediction(seq); + double pred = _predictor.get_new_prediction(seq); if (pred > 1.0) { pred = 1.0; } @@ -1444,19 +963,14 @@ double G1CollectorPolicy::accum_yg_surv_rate_pred(int age) const { double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards, size_t scanned_cards) const { return - predict_rs_update_time_ms(pending_cards) + - predict_rs_scan_time_ms(scanned_cards) + - predict_constant_other_time_ms(); + _analytics->predict_rs_update_time_ms(pending_cards) + + _analytics->predict_rs_scan_time_ms(scanned_cards, collector_state()->gcs_are_young()) + + _analytics->predict_constant_other_time_ms(); } double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const { - size_t rs_length = predict_rs_length_diff(); - size_t card_num; - if (collector_state()->gcs_are_young()) { - card_num = predict_young_card_num(rs_length); - } else { - card_num = predict_non_young_card_num(rs_length); - } + size_t rs_length = _analytics->predict_rs_lengths() + _analytics->predict_rs_length_diff(); + size_t card_num = _analytics->predict_card_num(rs_length, collector_state()->gcs_are_young()); return predict_base_elapsed_time_ms(pending_cards, card_num); } @@ -1476,160 +990,25 @@ size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) const { double G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const { size_t rs_length = hr->rem_set()->occupied(); - size_t card_num; - // Predicting the number of cards is based on which type of GC // we're predicting for. - if (for_young_gc) { - card_num = predict_young_card_num(rs_length); - } else { - card_num = predict_non_young_card_num(rs_length); - } + size_t card_num = _analytics->predict_card_num(rs_length, for_young_gc); size_t bytes_to_copy = predict_bytes_to_copy(hr); double region_elapsed_time_ms = - predict_rs_scan_time_ms(card_num) + - predict_object_copy_time_ms(bytes_to_copy); + _analytics->predict_rs_scan_time_ms(card_num, collector_state()->gcs_are_young()) + + _analytics->predict_object_copy_time_ms(bytes_to_copy, collector_state()->during_concurrent_mark()); // The prediction of the "other" time for this region is based // upon the region type and NOT the GC type. if (hr->is_young()) { - region_elapsed_time_ms += predict_young_other_time_ms(1); + region_elapsed_time_ms += _analytics->predict_young_other_time_ms(1); } else { - region_elapsed_time_ms += predict_non_young_other_time_ms(1); + region_elapsed_time_ms += _analytics->predict_non_young_other_time_ms(1); } return region_elapsed_time_ms; } -void G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length, - uint survivor_cset_region_length) { - _eden_cset_region_length = eden_cset_region_length; - _survivor_cset_region_length = survivor_cset_region_length; - _old_cset_region_length = 0; -} - -void G1CollectorPolicy::set_recorded_rs_lengths(size_t rs_lengths) { - _recorded_rs_lengths = rs_lengths; -} - -void G1CollectorPolicy::update_recent_gc_times(double end_time_sec, - double elapsed_ms) { - _recent_gc_times_ms->add(elapsed_ms); - _recent_prev_end_times_for_all_gcs_sec->add(end_time_sec); - _prev_collection_pause_end_ms = end_time_sec * 1000.0; -} - -void G1CollectorPolicy::clear_ratio_check_data() { - _ratio_over_threshold_count = 0; - _ratio_over_threshold_sum = 0.0; - _pauses_since_start = 0; -} - -size_t G1CollectorPolicy::expansion_amount() { - double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0; - double last_gc_overhead = _last_pause_time_ratio * 100.0; - double threshold = _gc_overhead_perc; - size_t expand_bytes = 0; - - // If the heap is at less than half its maximum size, scale the threshold down, - // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand, - // though the scaling code will likely keep the increase small. - if (_g1->capacity() <= _g1->max_capacity() / 2) { - threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2); - threshold = MAX2(threshold, 1.0); - } - - // If the last GC time ratio is over the threshold, increment the count of - // times it has been exceeded, and add this ratio to the sum of exceeded - // ratios. - if (last_gc_overhead > threshold) { - _ratio_over_threshold_count++; - _ratio_over_threshold_sum += last_gc_overhead; - } - - // Check if we've had enough GC time ratio checks that were over the - // threshold to trigger an expansion. We'll also expand if we've - // reached the end of the history buffer and the average of all entries - // is still over the threshold. This indicates a smaller number of GCs were - // long enough to make the average exceed the threshold. - bool filled_history_buffer = _pauses_since_start == NumPrevPausesForHeuristics; - if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) || - (filled_history_buffer && (recent_gc_overhead > threshold))) { - size_t min_expand_bytes = HeapRegion::GrainBytes; - size_t reserved_bytes = _g1->max_capacity(); - size_t committed_bytes = _g1->capacity(); - size_t uncommitted_bytes = reserved_bytes - committed_bytes; - size_t expand_bytes_via_pct = - uncommitted_bytes * G1ExpandByPercentOfAvailable / 100; - double scale_factor = 1.0; - - // If the current size is less than 1/4 of the Initial heap size, expand - // by half of the delta between the current and Initial sizes. IE, grow - // back quickly. - // - // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of - // the available expansion space, whichever is smaller, as the base - // expansion size. Then possibly scale this size according to how much the - // threshold has (on average) been exceeded by. If the delta is small - // (less than the StartScaleDownAt value), scale the size down linearly, but - // not by less than MinScaleDownFactor. If the delta is large (greater than - // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor - // times the base size. The scaling will be linear in the range from - // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words, - // ScaleUpRange sets the rate of scaling up. - if (committed_bytes < InitialHeapSize / 4) { - expand_bytes = (InitialHeapSize - committed_bytes) / 2; - } else { - double const MinScaleDownFactor = 0.2; - double const MaxScaleUpFactor = 2; - double const StartScaleDownAt = _gc_overhead_perc; - double const StartScaleUpAt = _gc_overhead_perc * 1.5; - double const ScaleUpRange = _gc_overhead_perc * 2.0; - - double ratio_delta; - if (filled_history_buffer) { - ratio_delta = recent_gc_overhead - threshold; - } else { - ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold; - } - - expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes); - if (ratio_delta < StartScaleDownAt) { - scale_factor = ratio_delta / StartScaleDownAt; - scale_factor = MAX2(scale_factor, MinScaleDownFactor); - } else if (ratio_delta > StartScaleUpAt) { - scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange); - scale_factor = MIN2(scale_factor, MaxScaleUpFactor); - } - } - - log_debug(gc, ergo, heap)("Attempt heap expansion (recent GC overhead higher than threshold after GC) " - "recent GC overhead: %1.2f %% threshold: %1.2f %% uncommitted: " SIZE_FORMAT "B base expansion amount and scale: " SIZE_FORMAT "B (%1.2f%%)", - recent_gc_overhead, threshold, uncommitted_bytes, expand_bytes, scale_factor * 100); - - expand_bytes = static_cast(expand_bytes * scale_factor); - - // Ensure the expansion size is at least the minimum growth amount - // and at most the remaining uncommitted byte size. - expand_bytes = MAX2(expand_bytes, min_expand_bytes); - expand_bytes = MIN2(expand_bytes, uncommitted_bytes); - - clear_ratio_check_data(); - } else { - // An expansion was not triggered. If we've started counting, increment - // the number of checks we've made in the current window. If we've - // reached the end of the window without resizing, clear the counters to - // start again the next time we see a ratio above the threshold. - if (_ratio_over_threshold_count > 0) { - _pauses_since_start++; - if (_pauses_since_start > NumPrevPausesForHeuristics) { - clear_ratio_check_data(); - } - } - } - - return expand_bytes; -} void G1CollectorPolicy::print_yg_surv_rate_info() const { #ifndef PRODUCT @@ -1747,269 +1126,17 @@ void G1CollectorPolicy::decide_on_conc_mark_initiation() { } } -class ParKnownGarbageHRClosure: public HeapRegionClosure { - G1CollectedHeap* _g1h; - CSetChooserParUpdater _cset_updater; - -public: - ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted, - uint chunk_size) : - _g1h(G1CollectedHeap::heap()), - _cset_updater(hrSorted, true /* parallel */, chunk_size) { } - - bool doHeapRegion(HeapRegion* r) { - // Do we have any marking information for this region? - if (r->is_marked()) { - // We will skip any region that's currently used as an old GC - // alloc region (we should not consider those for collection - // before we fill them up). - if (_cset_updater.should_add(r) && !_g1h->is_old_gc_alloc_region(r)) { - _cset_updater.add_region(r); - } - } - return false; - } -}; - -class ParKnownGarbageTask: public AbstractGangTask { - CollectionSetChooser* _hrSorted; - uint _chunk_size; - G1CollectedHeap* _g1; - HeapRegionClaimer _hrclaimer; - -public: - ParKnownGarbageTask(CollectionSetChooser* hrSorted, uint chunk_size, uint n_workers) : - AbstractGangTask("ParKnownGarbageTask"), - _hrSorted(hrSorted), _chunk_size(chunk_size), - _g1(G1CollectedHeap::heap()), _hrclaimer(n_workers) {} - - void work(uint worker_id) { - ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size); - _g1->heap_region_par_iterate(&parKnownGarbageCl, worker_id, &_hrclaimer); - } -}; - -uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const { - assert(n_workers > 0, "Active gc workers should be greater than 0"); - const uint overpartition_factor = 4; - const uint min_chunk_size = MAX2(n_regions / n_workers, 1U); - return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size); -} - void G1CollectorPolicy::record_concurrent_mark_cleanup_end() { - cset_chooser()->clear(); - - WorkGang* workers = _g1->workers(); - uint n_workers = workers->active_workers(); - - uint n_regions = _g1->num_regions(); - uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions); - cset_chooser()->prepare_for_par_region_addition(n_workers, n_regions, chunk_size); - ParKnownGarbageTask par_known_garbage_task(cset_chooser(), chunk_size, n_workers); - workers->run_task(&par_known_garbage_task); - - cset_chooser()->sort_regions(); + cset_chooser()->rebuild(_g1->workers(), _g1->num_regions()); double end_sec = os::elapsedTime(); double elapsed_time_ms = (end_sec - _mark_cleanup_start_sec) * 1000.0; - _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms); - _prev_collection_pause_end_ms += elapsed_time_ms; + _analytics->report_concurrent_mark_cleanup_times_ms(elapsed_time_ms); + _analytics->append_prev_collection_pause_end_ms(elapsed_time_ms); record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); } -// Add the heap region at the head of the non-incremental collection set -void G1CollectorPolicy::add_old_region_to_cset(HeapRegion* hr) { - assert(_inc_cset_build_state == Active, "Precondition"); - assert(hr->is_old(), "the region should be old"); - - assert(!hr->in_collection_set(), "should not already be in the CSet"); - _g1->register_old_region_with_cset(hr); - hr->set_next_in_collection_set(_collection_set); - _collection_set = hr; - _collection_set_bytes_used_before += hr->used(); - size_t rs_length = hr->rem_set()->occupied(); - _recorded_rs_lengths += rs_length; - _old_cset_region_length += 1; -} - -// Initialize the per-collection-set information -void G1CollectorPolicy::start_incremental_cset_building() { - assert(_inc_cset_build_state == Inactive, "Precondition"); - - _inc_cset_head = NULL; - _inc_cset_tail = NULL; - _inc_cset_bytes_used_before = 0; - - _inc_cset_recorded_rs_lengths = 0; - _inc_cset_recorded_rs_lengths_diffs = 0; - _inc_cset_predicted_elapsed_time_ms = 0.0; - _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; - _inc_cset_build_state = Active; -} - -void G1CollectorPolicy::finalize_incremental_cset_building() { - assert(_inc_cset_build_state == Active, "Precondition"); - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); - - // The two "main" fields, _inc_cset_recorded_rs_lengths and - // _inc_cset_predicted_elapsed_time_ms, are updated by the thread - // that adds a new region to the CSet. Further updates by the - // concurrent refinement thread that samples the young RSet lengths - // are accumulated in the *_diffs fields. Here we add the diffs to - // the "main" fields. - - if (_inc_cset_recorded_rs_lengths_diffs >= 0) { - _inc_cset_recorded_rs_lengths += _inc_cset_recorded_rs_lengths_diffs; - } else { - // This is defensive. The diff should in theory be always positive - // as RSets can only grow between GCs. However, given that we - // sample their size concurrently with other threads updating them - // it's possible that we might get the wrong size back, which - // could make the calculations somewhat inaccurate. - size_t diffs = (size_t) (-_inc_cset_recorded_rs_lengths_diffs); - if (_inc_cset_recorded_rs_lengths >= diffs) { - _inc_cset_recorded_rs_lengths -= diffs; - } else { - _inc_cset_recorded_rs_lengths = 0; - } - } - _inc_cset_predicted_elapsed_time_ms += - _inc_cset_predicted_elapsed_time_ms_diffs; - - _inc_cset_recorded_rs_lengths_diffs = 0; - _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; -} - -void G1CollectorPolicy::add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length) { - // This routine is used when: - // * adding survivor regions to the incremental cset at the end of an - // evacuation pause, - // * adding the current allocation region to the incremental cset - // when it is retired, and - // * updating existing policy information for a region in the - // incremental cset via young list RSet sampling. - // Therefore this routine may be called at a safepoint by the - // VM thread, or in-between safepoints by mutator threads (when - // retiring the current allocation region) or a concurrent - // refine thread (RSet sampling). - - double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); - size_t used_bytes = hr->used(); - _inc_cset_recorded_rs_lengths += rs_length; - _inc_cset_predicted_elapsed_time_ms += region_elapsed_time_ms; - _inc_cset_bytes_used_before += used_bytes; - - // Cache the values we have added to the aggregated information - // in the heap region in case we have to remove this region from - // the incremental collection set, or it is updated by the - // rset sampling code - hr->set_recorded_rs_length(rs_length); - hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); -} - -void G1CollectorPolicy::update_incremental_cset_info(HeapRegion* hr, - size_t new_rs_length) { - // Update the CSet information that is dependent on the new RS length - assert(hr->is_young(), "Precondition"); - assert(!SafepointSynchronize::is_at_safepoint(), - "should not be at a safepoint"); - - // We could have updated _inc_cset_recorded_rs_lengths and - // _inc_cset_predicted_elapsed_time_ms directly but we'd need to do - // that atomically, as this code is executed by a concurrent - // refinement thread, potentially concurrently with a mutator thread - // allocating a new region and also updating the same fields. To - // avoid the atomic operations we accumulate these updates on two - // separate fields (*_diffs) and we'll just add them to the "main" - // fields at the start of a GC. - - ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); - ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length; - _inc_cset_recorded_rs_lengths_diffs += rs_lengths_diff; - - double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); - double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); - double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; - _inc_cset_predicted_elapsed_time_ms_diffs += elapsed_ms_diff; - - hr->set_recorded_rs_length(new_rs_length); - hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); -} - -void G1CollectorPolicy::add_region_to_incremental_cset_common(HeapRegion* hr) { - assert(hr->is_young(), "invariant"); - assert(hr->young_index_in_cset() > -1, "should have already been set"); - assert(_inc_cset_build_state == Active, "Precondition"); - - // We need to clear and set the cached recorded/cached collection set - // information in the heap region here (before the region gets added - // to the collection set). An individual heap region's cached values - // are calculated, aggregated with the policy collection set info, - // and cached in the heap region here (initially) and (subsequently) - // by the Young List sampling code. - - size_t rs_length = hr->rem_set()->occupied(); - add_to_incremental_cset_info(hr, rs_length); - - assert(!hr->in_collection_set(), "invariant"); - _g1->register_young_region_with_cset(hr); - assert(hr->next_in_collection_set() == NULL, "invariant"); -} - -// Add the region at the RHS of the incremental cset -void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) { - // We should only ever be appending survivors at the end of a pause - assert(hr->is_survivor(), "Logic"); - - // Do the 'common' stuff - add_region_to_incremental_cset_common(hr); - - // Now add the region at the right hand side - if (_inc_cset_tail == NULL) { - assert(_inc_cset_head == NULL, "invariant"); - _inc_cset_head = hr; - } else { - _inc_cset_tail->set_next_in_collection_set(hr); - } - _inc_cset_tail = hr; -} - -// Add the region to the LHS of the incremental cset -void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) { - // Survivors should be added to the RHS at the end of a pause - assert(hr->is_eden(), "Logic"); - - // Do the 'common' stuff - add_region_to_incremental_cset_common(hr); - - // Add the region at the left hand side - hr->set_next_in_collection_set(_inc_cset_head); - if (_inc_cset_head == NULL) { - assert(_inc_cset_tail == NULL, "Invariant"); - _inc_cset_tail = hr; - } - _inc_cset_head = hr; -} - -#ifndef PRODUCT -void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream* st) { - assert(list_head == inc_cset_head() || list_head == collection_set(), "must be"); - - st->print_cr("\nCollection_set:"); - HeapRegion* csr = list_head; - while (csr != NULL) { - HeapRegion* next = csr->next_in_collection_set(); - assert(csr->in_collection_set(), "bad CS"); - st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d", - HR_FORMAT_PARAMS(csr), - p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()), - csr->age_in_surv_rate_group_cond()); - csr = next; - } -} -#endif // !PRODUCT - double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { // Returns the given amount of reclaimable bytes (that represents // the amount of reclaimable space still to be collected) as a @@ -2139,161 +1266,7 @@ uint G1CollectorPolicy::calc_max_old_cset_length() const { return (uint) result; } - -double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) { - double young_start_time_sec = os::elapsedTime(); - - YoungList* young_list = _g1->young_list(); - finalize_incremental_cset_building(); - - guarantee(target_pause_time_ms > 0.0, - "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); - guarantee(_collection_set == NULL, "Precondition"); - - double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); - double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); - - log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms", - _pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); - - collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young()); - - // The young list is laid with the survivor regions from the previous - // pause are appended to the RHS of the young list, i.e. - // [Newly Young Regions ++ Survivors from last pause]. - - uint survivor_region_length = young_list->survivor_length(); - uint eden_region_length = young_list->eden_length(); - init_cset_region_lengths(eden_region_length, survivor_region_length); - - HeapRegion* hr = young_list->first_survivor_region(); - while (hr != NULL) { - assert(hr->is_survivor(), "badly formed young list"); - // There is a convention that all the young regions in the CSet - // are tagged as "eden", so we do this for the survivors here. We - // use the special set_eden_pre_gc() as it doesn't check that the - // region is free (which is not the case here). - hr->set_eden_pre_gc(); - hr = hr->get_next_young_region(); - } - - // Clear the fields that point to the survivor list - they are all young now. - young_list->clear_survivors(); - - _collection_set = _inc_cset_head; - _collection_set_bytes_used_before = _inc_cset_bytes_used_before; - time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0); - - log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms", - eden_region_length, survivor_region_length, _inc_cset_predicted_elapsed_time_ms, target_pause_time_ms); - - // The number of recorded young regions is the incremental - // collection set's current size - set_recorded_rs_lengths(_inc_cset_recorded_rs_lengths); - - double young_end_time_sec = os::elapsedTime(); - phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0); - - return time_remaining_ms; -} - -void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { - double non_young_start_time_sec = os::elapsedTime(); - double predicted_old_time_ms = 0.0; - - - if (!collector_state()->gcs_are_young()) { - cset_chooser()->verify(); - const uint min_old_cset_length = calc_min_old_cset_length(); - const uint max_old_cset_length = calc_max_old_cset_length(); - - uint expensive_region_num = 0; - bool check_time_remaining = adaptive_young_list_length(); - - HeapRegion* hr = cset_chooser()->peek(); - while (hr != NULL) { - if (old_cset_region_length() >= max_old_cset_length) { - // Added maximum number of old regions to the CSet. - log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions", - old_cset_region_length(), max_old_cset_length); - break; - } - - - // Stop adding regions if the remaining reclaimable space is - // not above G1HeapWastePercent. - size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); - double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); - double threshold = (double) G1HeapWastePercent; - if (reclaimable_perc <= threshold) { - // We've added enough old regions that the amount of uncollected - // reclaimable space is at or below the waste threshold. Stop - // adding old regions to the CSet. - log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " - "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%", - old_cset_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); - break; - } - - double predicted_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); - if (check_time_remaining) { - if (predicted_time_ms > time_remaining_ms) { - // Too expensive for the current CSet. - - if (old_cset_region_length() >= min_old_cset_length) { - // We have added the minimum number of old regions to the CSet, - // we are done with this CSet. - log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). " - "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions", - predicted_time_ms, time_remaining_ms, old_cset_region_length(), min_old_cset_length); - break; - } - - // We'll add it anyway given that we haven't reached the - // minimum number of old regions. - expensive_region_num += 1; - } - } else { - if (old_cset_region_length() >= min_old_cset_length) { - // In the non-auto-tuning case, we'll finish adding regions - // to the CSet if we reach the minimum. - - log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions", - old_cset_region_length(), min_old_cset_length); - break; - } - } - - // We will add this region to the CSet. - time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - predicted_old_time_ms += predicted_time_ms; - cset_chooser()->pop(); // already have region via peek() - _g1->old_set_remove(hr); - add_old_region_to_cset(hr); - - hr = cset_chooser()->peek(); - } - if (hr == NULL) { - log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); - } - - if (expensive_region_num > 0) { - // We print the information once here at the end, predicated on - // whether we added any apparently expensive regions or not, to - // avoid generating output per region. - log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)." - "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms", - old_cset_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms); - } - - cset_chooser()->verify(); - } - - stop_incremental_cset_building(); - - log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f", - old_cset_region_length(), predicted_old_time_ms, time_remaining_ms); - - double non_young_end_time_sec = os::elapsedTime(); - phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); +void G1CollectorPolicy::finalize_collection_set(double target_pause_time_ms) { + double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms); + _collection_set->finalize_old_part(time_remaining_ms); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index 6db53e64119..01396394eb1 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP #define SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP -#include "gc/g1/collectionSetChooser.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1InCSetState.hpp" @@ -41,8 +40,10 @@ // * when to collect. class HeapRegion; +class G1CollectionSet; class CollectionSetChooser; class G1IHOPControl; +class G1Analytics; class G1YoungGenSizer; class G1CollectorPolicy: public CollectorPolicy { @@ -57,30 +58,14 @@ class G1CollectorPolicy: public CollectorPolicy { void report_ihop_statistics(); G1Predictions _predictor; - - double get_new_prediction(TruncatedSeq const* seq) const; - size_t get_new_size_prediction(TruncatedSeq const* seq) const; - + G1Analytics* _analytics; G1MMUTracker* _mmu_tracker; void initialize_alignments(); void initialize_flags(); - CollectionSetChooser* _cset_chooser; - double _full_collection_start_sec; - // These exclude marking times. - TruncatedSeq* _recent_gc_times_ms; - - TruncatedSeq* _concurrent_mark_remark_times_ms; - TruncatedSeq* _concurrent_mark_cleanup_times_ms; - - // Ratio check data for determining if heap growth is necessary. - uint _ratio_over_threshold_count; - double _ratio_over_threshold_sum; - uint _pauses_since_start; - uint _young_list_target_length; uint _young_list_fixed_length; @@ -90,58 +75,14 @@ class G1CollectorPolicy: public CollectorPolicy { SurvRateGroup* _short_lived_surv_rate_group; SurvRateGroup* _survivor_surv_rate_group; - // add here any more surv rate groups - - double _gc_overhead_perc; double _reserve_factor; uint _reserve_regions; - enum PredictionConstants { - TruncatedSeqLength = 10, - NumPrevPausesForHeuristics = 10, - // MinOverThresholdForGrowth must be less than NumPrevPausesForHeuristics, - // representing the minimum number of pause time ratios that exceed - // GCTimeRatio before a heap expansion will be triggered. - MinOverThresholdForGrowth = 4 - }; - - TruncatedSeq* _alloc_rate_ms_seq; - double _prev_collection_pause_end_ms; - - TruncatedSeq* _rs_length_diff_seq; - TruncatedSeq* _cost_per_card_ms_seq; - TruncatedSeq* _cost_scan_hcc_seq; - TruncatedSeq* _young_cards_per_entry_ratio_seq; - TruncatedSeq* _mixed_cards_per_entry_ratio_seq; - TruncatedSeq* _cost_per_entry_ms_seq; - TruncatedSeq* _mixed_cost_per_entry_ms_seq; - TruncatedSeq* _cost_per_byte_ms_seq; - TruncatedSeq* _constant_other_time_ms_seq; - TruncatedSeq* _young_other_cost_per_region_ms_seq; - TruncatedSeq* _non_young_other_cost_per_region_ms_seq; - - TruncatedSeq* _pending_cards_seq; - TruncatedSeq* _rs_lengths_seq; - - TruncatedSeq* _cost_per_byte_ms_during_cm_seq; - G1YoungGenSizer* _young_gen_sizer; - uint _eden_cset_region_length; - uint _survivor_cset_region_length; - uint _old_cset_region_length; - - void init_cset_region_lengths(uint eden_cset_region_length, - uint survivor_cset_region_length); - - uint eden_cset_region_length() const { return _eden_cset_region_length; } - uint survivor_cset_region_length() const { return _survivor_cset_region_length; } - uint old_cset_region_length() const { return _old_cset_region_length; } - uint _free_regions_at_end_of_collection; - size_t _recorded_rs_lengths; size_t _max_rs_lengths; size_t _rs_lengths_prediction; @@ -150,10 +91,6 @@ class G1CollectorPolicy: public CollectorPolicy { bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group); #endif // PRODUCT - void adjust_concurrent_refinement(double update_rs_time, - double update_rs_processed_buffers, - double goal_ms); - double _pause_time_target_ms; size_t _pending_cards; @@ -165,6 +102,7 @@ class G1CollectorPolicy: public CollectorPolicy { G1InitialMarkToMixedTimeTracker _initial_mark_to_mixed; public: const G1Predictions& predictor() const { return _predictor; } + const G1Analytics* analytics() const { return const_cast(_analytics); } // Add the given number of bytes to the total number of allocated bytes in the old gen. void add_bytes_allocated_in_old_since_last_gc(size_t bytes) { _bytes_allocated_in_old_since_last_gc += bytes; } @@ -191,37 +129,6 @@ public: _max_rs_lengths = rs_lengths; } - size_t predict_rs_length_diff() const; - - double predict_alloc_rate_ms() const; - - double predict_cost_per_card_ms() const; - - double predict_scan_hcc_ms() const; - - double predict_rs_update_time_ms(size_t pending_cards) const; - - double predict_young_cards_per_entry_ratio() const; - - double predict_mixed_cards_per_entry_ratio() const; - - size_t predict_young_card_num(size_t rs_length) const; - - size_t predict_non_young_card_num(size_t rs_length) const; - - double predict_rs_scan_time_ms(size_t card_num) const; - - double predict_mixed_rs_scan_time_ms(size_t card_num) const; - - double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const; - - double predict_object_copy_time_ms(size_t bytes_to_copy) const; - - double predict_constant_other_time_ms() const; - - double predict_young_other_time_ms(size_t young_num) const; - - double predict_non_young_other_time_ms(size_t non_young_num) const; double predict_base_elapsed_time_ms(size_t pending_cards) const; double predict_base_elapsed_time_ms(size_t pending_cards, @@ -229,13 +136,6 @@ public: size_t predict_bytes_to_copy(HeapRegion* hr) const; double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const; - void set_recorded_rs_lengths(size_t rs_lengths); - - uint cset_region_length() const { return young_cset_region_length() + - old_cset_region_length(); } - uint young_cset_region_length() const { return eden_cset_region_length() + - survivor_cset_region_length(); } - double predict_survivor_regions_evac_time() const; bool should_update_surv_rate_group_predictors() { @@ -261,10 +161,6 @@ public: return _mmu_tracker->max_gc_time() * 1000.0; } - double predict_remark_time_ms() const; - - double predict_cleanup_time_ms() const; - // Returns an estimate of the survival rate of the region at yg-age // "yg_age". double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const; @@ -274,6 +170,7 @@ public: double accum_yg_surv_rate_pred(int age) const; protected: + G1CollectionSet* _collection_set; virtual double average_time_ms(G1GCPhaseTimes::GCParPhases phase) const; virtual double other_time_ms(double pause_time_ms) const; @@ -281,90 +178,17 @@ protected: double non_young_other_time_ms() const; double constant_other_time_ms(double pause_time_ms) const; - CollectionSetChooser* cset_chooser() const { - return _cset_chooser; - } - + CollectionSetChooser* cset_chooser() const; private: - // Statistics kept per GC stoppage, pause or full. - TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec; - - // Add a new GC of the given duration and end time to the record. - void update_recent_gc_times(double end_time_sec, double elapsed_ms); - - // The head of the list (via "next_in_collection_set()") representing the - // current collection set. Set from the incrementally built collection - // set at the start of the pause. - HeapRegion* _collection_set; - - // The number of bytes in the collection set before the pause. Set from - // the incrementally built collection set at the start of an evacuation - // pause, and incremented in finalize_old_cset_part() when adding old regions - // (if any) to the collection set. - size_t _collection_set_bytes_used_before; // The number of bytes copied during the GC. size_t _bytes_copied_during_gc; - // The associated information that is maintained while the incremental - // collection set is being built with young regions. Used to populate - // the recorded info for the evacuation pause. - - enum CSetBuildType { - Active, // We are actively building the collection set - Inactive // We are not actively building the collection set - }; - - CSetBuildType _inc_cset_build_state; - - // The head of the incrementally built collection set. - HeapRegion* _inc_cset_head; - - // The tail of the incrementally built collection set. - HeapRegion* _inc_cset_tail; - - // The number of bytes in the incrementally built collection set. - // Used to set _collection_set_bytes_used_before at the start of - // an evacuation pause. - size_t _inc_cset_bytes_used_before; - - // The RSet lengths recorded for regions in the CSet. It is updated - // by the thread that adds a new region to the CSet. We assume that - // only one thread can be allocating a new CSet region (currently, - // it does so after taking the Heap_lock) hence no need to - // synchronize updates to this field. - size_t _inc_cset_recorded_rs_lengths; - - // A concurrent refinement thread periodically samples the young - // region RSets and needs to update _inc_cset_recorded_rs_lengths as - // the RSets grow. Instead of having to synchronize updates to that - // field we accumulate them in this field and add it to - // _inc_cset_recorded_rs_lengths_diffs at the start of a GC. - ssize_t _inc_cset_recorded_rs_lengths_diffs; - - // The predicted elapsed time it will take to collect the regions in - // the CSet. This is updated by the thread that adds a new region to - // the CSet. See the comment for _inc_cset_recorded_rs_lengths about - // MT-safety assumptions. - double _inc_cset_predicted_elapsed_time_ms; - - // See the comment for _inc_cset_recorded_rs_lengths_diffs. - double _inc_cset_predicted_elapsed_time_ms_diffs; - // Stash a pointer to the g1 heap. G1CollectedHeap* _g1; G1GCPhaseTimes* _phase_times; - // The ratio of gc time to elapsed time, computed over recent pauses, - // and the ratio for just the last pause. - double _recent_avg_pause_time_ratio; - double _last_pause_time_ratio; - - double recent_avg_pause_time_ratio() const { - return _recent_avg_pause_time_ratio; - } - // This set of variables tracks the collector efficiency, in order to // determine whether we should initiate a new marking. double _mark_remark_start_sec; @@ -412,10 +236,6 @@ private: void update_rs_lengths_prediction(); void update_rs_lengths_prediction(size_t prediction); - // Calculate and return chunk size (in number of regions) for parallel - // concurrent mark cleanup. - uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const; - // Check whether a given young length (young_length) fits into the // given target pause time and whether the prediction for the amount // of objects to be copied for the given length will fit into the @@ -424,6 +244,9 @@ private: bool predict_will_fit(uint young_length, double base_time_ms, uint base_free_regions, double target_pause_time_ms) const; +public: + size_t pending_cards() const { return _pending_cards; } + // Calculate the minimum number of old regions we'll add to the CSet // during a mixed GC. uint calc_min_old_cset_length() const; @@ -436,6 +259,7 @@ private: // as a percentage of the current heap capacity. double reclaimable_bytes_perc(size_t reclaimable_bytes) const; +private: // Sets up marking if proper conditions are met. void maybe_start_marking(); @@ -478,7 +302,7 @@ public: void init(); - virtual void note_gc_start(uint num_active_workers); + virtual void note_gc_start(); // Create jstat counters for the policy. virtual void initialize_gc_policy_counters(); @@ -520,83 +344,20 @@ public: return _bytes_copied_during_gc; } - size_t collection_set_bytes_used_before() const { - return _collection_set_bytes_used_before; - } - // Determine whether there are candidate regions so that the // next GC should be mixed. The two action strings are used // in the ergo output when the method returns true or false. bool next_gc_should_be_mixed(const char* true_action_str, const char* false_action_str) const; - // Choose a new collection set. Marks the chosen regions as being - // "in_collection_set", and links them together. The head and number of - // the collection set are available via access methods. - double finalize_young_cset_part(double target_pause_time_ms); - virtual void finalize_old_cset_part(double time_remaining_ms); - - // The head of the list (via "next_in_collection_set()") representing the - // current collection set. - HeapRegion* collection_set() { return _collection_set; } - - void clear_collection_set() { _collection_set = NULL; } - - // Add old region "hr" to the CSet. - void add_old_region_to_cset(HeapRegion* hr); - - // Incremental CSet Support - - // The head of the incrementally built collection set. - HeapRegion* inc_cset_head() { return _inc_cset_head; } - - // The tail of the incrementally built collection set. - HeapRegion* inc_set_tail() { return _inc_cset_tail; } - - // Initialize incremental collection set info. - void start_incremental_cset_building(); - - // Perform any final calculations on the incremental CSet fields - // before we can use them. - void finalize_incremental_cset_building(); - - void clear_incremental_cset() { - _inc_cset_head = NULL; - _inc_cset_tail = NULL; - } - - // Stop adding regions to the incremental collection set - void stop_incremental_cset_building() { _inc_cset_build_state = Inactive; } - - // Add information about hr to the aggregated information for the - // incrementally built collection set. - void add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length); - - // Update information about hr in the aggregated information for - // the incrementally built collection set. - void update_incremental_cset_info(HeapRegion* hr, size_t new_rs_length); - + virtual void finalize_collection_set(double target_pause_time_ms); private: - // Update the incremental cset information when adding a region - // (should not be called directly). - void add_region_to_incremental_cset_common(HeapRegion* hr); - // Set the state to start a concurrent marking cycle and clear // _initiate_conc_mark_if_possible because it has now been // acted on. void initiate_conc_mark(); public: - // Add hr to the LHS of the incremental collection set. - void add_region_to_incremental_cset_lhs(HeapRegion* hr); - - // Add hr to the RHS of the incremental collection set. - void add_region_to_incremental_cset_rhs(HeapRegion* hr); - -#ifndef PRODUCT - void print_collection_set(HeapRegion* list_head, outputStream* st); -#endif // !PRODUCT - // This sets the initiate_conc_mark_if_possible() flag to start a // new cycle, as long as we are not already in one. It's best if it // is called during a safepoint when the test whether a cycle is in @@ -611,13 +372,6 @@ public: // the initial-mark work and start a marking cycle. void decide_on_conc_mark_initiation(); - // If an expansion would be appropriate, because recent GC overhead had - // exceeded the desired limit, return an amount to expand by. - virtual size_t expansion_amount(); - - // Clear ratio tracking data used by expansion_amount(). - void clear_ratio_check_data(); - // Print stats on young survival ratio void print_yg_surv_rate_info() const; @@ -627,7 +381,6 @@ public: } else { _short_lived_surv_rate_group->finished_recalculating_age_indexes(); } - // do that for any other surv rate groups } size_t young_list_target_length() const { return _young_list_target_length; } @@ -658,16 +411,6 @@ private: // The limit on the number of regions allocated for survivors. uint _max_survivor_regions; - // For reporting purposes. - // The value of _heap_bytes_before_gc is also used to calculate - // the cost of copying. - - // The amount of survivor regions after a collection. - uint _recorded_survivor_regions; - // List of survivor regions. - HeapRegion* _recorded_survivor_head; - HeapRegion* _recorded_survivor_tail; - AgeTable _survivors_age_table; public: @@ -677,22 +420,6 @@ public: return _max_survivor_regions; } - static const uint REGIONS_UNLIMITED = (uint) -1; - - uint max_regions(InCSetState dest) const { - switch (dest.value()) { - case InCSetState::Young: - return _max_survivor_regions; - case InCSetState::Old: - return REGIONS_UNLIMITED; - default: - assert(false, "Unknown dest state: " CSETSTATE_FORMAT, dest.value()); - break; - } - // keep some compilers happy - return 0; - } - void note_start_adding_survivor_regions() { _survivor_surv_rate_group->start_adding_regions(); } @@ -701,18 +428,6 @@ public: _survivor_surv_rate_group->stop_adding_regions(); } - void record_survivor_regions(uint regions, - HeapRegion* head, - HeapRegion* tail) { - _recorded_survivor_regions = regions; - _recorded_survivor_head = head; - _recorded_survivor_tail = tail; - } - - uint recorded_survivor_regions() const { - return _recorded_survivor_regions; - } - void record_age_table(AgeTable* age_table) { _survivors_age_table.merge(age_table); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp index ed83b5f9639..c0d1054c721 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,9 @@ #ifndef SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP #define SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP -#include "utilities/globalDefinitions.hpp" #include "gc/g1/g1YCTypes.hpp" +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" // Various state variables that indicate // the phase of the G1 collection. @@ -71,7 +72,6 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { bool _in_marking_window; bool _in_marking_window_im; - bool _concurrent_cycle_started; bool _full_collection; public: @@ -87,7 +87,6 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { _mark_in_progress(false), _in_marking_window(false), _in_marking_window_im(false), - _concurrent_cycle_started(false), _full_collection(false) {} // Setters @@ -100,7 +99,6 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { void set_mark_in_progress(bool v) { _mark_in_progress = v; } void set_in_marking_window(bool v) { _in_marking_window = v; } void set_in_marking_window_im(bool v) { _in_marking_window_im = v; } - void set_concurrent_cycle_started(bool v) { _concurrent_cycle_started = v; } void set_full_collection(bool v) { _full_collection = v; } // Getters @@ -113,7 +111,6 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { bool mark_in_progress() const { return _mark_in_progress; } bool in_marking_window() const { return _in_marking_window; } bool in_marking_window_im() const { return _in_marking_window_im; } - bool concurrent_cycle_started() const { return _concurrent_cycle_started; } bool full_collection() const { return _full_collection; } // Composite booleans (clients worry about flickering) diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index fa8ae83c351..2ed3dd0f4ed 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -120,74 +120,10 @@ void G1CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_r } // We need to clear the bitmap on commit, removing any existing information. MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords); - _bm->clearRange(mr); + _bm->clear_range(mr); } -// Closure used for clearing the given mark bitmap. -class ClearBitmapHRClosure : public HeapRegionClosure { - private: - G1ConcurrentMark* _cm; - G1CMBitMap* _bitmap; - bool _may_yield; // The closure may yield during iteration. If yielded, abort the iteration. - public: - ClearBitmapHRClosure(G1ConcurrentMark* cm, G1CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) { - assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield."); - } - - virtual bool doHeapRegion(HeapRegion* r) { - size_t const chunk_size_in_words = M / HeapWordSize; - - HeapWord* cur = r->bottom(); - HeapWord* const end = r->end(); - - while (cur < end) { - MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end)); - _bitmap->clearRange(mr); - - cur += chunk_size_in_words; - - // Abort iteration if after yielding the marking has been aborted. - if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) { - return true; - } - // Repeat the asserts from before the start of the closure. We will do them - // as asserts here to minimize their overhead on the product. However, we - // will have them as guarantees at the beginning / end of the bitmap - // clearing to get some checking in the product. - assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant"); - assert(!_may_yield || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant"); - } - - return false; - } -}; - -class ParClearNextMarkBitmapTask : public AbstractGangTask { - ClearBitmapHRClosure* _cl; - HeapRegionClaimer _hrclaimer; - bool _suspendible; // If the task is suspendible, workers must join the STS. - -public: - ParClearNextMarkBitmapTask(ClearBitmapHRClosure *cl, uint n_workers, bool suspendible) : - _cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {} - - void work(uint worker_id) { - SuspendibleThreadSetJoiner sts_join(_suspendible); - G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer, true); - } -}; - -void G1CMBitMap::clearAll() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - ClearBitmapHRClosure cl(NULL, this, false /* may_yield */); - uint n_workers = g1h->workers()->active_workers(); - ParClearNextMarkBitmapTask task(&cl, n_workers, false); - g1h->workers()->run_task(&task); - guarantee(cl.complete(), "Must have completed iteration."); - return; -} - -void G1CMBitMap::clearRange(MemRegion mr) { +void G1CMBitMap::clear_range(MemRegion mr) { mr.intersection(MemRegion(_bmStartWord, _bmWordSize)); assert(!mr.is_empty(), "unexpected empty region"); // convert address range into offset range @@ -203,12 +139,12 @@ bool G1CMMarkStack::allocate(size_t capacity) { // allocate a stack of the requisite depth ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop))); if (!rs.is_reserved()) { - warning("ConcurrentMark MarkStack allocation failure"); + log_warning(gc)("ConcurrentMark MarkStack allocation failure"); return false; } MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); if (!_virtual_space.initialize(rs, rs.size())) { - warning("ConcurrentMark MarkStack backing store failure"); + log_warning(gc)("ConcurrentMark MarkStack backing store failure"); // Release the virtual memory reserved for the marking stack rs.release(); return false; @@ -441,7 +377,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* _has_aborted(false), _restart_for_overflow(false), _concurrent_marking_in_progress(false), - _concurrent_phase_status(ConcPhaseNotStarted), + _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()), + _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()), // _verbose_level set below @@ -478,9 +415,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* _root_regions.init(_g1h, this); if (ConcGCThreads > ParallelGCThreads) { - warning("Can't have more ConcGCThreads (%u) " - "than ParallelGCThreads (%u).", - ConcGCThreads, ParallelGCThreads); + log_warning(gc)("Can't have more ConcGCThreads (%u) than ParallelGCThreads (%u).", + ConcGCThreads, ParallelGCThreads); return; } if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) { @@ -534,9 +470,9 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* // Verify that the calculated value for MarkStackSize is in range. // It would be nice to use the private utility routine from Arguments. if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) { - warning("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): " - "must be between 1 and " SIZE_FORMAT, - mark_stack_size, MarkStackSizeMax); + log_warning(gc)("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): " + "must be between 1 and " SIZE_FORMAT, + mark_stack_size, MarkStackSizeMax); return; } FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size); @@ -545,16 +481,16 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* if (FLAG_IS_CMDLINE(MarkStackSize)) { if (FLAG_IS_DEFAULT(MarkStackSizeMax)) { if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) { - warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): " - "must be between 1 and " SIZE_FORMAT, - MarkStackSize, MarkStackSizeMax); + log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): " + "must be between 1 and " SIZE_FORMAT, + MarkStackSize, MarkStackSizeMax); return; } } else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) { if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) { - warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")" - " or for MarkStackSizeMax (" SIZE_FORMAT ")", - MarkStackSize, MarkStackSizeMax); + log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")" + " or for MarkStackSizeMax (" SIZE_FORMAT ")", + MarkStackSize, MarkStackSizeMax); return; } } @@ -562,7 +498,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* } if (!_markStack.allocate(MarkStackSize)) { - warning("Failed to allocate CM marking stack"); + log_warning(gc)("Failed to allocate CM marking stack"); return; } @@ -698,9 +634,76 @@ G1ConcurrentMark::~G1ConcurrentMark() { ShouldNotReachHere(); } -void G1ConcurrentMark::clearNextBitmap() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); +class G1ClearBitMapTask : public AbstractGangTask { + // Heap region closure used for clearing the given mark bitmap. + class G1ClearBitmapHRClosure : public HeapRegionClosure { + private: + G1CMBitMap* _bitmap; + G1ConcurrentMark* _cm; + public: + G1ClearBitmapHRClosure(G1CMBitMap* bitmap, G1ConcurrentMark* cm) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap) { + } + virtual bool doHeapRegion(HeapRegion* r) { + size_t const chunk_size_in_words = M / HeapWordSize; + + HeapWord* cur = r->bottom(); + HeapWord* const end = r->end(); + + while (cur < end) { + MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end)); + _bitmap->clear_range(mr); + + cur += chunk_size_in_words; + + // Abort iteration if after yielding the marking has been aborted. + if (_cm != NULL && _cm->do_yield_check() && _cm->has_aborted()) { + return true; + } + // Repeat the asserts from before the start of the closure. We will do them + // as asserts here to minimize their overhead on the product. However, we + // will have them as guarantees at the beginning / end of the bitmap + // clearing to get some checking in the product. + assert(_cm == NULL || _cm->cmThread()->during_cycle(), "invariant"); + assert(_cm == NULL || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant"); + } + assert(cur == end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index()); + + return false; + } + }; + + G1ClearBitmapHRClosure _cl; + HeapRegionClaimer _hr_claimer; + bool _suspendible; // If the task is suspendible, workers must join the STS. + +public: + G1ClearBitMapTask(G1CMBitMap* bitmap, G1ConcurrentMark* cm, uint n_workers, bool suspendible) : + AbstractGangTask("Parallel Clear Bitmap Task"), + _cl(bitmap, suspendible ? cm : NULL), + _hr_claimer(n_workers), + _suspendible(suspendible) + { } + + void work(uint worker_id) { + SuspendibleThreadSetJoiner sts_join(_suspendible); + G1CollectedHeap::heap()->heap_region_par_iterate(&_cl, worker_id, &_hr_claimer, true); + } + + bool is_complete() { + return _cl.complete(); + } +}; + +void G1ConcurrentMark::clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield) { + assert(may_yield || SafepointSynchronize::is_at_safepoint(), "Non-yielding bitmap clear only allowed at safepoint."); + + G1ClearBitMapTask task(bitmap, this, workers->active_workers(), may_yield); + workers->run_task(&task); + guarantee(!may_yield || task.is_complete(), "Must have completed iteration when not yielding."); +} + +void G1ConcurrentMark::cleanup_for_next_mark() { // Make sure that the concurrent mark thread looks to still be in // the current cycle. guarantee(cmThread()->during_cycle(), "invariant"); @@ -709,21 +712,24 @@ void G1ConcurrentMark::clearNextBitmap() { // marking bitmap and getting it ready for the next cycle. During // this time no other cycle can start. So, let's make sure that this // is the case. - guarantee(!g1h->collector_state()->mark_in_progress(), "invariant"); + guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant"); - ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */); - ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true); - _parallel_workers->run_task(&task); + clear_bitmap(_nextMarkBitMap, _parallel_workers, true); // Clear the liveness counting data. If the marking has been aborted, the abort() // call already did that. - if (cl.complete()) { + if (!has_aborted()) { clear_all_count_data(); } // Repeat the asserts from above. guarantee(cmThread()->during_cycle(), "invariant"); - guarantee(!g1h->collector_state()->mark_in_progress(), "invariant"); + guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant"); +} + +void G1ConcurrentMark::clear_prev_bitmap(WorkGang* workers) { + assert(SafepointSynchronize::is_at_safepoint(), "Should only clear the entire prev bitmap at a safepoint."); + clear_bitmap((G1CMBitMap*)_prevMarkBitMap, workers, false); } class CheckBitmapClearHRClosure : public HeapRegionClosure { @@ -848,7 +854,7 @@ void G1ConcurrentMark::enter_first_sync_barrier(uint worker_id) { // marking. reset_marking_state(true /* clear_overflow */); - log_info(gc)("Concurrent Mark reset for overflow"); + log_info(gc, marking)("Concurrent Mark reset for overflow"); } } @@ -983,13 +989,12 @@ public: } }; -void G1ConcurrentMark::scanRootRegions() { +void G1ConcurrentMark::scan_root_regions() { // scan_in_progress() will have been set to true only if there was // at least one root region to scan. So, if it's false, we // should not attempt to do any further work. if (root_regions()->scan_in_progress()) { assert(!has_aborted(), "Aborting before root region scanning is finished not supported."); - GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan"); _parallel_marking_threads = calc_parallel_marking_threads(); assert(parallel_marking_threads() <= max_parallel_marking_threads(), @@ -1007,47 +1012,27 @@ void G1ConcurrentMark::scanRootRegions() { } } -void G1ConcurrentMark::register_concurrent_phase_start(const char* title) { - uint old_val = 0; - do { - old_val = Atomic::cmpxchg(ConcPhaseStarted, &_concurrent_phase_status, ConcPhaseNotStarted); - } while (old_val != ConcPhaseNotStarted); - _g1h->gc_timer_cm()->register_gc_concurrent_start(title); +void G1ConcurrentMark::concurrent_cycle_start() { + _gc_timer_cm->register_gc_start(); + + _gc_tracer_cm->report_gc_start(GCCause::_no_gc /* first parameter is not used */, _gc_timer_cm->gc_start()); + + _g1h->trace_heap_before_gc(_gc_tracer_cm); } -void G1ConcurrentMark::register_concurrent_phase_end_common(bool end_timer) { - if (_concurrent_phase_status == ConcPhaseNotStarted) { - return; +void G1ConcurrentMark::concurrent_cycle_end() { + _g1h->trace_heap_after_gc(_gc_tracer_cm); + + if (has_aborted()) { + _gc_tracer_cm->report_concurrent_mode_failure(); } - uint old_val = Atomic::cmpxchg(ConcPhaseStopping, &_concurrent_phase_status, ConcPhaseStarted); - if (old_val == ConcPhaseStarted) { - _g1h->gc_timer_cm()->register_gc_concurrent_end(); - // If 'end_timer' is true, we came here to end timer which needs concurrent phase ended. - // We need to end it before changing the status to 'ConcPhaseNotStarted' to prevent - // starting a new concurrent phase by 'ConcurrentMarkThread'. - if (end_timer) { - _g1h->gc_timer_cm()->register_gc_end(); - } - old_val = Atomic::cmpxchg(ConcPhaseNotStarted, &_concurrent_phase_status, ConcPhaseStopping); - assert(old_val == ConcPhaseStopping, "Should not have changed since we entered this scope."); - } else { - do { - // Let other thread finish changing '_concurrent_phase_status' to 'ConcPhaseNotStarted'. - os::naked_short_sleep(1); - } while (_concurrent_phase_status != ConcPhaseNotStarted); - } + _gc_timer_cm->register_gc_end(); + + _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); } -void G1ConcurrentMark::register_concurrent_phase_end() { - register_concurrent_phase_end_common(false); -} - -void G1ConcurrentMark::register_concurrent_gc_end_and_stop_timer() { - register_concurrent_phase_end_common(true); -} - -void G1ConcurrentMark::markFromRoots() { +void G1ConcurrentMark::mark_from_roots() { // we might be tempted to assert that: // assert(asynch == !SafepointSynchronize::is_at_safepoint(), // "inconsistent argument?"); @@ -1110,7 +1095,6 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (has_overflown()) { // Oops. We overflowed. Restart concurrent marking. _restart_for_overflow = true; - log_develop_trace(gc)("Remark led to restart for overflow."); // Verify the heap w.r.t. the previous marking bitmap. if (VerifyDuringGC) { @@ -1124,7 +1108,7 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { reset_marking_state(); } else { { - GCTraceTime(Debug, gc) trace("Aggregate Data", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc, phases) trace("Aggregate Data", _gc_timer_cm); // Aggregate the per-task counting data that we have accumulated // while marking. @@ -1163,7 +1147,7 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { g1p->record_concurrent_mark_remark_end(); G1CMIsAliveClosure is_alive(g1h); - g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive); + _gc_tracer_cm->report_object_count_after_gc(&is_alive); } // Base class of the closures that finalize and verify the @@ -1752,11 +1736,9 @@ void G1ConcurrentMark::cleanup() { // sure we update the old gen/space data. g1h->g1mm()->update_sizes(); g1h->allocation_context_stats().update_after_mark(); - - g1h->trace_heap_after_concurrent_cycle(); } -void G1ConcurrentMark::completeCleanup() { +void G1ConcurrentMark::complete_cleanup() { if (has_aborted()) return; G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -2045,7 +2027,7 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // Inner scope to exclude the cleaning of the string and symbol // tables from the displayed time. { - GCTraceTime(Debug, gc) trace("Reference Processing", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc, phases) trace("Reference Processing", _gc_timer_cm); ReferenceProcessor* rp = g1h->ref_processor_cm(); @@ -2102,8 +2084,8 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { &g1_keep_alive, &g1_drain_mark_stack, executor, - g1h->gc_timer_cm()); - g1h->gc_tracer_cm()->report_gc_reference_stats(stats); + _gc_timer_cm); + _gc_tracer_cm->report_gc_reference_stats(stats); // The do_oop work routines of the keep_alive and drain_marking_stack // oop closures will set the has_overflown flag if we overflow the @@ -2134,28 +2116,24 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(_markStack.isEmpty(), "Marking should have completed"); // Unload Klasses, String, Symbols, Code Cache, etc. - { - GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm()); + if (ClassUnloadingWithConcurrentMark) { + bool purged_classes; - if (ClassUnloadingWithConcurrentMark) { - bool purged_classes; - - { - GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm()); - purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */); - } - - { - GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm()); - weakRefsWorkParallelPart(&g1_is_alive, purged_classes); - } + { + GCTraceTime(Debug, gc, phases) trace("System Dictionary Unloading", _gc_timer_cm); + purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */); } - if (G1StringDedup::is_enabled()) { - GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm()); - G1StringDedup::unlink(&g1_is_alive); + { + GCTraceTime(Debug, gc, phases) trace("Parallel Unloading", _gc_timer_cm); + weakRefsWorkParallelPart(&g1_is_alive, purged_classes); } } + + if (G1StringDedup::is_enabled()) { + GCTraceTime(Debug, gc, phases) trace("String Deduplication Unlink", _gc_timer_cm); + G1StringDedup::unlink(&g1_is_alive); + } } void G1ConcurrentMark::swapMarkBitMaps() { @@ -2273,7 +2251,7 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { HandleMark hm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc, phases) trace("Finalize Marking", _gc_timer_cm); g1h->ensure_parsability(false); @@ -2308,7 +2286,7 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { void G1ConcurrentMark::clearRangePrevBitmap(MemRegion mr) { // Note we are overriding the read-only view of the prev map here, via // the cast. - ((G1CMBitMap*)_prevMarkBitMap)->clearRange(mr); + ((G1CMBitMap*)_prevMarkBitMap)->clear_range(mr); } HeapRegion* @@ -2605,7 +2583,7 @@ void G1ConcurrentMark::abort() { // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next // concurrent bitmap clearing. - _nextMarkBitMap->clearAll(); + clear_bitmap(_nextMarkBitMap, _g1h->workers(), false); // Note we cannot clear the previous marking bitmap here // since VerifyDuringGC verifies the objects marked during @@ -2629,10 +2607,6 @@ void G1ConcurrentMark::abort() { satb_mq_set.set_active_all_threads( false, /* new active value */ satb_mq_set.is_active() /* expected_active */); - - _g1h->trace_heap_after_concurrent_cycle(); - - _g1h->register_concurrent_cycle_end(); } static void print_ms_time_info(const char* prefix, const char* name, @@ -2646,7 +2620,7 @@ static void print_ms_time_info(const char* prefix, const char* name, } void G1ConcurrentMark::print_summary_info() { - LogHandle(gc, marking) log; + Log(gc, marking) log; if (!log.is_trace()) { return; } @@ -3554,8 +3528,6 @@ G1PrintRegionLivenessInfoClosure:: G1PrintRegionLivenessInfoClosure(const char* phase_name) : _total_used_bytes(0), _total_capacity_bytes(0), _total_prev_live_bytes(0), _total_next_live_bytes(0), - _hum_used_bytes(0), _hum_capacity_bytes(0), - _hum_prev_live_bytes(0), _hum_next_live_bytes(0), _total_remset_bytes(0), _total_strong_code_roots_bytes(0) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); MemRegion g1_reserved = g1h->g1_reserved(); @@ -3595,36 +3567,6 @@ G1PrintRegionLivenessInfoClosure(const char* phase_name) "(bytes)", "(bytes)"); } -// It takes as a parameter a reference to one of the _hum_* fields, it -// deduces the corresponding value for a region in a humongous region -// series (either the region size, or what's left if the _hum_* field -// is < the region size), and updates the _hum_* field accordingly. -size_t G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* hum_bytes) { - size_t bytes = 0; - // The > 0 check is to deal with the prev and next live bytes which - // could be 0. - if (*hum_bytes > 0) { - bytes = MIN2(HeapRegion::GrainBytes, *hum_bytes); - *hum_bytes -= bytes; - } - return bytes; -} - -// It deduces the values for a region in a humongous region series -// from the _hum_* fields and updates those accordingly. It assumes -// that that _hum_* fields have already been set up from the "starts -// humongous" region and we visit the regions in address order. -void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes, - size_t* capacity_bytes, - size_t* prev_live_bytes, - size_t* next_live_bytes) { - assert(_hum_used_bytes > 0 && _hum_capacity_bytes > 0, "pre-condition"); - *used_bytes = get_hum_bytes(&_hum_used_bytes); - *capacity_bytes = get_hum_bytes(&_hum_capacity_bytes); - *prev_live_bytes = get_hum_bytes(&_hum_prev_live_bytes); - *next_live_bytes = get_hum_bytes(&_hum_next_live_bytes); -} - bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { const char* type = r->get_type_str(); HeapWord* bottom = r->bottom(); @@ -3637,24 +3579,6 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size(); - if (r->is_starts_humongous()) { - assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 && - _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0, - "they should have been zeroed after the last time we used them"); - // Set up the _hum_* fields. - _hum_capacity_bytes = capacity_bytes; - _hum_used_bytes = used_bytes; - _hum_prev_live_bytes = prev_live_bytes; - _hum_next_live_bytes = next_live_bytes; - get_hum_bytes(&used_bytes, &capacity_bytes, - &prev_live_bytes, &next_live_bytes); - end = bottom + HeapRegion::GrainWords; - } else if (r->is_continues_humongous()) { - get_hum_bytes(&used_bytes, &capacity_bytes, - &prev_live_bytes, &next_live_bytes); - assert(end == bottom + HeapRegion::GrainWords, "invariant"); - } - _total_used_bytes += used_bytes; _total_capacity_bytes += capacity_bytes; _total_prev_live_bytes += prev_live_bytes; diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp index 9e1730d95d7..1608c81f96f 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp @@ -34,6 +34,8 @@ class G1CollectedHeap; class G1CMBitMap; class G1CMTask; class G1ConcurrentMark; +class ConcurrentGCTimer; +class G1OldTracer; typedef GenericTaskQueue G1CMTaskQueue; typedef GenericTaskQueueSet G1CMTaskQueueSet; @@ -139,10 +141,7 @@ class G1CMBitMap : public G1CMBitMapRO { inline void clear(HeapWord* addr); inline bool parMark(HeapWord* addr); - void clearRange(MemRegion mr); - - // Clear the whole mark bitmap. - void clearAll(); + void clear_range(MemRegion mr); }; // Represents a marking stack used by ConcurrentMarking in the G1 collector. @@ -352,17 +351,9 @@ protected: // time of remark. volatile bool _concurrent_marking_in_progress; - // There would be a race between ConcurrentMarkThread and VMThread(ConcurrentMark::abort()) - // to call ConcurrentGCTimer::register_gc_concurrent_end(). - // And this variable is used to keep track of concurrent phase. - volatile uint _concurrent_phase_status; - // Concurrent phase is not yet started. - static const uint ConcPhaseNotStarted = 0; - // Concurrent phase is started. - static const uint ConcPhaseStarted = 1; - // Caller thread of ConcurrentGCTimer::register_gc_concurrent_end() is ending concurrent phase. - // So other thread should wait until the status to be changed to ConcPhaseNotStarted. - static const uint ConcPhaseStopping = 2; + ConcurrentGCTimer* _gc_timer_cm; + + G1OldTracer* _gc_tracer_cm; // All of these times are in ms NumberSeq _init_times; @@ -497,6 +488,9 @@ protected: // end_timer, true to end gc timer after ending concurrent phase. void register_concurrent_phase_end_common(bool end_timer); + // Clear the given bitmap in parallel using the given WorkGang. If may_yield is + // true, periodically insert checks to see if this method should exit prematurely. + void clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield); public: // Manipulation of the global mark stack. // The push and pop operations are used by tasks for transfers @@ -530,10 +524,8 @@ public: _concurrent_marking_in_progress = false; } - void register_concurrent_phase_start(const char* title); - void register_concurrent_phase_end(); - // Ends both concurrent phase and timer. - void register_concurrent_gc_end_and_stop_timer(); + void concurrent_cycle_start(); + void concurrent_cycle_end(); void update_accum_task_vtime(int i, double vtime) { _accum_task_vtime[i] += vtime; @@ -585,8 +577,13 @@ public: uint worker_id, HeapRegion* hr = NULL); - // Clear the next marking bitmap (will be called concurrently). - void clearNextBitmap(); + // Prepare internal data structures for the next mark cycle. This includes clearing + // the next mark bitmap and some internal data structures. This method is intended + // to be called concurrently to the mutator. It will yield to safepoint requests. + void cleanup_for_next_mark(); + + // Clear the previous marking bitmap during safepoint. + void clear_prev_bitmap(WorkGang* workers); // Return whether the next mark bitmap has no marks set. To be used for assertions // only. Will not yield to pause requests. @@ -603,18 +600,18 @@ public: // Scan all the root regions and mark everything reachable from // them. - void scanRootRegions(); + void scan_root_regions(); // Scan a single root region and mark everything reachable from it. void scanRootRegion(HeapRegion* hr, uint worker_id); // Do concurrent phase of marking, to a tentative transitive closure. - void markFromRoots(); + void mark_from_roots(); void checkpointRootsFinal(bool clear_all_soft_refs); void checkpointRootsFinalWork(); void cleanup(); - void completeCleanup(); + void complete_cleanup(); // Mark in the previous bitmap. NB: this is usually read-only, so use // this carefully! @@ -730,6 +727,9 @@ public: return _completed_initialization; } + ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; } + G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; } + protected: // Clear all the per-task bitmaps and arrays used to store the // counting data. @@ -996,18 +996,6 @@ private: size_t _total_prev_live_bytes; size_t _total_next_live_bytes; - // These are set up when we come across a "stars humongous" region - // (as this is where most of this information is stored, not in the - // subsequent "continues humongous" regions). After that, for every - // region in a given humongous region series we deduce the right - // values for it by simply subtracting the appropriate amount from - // these fields. All these values should reach 0 after we've visited - // the last region in the series. - size_t _hum_used_bytes; - size_t _hum_capacity_bytes; - size_t _hum_prev_live_bytes; - size_t _hum_next_live_bytes; - // Accumulator for the remembered set size size_t _total_remset_bytes; @@ -1026,11 +1014,6 @@ private: return (double) val / (double) M; } - // See the .cpp file. - size_t get_hum_bytes(size_t* hum_bytes); - void get_hum_bytes(size_t* used_bytes, size_t* capacity_bytes, - size_t* prev_live_bytes, size_t* next_live_bytes); - public: // The header and footer are printed in the constructor and // destructor respectively. diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index 1cb7384ed46..0a66488f71d 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -110,15 +110,9 @@ void G1EvacStats::adjust_desired_plab_sz() { size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy); // Take historical weighted average _filter.sample(cur_plab_sz); - // Clip from above and below, and align to object boundary - size_t plab_sz; - plab_sz = MAX2(min_size(), (size_t)_filter.average()); - plab_sz = MIN2(max_size(), plab_sz); - plab_sz = align_object_size(plab_sz); - // Latch the result - _desired_net_plab_sz = plab_sz; + _desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average()); - log_sizing(cur_plab_sz, plab_sz); + log_sizing(cur_plab_sz, _desired_net_plab_sz); // Clear accumulators for next round. reset(); } diff --git a/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp index 41b129c2111..75bf9a85861 100644 --- a/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,8 @@ void G1FromCardCache::initialize(uint num_par_rem_sets, uint max_num_regions) { guarantee(_cache == NULL, "Should not call this multiple times"); _max_regions = max_num_regions; - _cache = Padded2DArray::create_unfreeable(num_par_rem_sets, - _max_regions, + _cache = Padded2DArray::create_unfreeable(_max_regions, + num_par_rem_sets, &_static_mem_size); invalidate(0, _max_regions); diff --git a/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp b/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp index 67c8ec65a52..8c0864609ae 100644 --- a/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp +++ b/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,11 @@ // a per-region and per-thread basis. class G1FromCardCache : public AllStatic { private: - // Array of card indices. Indexed by thread X and heap region to minimize + // Array of card indices. Indexed by heap region (rows) and thread (columns) to minimize // thread contention. + // This order minimizes the time to clear all entries for a given region during region + // freeing. I.e. a single clear of a single memory area instead of multiple separate + // accesses with a large stride per region. static int** _cache; static uint _max_regions; static size_t _static_mem_size; @@ -58,11 +61,11 @@ class G1FromCardCache : public AllStatic { } static int at(uint worker_id, uint region_idx) { - return _cache[worker_id][region_idx]; + return _cache[region_idx][worker_id]; } static void set(uint worker_id, uint region_idx, int val) { - _cache[worker_id][region_idx] = val; + _cache[region_idx][worker_id] = val; } static void initialize(uint num_par_rem_sets, uint max_num_regions); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 9ab25e6a73f..bc7b17cef76 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -33,7 +33,7 @@ #include "runtime/timer.hpp" #include "runtime/os.hpp" -static const char* Indents[5] = {"", " ", " ", " ", " "}; +static const char* Indents[5] = {"", " ", " ", " ", " "}; G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _max_gc_threads(max_gc_threads) @@ -94,11 +94,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs (ms):"); } -void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { - assert(active_gc_threads > 0, "The number of threads must be > 0"); - assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads"); +void G1GCPhaseTimes::note_gc_start() { _gc_start_counter = os::elapsed_counter(); - _active_gc_threads = active_gc_threads; _cur_expand_heap_time_ms = 0.0; _external_accounted_time_ms = 0.0; @@ -109,31 +106,55 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { } } +#define ASSERT_PHASE_UNINITIALIZED(phase) \ + assert(_gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started"); + +double G1GCPhaseTimes::worker_time(GCParPhases phase, uint worker) { + double value = _gc_par_phases[phase]->get(worker); + if (value != WorkerDataArray::uninitialized()) { + return value; + } + return 0.0; +} + void G1GCPhaseTimes::note_gc_end() { _gc_pause_time_ms = TimeHelper::counter_to_millis(os::elapsed_counter() - _gc_start_counter); - for (uint i = 0; i < _active_gc_threads; i++) { - double worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i); - record_time_secs(GCWorkerTotal, i , worker_time); - double worker_known_time = - _gc_par_phases[ExtRootScan]->get(i) + - _gc_par_phases[SATBFiltering]->get(i) + - _gc_par_phases[UpdateRS]->get(i) + - _gc_par_phases[ScanRS]->get(i) + - _gc_par_phases[CodeRoots]->get(i) + - _gc_par_phases[ObjCopy]->get(i) + - _gc_par_phases[Termination]->get(i); + double uninitialized = WorkerDataArray::uninitialized(); - record_time_secs(Other, i, worker_time - worker_known_time); - } + for (uint i = 0; i < _max_gc_threads; i++) { + double worker_start = _gc_par_phases[GCWorkerStart]->get(i); + if (worker_start != uninitialized) { + assert(_gc_par_phases[GCWorkerEnd]->get(i) != uninitialized, "Worker started but not ended."); + double total_worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i); + record_time_secs(GCWorkerTotal, i , total_worker_time); - for (int i = 0; i < GCParPhasesSentinel; i++) { - if (_gc_par_phases[i] != NULL) { - _gc_par_phases[i]->verify(_active_gc_threads); + double worker_known_time = + worker_time(ExtRootScan, i) + + worker_time(SATBFiltering, i) + + worker_time(UpdateRS, i) + + worker_time(ScanRS, i) + + worker_time(CodeRoots, i) + + worker_time(ObjCopy, i) + + worker_time(Termination, i); + + record_time_secs(Other, i, total_worker_time - worker_known_time); + } else { + // Make sure all slots are uninitialized since this thread did not seem to have been started + ASSERT_PHASE_UNINITIALIZED(GCWorkerEnd); + ASSERT_PHASE_UNINITIALIZED(ExtRootScan); + ASSERT_PHASE_UNINITIALIZED(SATBFiltering); + ASSERT_PHASE_UNINITIALIZED(UpdateRS); + ASSERT_PHASE_UNINITIALIZED(ScanRS); + ASSERT_PHASE_UNINITIALIZED(CodeRoots); + ASSERT_PHASE_UNINITIALIZED(ObjCopy); + ASSERT_PHASE_UNINITIALIZED(Termination); } } } +#undef ASSERT_PHASE_UNINITIALIZED + // record the time a phase took in seconds void G1GCPhaseTimes::record_time_secs(GCParPhases phase, uint worker_i, double secs) { _gc_par_phases[phase]->set(worker_i, secs); @@ -150,39 +171,39 @@ void G1GCPhaseTimes::record_thread_work_item(GCParPhases phase, uint worker_i, s // return the average time for a phase in milliseconds double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->average(_active_gc_threads) * 1000.0; + return _gc_par_phases[phase]->average() * 1000.0; } size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) { assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->sum(_active_gc_threads); + return _gc_par_phases[phase]->thread_work_items()->sum(); } template void G1GCPhaseTimes::details(T* phase, const char* indent) { - LogHandle(gc, phases, task) log; + Log(gc, phases, task) log; if (log.is_level(LogLevel::Trace)) { outputStream* trace_out = log.trace_stream(); trace_out->print("%s", indent); - phase->print_details_on(trace_out, _active_gc_threads); + phase->print_details_on(trace_out); } } void G1GCPhaseTimes::log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum) { out->print("%s", Indents[indent]); - phase->print_summary_on(out, _active_gc_threads, print_sum); + phase->print_summary_on(out, print_sum); details(phase, Indents[indent]); WorkerDataArray* work_items = phase->thread_work_items(); if (work_items != NULL) { out->print("%s", Indents[indent + 1]); - work_items->print_summary_on(out, _active_gc_threads, true); + work_items->print_summary_on(out, true); details(work_items, Indents[indent + 1]); } } void G1GCPhaseTimes::debug_phase(WorkerDataArray* phase) { - LogHandle(gc, phases) log; + Log(gc, phases) log; if (log.is_level(LogLevel::Debug)) { ResourceMark rm; log_phase(phase, 2, log.debug_stream(), true); @@ -190,7 +211,7 @@ void G1GCPhaseTimes::debug_phase(WorkerDataArray* phase) { } void G1GCPhaseTimes::trace_phase(WorkerDataArray* phase, bool print_sum) { - LogHandle(gc, phases) log; + Log(gc, phases) log; if (log.is_level(LogLevel::Trace)) { ResourceMark rm; log_phase(phase, 3, log.trace_stream(), print_sum); @@ -277,11 +298,11 @@ void G1GCPhaseTimes::print() { } debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); + trace_phase(_gc_par_phases[PreserveCMReferents]); debug_line("Reference Processing", _cur_ref_proc_time_ms); debug_line("Reference Enqueuing", _cur_ref_enq_time_ms); debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms); trace_phase(_gc_par_phases[RedirtyCards]); - trace_phase(_gc_par_phases[PreserveCMReferents]); if (G1EagerReclaimHumongousObjects) { debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index e87075b5e93..88deb79d367 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -32,7 +32,6 @@ class LineBuffer; template class WorkerDataArray; class G1GCPhaseTimes : public CHeapObj { - uint _active_gc_threads; uint _max_gc_threads; jlong _gc_start_counter; double _gc_pause_time_ms; @@ -123,6 +122,7 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; + double worker_time(GCParPhases phase, uint worker); void note_gc_end(); template @@ -133,7 +133,7 @@ class G1GCPhaseTimes : public CHeapObj { public: G1GCPhaseTimes(uint max_gc_threads); - void note_gc_start(uint active_gc_threads); + void note_gc_start(); void print(); // record the time a phase took in seconds diff --git a/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.cpp new file mode 100644 index 00000000000..5fa79c87dfc --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1HeapSizingPolicy.hpp" +#include "gc/g1/g1Analytics.hpp" +#include "logging/log.hpp" +#include "runtime/globals.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +G1HeapSizingPolicy::G1HeapSizingPolicy(const G1CollectedHeap* g1, const G1Analytics* analytics) : + _g1(g1), + _analytics(analytics), + _num_prev_pauses_for_heuristics(analytics->number_of_recorded_pause_times()) { + assert(MinOverThresholdForGrowth < _num_prev_pauses_for_heuristics, "Threshold must be less than %u", _num_prev_pauses_for_heuristics); + clear_ratio_check_data(); + } + +void G1HeapSizingPolicy::clear_ratio_check_data() { + _ratio_over_threshold_count = 0; + _ratio_over_threshold_sum = 0.0; + _pauses_since_start = 0; +} + +size_t G1HeapSizingPolicy::expansion_amount() { + double recent_gc_overhead = _analytics->recent_avg_pause_time_ratio() * 100.0; + double last_gc_overhead = _analytics->last_pause_time_ratio() * 100.0; + assert(GCTimeRatio > 0, + "we should have set it to a default value set_g1_gc_flags() " + "if a user set it to 0"); + const double gc_overhead_perc = 100.0 * (1.0 / (1.0 + GCTimeRatio)); + + double threshold = gc_overhead_perc; + size_t expand_bytes = 0; + + // If the heap is at less than half its maximum size, scale the threshold down, + // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand, + // though the scaling code will likely keep the increase small. + if (_g1->capacity() <= _g1->max_capacity() / 2) { + threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2); + threshold = MAX2(threshold, 1.0); + } + + // If the last GC time ratio is over the threshold, increment the count of + // times it has been exceeded, and add this ratio to the sum of exceeded + // ratios. + if (last_gc_overhead > threshold) { + _ratio_over_threshold_count++; + _ratio_over_threshold_sum += last_gc_overhead; + } + + // Check if we've had enough GC time ratio checks that were over the + // threshold to trigger an expansion. We'll also expand if we've + // reached the end of the history buffer and the average of all entries + // is still over the threshold. This indicates a smaller number of GCs were + // long enough to make the average exceed the threshold. + bool filled_history_buffer = _pauses_since_start == _num_prev_pauses_for_heuristics; + if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) || + (filled_history_buffer && (recent_gc_overhead > threshold))) { + size_t min_expand_bytes = HeapRegion::GrainBytes; + size_t reserved_bytes = _g1->max_capacity(); + size_t committed_bytes = _g1->capacity(); + size_t uncommitted_bytes = reserved_bytes - committed_bytes; + size_t expand_bytes_via_pct = + uncommitted_bytes * G1ExpandByPercentOfAvailable / 100; + double scale_factor = 1.0; + + // If the current size is less than 1/4 of the Initial heap size, expand + // by half of the delta between the current and Initial sizes. IE, grow + // back quickly. + // + // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of + // the available expansion space, whichever is smaller, as the base + // expansion size. Then possibly scale this size according to how much the + // threshold has (on average) been exceeded by. If the delta is small + // (less than the StartScaleDownAt value), scale the size down linearly, but + // not by less than MinScaleDownFactor. If the delta is large (greater than + // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor + // times the base size. The scaling will be linear in the range from + // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words, + // ScaleUpRange sets the rate of scaling up. + if (committed_bytes < InitialHeapSize / 4) { + expand_bytes = (InitialHeapSize - committed_bytes) / 2; + } else { + double const MinScaleDownFactor = 0.2; + double const MaxScaleUpFactor = 2; + double const StartScaleDownAt = gc_overhead_perc; + double const StartScaleUpAt = gc_overhead_perc * 1.5; + double const ScaleUpRange = gc_overhead_perc * 2.0; + + double ratio_delta; + if (filled_history_buffer) { + ratio_delta = recent_gc_overhead - threshold; + } else { + ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold; + } + + expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes); + if (ratio_delta < StartScaleDownAt) { + scale_factor = ratio_delta / StartScaleDownAt; + scale_factor = MAX2(scale_factor, MinScaleDownFactor); + } else if (ratio_delta > StartScaleUpAt) { + scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange); + scale_factor = MIN2(scale_factor, MaxScaleUpFactor); + } + } + + log_debug(gc, ergo, heap)("Attempt heap expansion (recent GC overhead higher than threshold after GC) " + "recent GC overhead: %1.2f %% threshold: %1.2f %% uncommitted: " SIZE_FORMAT "B base expansion amount and scale: " SIZE_FORMAT "B (%1.2f%%)", + recent_gc_overhead, threshold, uncommitted_bytes, expand_bytes, scale_factor * 100); + + expand_bytes = static_cast(expand_bytes * scale_factor); + + // Ensure the expansion size is at least the minimum growth amount + // and at most the remaining uncommitted byte size. + expand_bytes = MAX2(expand_bytes, min_expand_bytes); + expand_bytes = MIN2(expand_bytes, uncommitted_bytes); + + clear_ratio_check_data(); + } else { + // An expansion was not triggered. If we've started counting, increment + // the number of checks we've made in the current window. If we've + // reached the end of the window without resizing, clear the counters to + // start again the next time we see a ratio above the threshold. + if (_ratio_over_threshold_count > 0) { + _pauses_since_start++; + if (_pauses_since_start > _num_prev_pauses_for_heuristics) { + clear_ratio_check_data(); + } + } + } + + return expand_bytes; +} diff --git a/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.hpp new file mode 100644 index 00000000000..8bbf9e7325d --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1HEAPSIZINGPOLICY_HPP +#define SHARE_VM_GC_G1_G1HEAPSIZINGPOLICY_HPP + +#include "memory/allocation.hpp" + +class G1Analytics; +class G1CollectedHeap; + +class G1HeapSizingPolicy: public CHeapObj { + // MinOverThresholdForGrowth must be less than the number of recorded + // pause times in G1Analytics, representing the minimum number of pause + // time ratios that exceed GCTimeRatio before a heap expansion will be triggered. + const static uint MinOverThresholdForGrowth = 4; + + const G1CollectedHeap* _g1; + const G1Analytics* _analytics; + + const uint _num_prev_pauses_for_heuristics; + // Ratio check data for determining if heap growth is necessary. + uint _ratio_over_threshold_count; + double _ratio_over_threshold_sum; + uint _pauses_since_start; + + +protected: + G1HeapSizingPolicy(const G1CollectedHeap* g1, const G1Analytics* analytics); +public: + + // If an expansion would be appropriate, because recent GC overhead had + // exceeded the desired limit, return an amount to expand by. + virtual size_t expansion_amount(); + + // Clear ratio tracking data used by expansion_amount(). + void clear_ratio_check_data(); + + static G1HeapSizingPolicy* create(const G1CollectedHeap* g1, const G1Analytics* analytics); +}; + +#endif // SRC_SHARE_VM_GC_G1_G1HEAPSIZINGPOLICY_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy_ext.cpp b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy_ext.cpp new file mode 100644 index 00000000000..48432568cc0 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy_ext.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1HeapSizingPolicy.hpp" + +G1HeapSizingPolicy* G1HeapSizingPolicy::create(const G1CollectedHeap* g1, const G1Analytics* analytics) { + return new G1HeapSizingPolicy(g1, analytics); +} diff --git a/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp b/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp index 8a74f817794..2d1562ea05a 100644 --- a/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp @@ -82,8 +82,8 @@ public: void G1HeapTransition::print() { Data after(_g1_heap); - size_t eden_capacity_bytes_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length; - size_t survivor_capacity_bytes_after_gc = _g1_heap->g1_policy()->max_survivor_regions(); + size_t eden_capacity_length_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length; + size_t survivor_capacity_length_after_gc = _g1_heap->g1_policy()->max_survivor_regions(); DetailedUsage usage; if (log_is_enabled(Trace, gc, heap)) { @@ -100,11 +100,11 @@ void G1HeapTransition::print() { } log_info(gc, heap)("Eden regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")", - _before._eden_length, after._eden_length, eden_capacity_bytes_after_gc); + _before._eden_length, after._eden_length, eden_capacity_length_after_gc); log_trace(gc, heap)(" Used: 0K, Waste: 0K"); log_info(gc, heap)("Survivor regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")", - _before._survivor_length, after._survivor_length, survivor_capacity_bytes_after_gc); + _before._survivor_length, after._survivor_length, survivor_capacity_length_after_gc); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K); diff --git a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp index 1354b0d1fe8..ddbdfad5f14 100644 --- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp @@ -60,7 +60,7 @@ public: if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); if (_g1h->is_obj_dead_cond(obj, _vo)) { - LogHandle(gc, verify) log; + Log(gc, verify) log; log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj)); if (_vo == VerifyOption_G1UseMarkWord) { log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark())); @@ -406,7 +406,7 @@ void G1HeapVerifier::verify(VerifyOption vo) { // It helps to have the per-region information in the output to // help us track down what went wrong. This is why we call // print_extended_on() instead of print_on(). - LogHandle(gc, verify) log; + Log(gc, verify) log; ResourceMark rm; _g1h->print_extended_on(log.error_stream()); } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp index 013be1a12f8..aae9c94f0f6 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp @@ -36,7 +36,7 @@ void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) { _use_cache = true; _hot_cache_size = (size_t)1 << G1ConcRSLogCacheSize; - _hot_cache = _hot_cache_memory.allocate(_hot_cache_size); + _hot_cache = ArrayAllocator::allocate(_hot_cache_size); reset_hot_cache_internal(); @@ -51,7 +51,7 @@ void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) { G1HotCardCache::~G1HotCardCache() { if (default_use_cache()) { assert(_hot_cache != NULL, "Logic"); - _hot_cache_memory.free(); + ArrayAllocator::free(_hot_cache, _hot_cache_size); _hot_cache = NULL; } } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp index 5ec0fbbcb2a..d53b5b0c769 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp @@ -61,7 +61,6 @@ class G1HotCardCache: public CHeapObj { G1CardCounts _card_counts; - ArrayAllocator _hot_cache_memory; // The card cache table jbyte** _hot_cache; diff --git a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp index 7218472cc3c..80aaad3c79b 100644 --- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp @@ -122,7 +122,7 @@ void G1MarkSweep::allocate_stacks() { void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", gc_timer()); + GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", gc_timer()); G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -137,34 +137,49 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, &follow_code_closure); } - // Process reference objects found during marking - ReferenceProcessor* rp = GenMarkSweep::ref_processor(); - assert(rp == g1h->ref_processor_stw(), "Sanity"); + { + GCTraceTime(Debug, gc, phases) trace("Reference Processing", gc_timer()); - rp->setup_policy(clear_all_softrefs); - const ReferenceProcessorStats& stats = - rp->process_discovered_references(&GenMarkSweep::is_alive, - &GenMarkSweep::keep_alive, - &GenMarkSweep::follow_stack_closure, - NULL, - gc_timer()); - gc_tracer()->report_gc_reference_stats(stats); + // Process reference objects found during marking + ReferenceProcessor* rp = GenMarkSweep::ref_processor(); + assert(rp == g1h->ref_processor_stw(), "Sanity"); + rp->setup_policy(clear_all_softrefs); + const ReferenceProcessorStats& stats = + rp->process_discovered_references(&GenMarkSweep::is_alive, + &GenMarkSweep::keep_alive, + &GenMarkSweep::follow_stack_closure, + NULL, + gc_timer()); + gc_tracer()->report_gc_reference_stats(stats); + } // This is the point where the entire marking should have completed. assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed"); - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); + { + GCTraceTime(Debug, gc, phases) trace("Class Unloading", gc_timer()); - // Unload nmethods. - CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class); + // Unload classes and purge the SystemDictionary. + bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); - // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); + // Unload nmethods. + CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class); - // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. - g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); + } + + { + GCTraceTime(Debug, gc, phases) trace("Scrub String and Symbol Tables", gc_timer()); + // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. + g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); + } + + if (G1StringDedup::is_enabled()) { + GCTraceTime(Debug, gc, phases) trace("String Deduplication Unlink", gc_timer()); + G1StringDedup::unlink(&GenMarkSweep::is_alive); + } if (VerifyDuringGC) { HandleMark hm; // handle scope @@ -197,7 +212,7 @@ void G1MarkSweep::mark_sweep_phase2() { // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", gc_timer()); + GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", gc_timer()); prepare_compaction(); } @@ -220,17 +235,11 @@ class G1AdjustPointersClosure: public HeapRegionClosure { } }; -class G1AlwaysTrueClosure: public BoolObjectClosure { -public: - bool do_object_b(oop p) { return true; } -}; -static G1AlwaysTrueClosure always_true; - void G1MarkSweep::mark_sweep_phase3() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", gc_timer()); + GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer()); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -248,7 +257,7 @@ void G1MarkSweep::mark_sweep_phase3() { // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) - JNIHandles::weak_oops_do(&always_true, &GenMarkSweep::adjust_pointer_closure); + JNIHandles::weak_oops_do(&GenMarkSweep::adjust_pointer_closure); if (G1StringDedup::is_enabled()) { G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); @@ -291,7 +300,7 @@ void G1MarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime(Trace, gc) tm("Phase 4: Move objects", gc_timer()); + GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", gc_timer()); G1SpaceCompactClosure blk; g1h->heap_region_iterate(&blk); diff --git a/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp b/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp index 4be78e3db95..1dcbcc24c36 100644 --- a/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp +++ b/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ void G1MonitoringSupport::recalculate_sizes() { // of a GC). uint young_list_length = g1->young_list()->length(); - uint survivor_list_length = g1->g1_policy()->recorded_survivor_regions(); + uint survivor_list_length = g1->young_list()->survivor_length(); assert(young_list_length >= survivor_list_length, "invariant"); uint eden_list_length = young_list_length - survivor_list_length; // Max length includes any potential extensions to the young gen diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp index 5a9b7f780a4..932bcbbfc4c 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp @@ -176,13 +176,22 @@ inline void G1UpdateRSOrPushRefOopClosure::do_oop_work(T* p) { #endif // ASSERT assert(_from != NULL, "from region must be non-NULL"); - assert(_from->is_in_reserved(p), "p is not in from"); + assert(_from->is_in_reserved(p) || + (_from->is_humongous() && + _g1->heap_region_containing(p)->is_humongous() && + _from->humongous_start_region() == _g1->heap_region_containing(p)->humongous_start_region()), + "p " PTR_FORMAT " is not in the same region %u or part of the correct humongous object starting at region %u.", + p2i(p), _from->hrm_index(), _from->humongous_start_region()->hrm_index()); HeapRegion* to = _g1->heap_region_containing(obj); if (_from == to) { // Normally this closure should only be called with cross-region references. // But since Java threads are manipulating the references concurrently and we // reload the values things may have changed. + // Also this check lets slip through references from a humongous continues region + // to its humongous start region, as they are in different regions, and adds a + // remembered set entry. This is benign (apart from memory usage), as we never + // try to either evacuate or eager reclaim these kind of regions. return; } diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index b59fc203c6c..dc324322ae8 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1RootClosures.hpp" @@ -80,7 +81,7 @@ void G1ParScanThreadState::flush(size_t* surviving_young_words) { _plab_allocator->flush_and_retire_stats(); _g1h->g1_policy()->record_age_table(&_age_table); - uint length = _g1h->g1_policy()->young_cset_region_length(); + uint length = _g1h->collection_set()->young_region_length(); for (uint region_index = 0; region_index < length; region_index++) { surviving_young_words[region_index] += _surviving_young_words[region_index]; } diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 8c31430e185..eb091443887 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -39,6 +39,7 @@ #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/intHisto.hpp" @@ -536,7 +537,7 @@ void G1RemSet::print_periodic_summary_info(const char* header, uint period_count current.initialize(this); _prev_period_summary.subtract_from(¤t); - LogHandle(gc, remset) log; + Log(gc, remset) log; log.trace("%s", header); ResourceMark rm; _prev_period_summary.print_on(log.trace_stream()); @@ -546,7 +547,7 @@ void G1RemSet::print_periodic_summary_info(const char* header, uint period_count } void G1RemSet::print_summary_info() { - LogHandle(gc, remset, exit) log; + Log(gc, remset, exit) log; if (log.is_trace()) { log.trace(" Cumulative RS summary"); G1RemSetSummary current; diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp index fc6ad1bf116..8b8ce067eaf 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ void G1StringDedup::initialize() { void G1StringDedup::stop() { assert(is_enabled(), "String deduplication not enabled"); - G1StringDedupThread::stop(); + G1StringDedupThread::thread()->stop(); } bool G1StringDedup::is_candidate_from_mark(oop obj) { diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp index 47a8f40b460..3075c269ebc 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp @@ -570,7 +570,7 @@ void G1StringDedupTable::trim_entry_cache() { } void G1StringDedupTable::print_statistics() { - LogHandle(gc, stringdedup) log; + Log(gc, stringdedup) log; log.debug(" [Table]"); log.debug(" [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]", G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry))); diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp index bd4d9b89648..4c6dc45fc90 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,11 +81,9 @@ void G1StringDedupThread::deduplicate_shared_strings(G1StringDedupStat& stat) { StringTable::shared_oops_do(&sharedStringDedup); } -void G1StringDedupThread::run() { +void G1StringDedupThread::run_service() { G1StringDedupStat total_stat; - initialize_in_thread(); - wait_for_universe_init(); deduplicate_shared_strings(total_stat); // Main loop @@ -96,7 +94,7 @@ void G1StringDedupThread::run() { // Wait for the queue to become non-empty G1StringDedupQueue::wait(); - if (_should_terminate) { + if (should_terminate()) { break; } @@ -133,23 +131,10 @@ void G1StringDedupThread::run() { } } - terminate(); } -void G1StringDedupThread::stop() { - { - MonitorLockerEx ml(Terminator_lock); - _thread->_should_terminate = true; - } - +void G1StringDedupThread::stop_service() { G1StringDedupQueue::cancel_wait(); - - { - MonitorLockerEx ml(Terminator_lock); - while (!_thread->_has_terminated) { - ml.wait(); - } - } } void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp index 6c8a275f666..ff568114d86 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,14 +45,14 @@ private: void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + void run_service(); + void stop_service(); + public: static void create(); - static void stop(); static G1StringDedupThread* thread(); - virtual void run(); - void deduplicate_shared_strings(G1StringDedupStat& stat); }; diff --git a/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.cpp b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.cpp new file mode 100644 index 00000000000..cf7866770d5 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1YoungGenSizer.hpp" +#include "gc/g1/heapRegion.hpp" + +G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), + _min_desired_young_length(0), _max_desired_young_length(0) { + if (FLAG_IS_CMDLINE(NewRatio)) { + if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { + warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); + } else { + _sizer_kind = SizerNewRatio; + _adaptive_size = false; + return; + } + } + + if (NewSize > MaxNewSize) { + if (FLAG_IS_CMDLINE(MaxNewSize)) { + warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " + "A new max generation size of " SIZE_FORMAT "k will be used.", + NewSize/K, MaxNewSize/K, NewSize/K); + } + MaxNewSize = NewSize; + } + + if (FLAG_IS_CMDLINE(NewSize)) { + _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes), + 1U); + if (FLAG_IS_CMDLINE(MaxNewSize)) { + _max_desired_young_length = + MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), + 1U); + _sizer_kind = SizerMaxAndNewSize; + _adaptive_size = _min_desired_young_length == _max_desired_young_length; + } else { + _sizer_kind = SizerNewSizeOnly; + } + } else if (FLAG_IS_CMDLINE(MaxNewSize)) { + _max_desired_young_length = + MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), + 1U); + _sizer_kind = SizerMaxNewSizeOnly; + } +} + +uint G1YoungGenSizer::calculate_default_min_length(uint new_number_of_heap_regions) { + uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100; + return MAX2(1U, default_value); +} + +uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regions) { + uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100; + return MAX2(1U, default_value); +} + +void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) { + assert(number_of_heap_regions > 0, "Heap must be initialized"); + + switch (_sizer_kind) { + case SizerDefaults: + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *max_young_length = calculate_default_max_length(number_of_heap_regions); + break; + case SizerNewSizeOnly: + *max_young_length = calculate_default_max_length(number_of_heap_regions); + *max_young_length = MAX2(*min_young_length, *max_young_length); + break; + case SizerMaxNewSizeOnly: + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *min_young_length = MIN2(*min_young_length, *max_young_length); + break; + case SizerMaxAndNewSize: + // Do nothing. Values set on the command line, don't update them at runtime. + break; + case SizerNewRatio: + *min_young_length = number_of_heap_regions / (NewRatio + 1); + *max_young_length = *min_young_length; + break; + default: + ShouldNotReachHere(); + } + + assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values"); +} + +uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) { + // We need to pass the desired values because recalculation may not update these + // values in some cases. + uint temp = _min_desired_young_length; + uint result = _max_desired_young_length; + recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); + return result; +} + +void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { + recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, + &_max_desired_young_length); +} diff --git a/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.hpp b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.hpp new file mode 100644 index 00000000000..1d5421b2802 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "memory/allocation.hpp" + +// There are three command line options related to the young gen size: +// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is +// just a short form for NewSize==MaxNewSize). G1 will use its internal +// heuristics to calculate the actual young gen size, so these options +// basically only limit the range within which G1 can pick a young gen +// size. Also, these are general options taking byte sizes. G1 will +// internally work with a number of regions instead. So, some rounding +// will occur. +// +// If nothing related to the the young gen size is set on the command +// line we should allow the young gen to be between G1NewSizePercent +// and G1MaxNewSizePercent of the heap size. This means that every time +// the heap size changes, the limits for the young gen size will be +// recalculated. +// +// If only -XX:NewSize is set we should use the specified value as the +// minimum size for young gen. Still using G1MaxNewSizePercent of the +// heap as maximum. +// +// If only -XX:MaxNewSize is set we should use the specified value as the +// maximum size for young gen. Still using G1NewSizePercent of the heap +// as minimum. +// +// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values. +// No updates when the heap size changes. There is a special case when +// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a +// different heuristic for calculating the collection set when we do mixed +// collection. +// +// If only -XX:NewRatio is set we should use the specified ratio of the heap +// as both min and max. This will be interpreted as "fixed" just like the +// NewSize==MaxNewSize case above. But we will update the min and max +// every time the heap size changes. +// +// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is +// combined with either NewSize or MaxNewSize. (A warning message is printed.) +class G1YoungGenSizer : public CHeapObj { +private: + enum SizerKind { + SizerDefaults, + SizerNewSizeOnly, + SizerMaxNewSizeOnly, + SizerMaxAndNewSize, + SizerNewRatio + }; + SizerKind _sizer_kind; + uint _min_desired_young_length; + uint _max_desired_young_length; + bool _adaptive_size; + uint calculate_default_min_length(uint new_number_of_heap_regions); + uint calculate_default_max_length(uint new_number_of_heap_regions); + + // Update the given values for minimum and maximum young gen length in regions + // given the number of heap regions depending on the kind of sizing algorithm. + void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length); + +public: + G1YoungGenSizer(); + // Calculate the maximum length of the young gen given the number of regions + // depending on the sizing algorithm. + uint max_young_length(uint number_of_heap_regions); + + void heap_size_changed(uint new_number_of_heap_regions); + uint min_desired_young_length() { + return _min_desired_young_length; + } + uint max_desired_young_length() { + return _max_desired_young_length; + } + + bool adaptive_young_list_length() const { + return _adaptive_size; + } +}; + diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index 8df01b58511..b435c052cad 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -25,38 +25,13 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" -void G1YoungRemSetSamplingThread::run() { - initialize_in_thread(); - wait_for_universe_init(); - - run_service(); - - terminate(); -} - -void G1YoungRemSetSamplingThread::stop() { - // it is ok to take late safepoints here, if needed - { - MutexLockerEx mu(Terminator_lock); - _should_terminate = true; - } - - stop_service(); - - { - MutexLockerEx mu(Terminator_lock); - while (!_has_terminated) { - Terminator_lock->wait(); - } - } -} - G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : ConcurrentGCThread(), _monitor(Mutex::nonleaf, @@ -69,7 +44,7 @@ G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); - if (!_should_terminate) { + if (!should_terminate()) { uintx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? _monitor.wait(Mutex::_no_safepoint_check_flag, waitms); } @@ -78,7 +53,7 @@ void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { void G1YoungRemSetSamplingThread::run_service() { double vtime_start = os::elapsedVTime(); - while (!_should_terminate) { + while (!should_terminate()) { sample_young_list_rs_lengths(); if (os::supports_vtime()) { @@ -114,7 +89,7 @@ void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { // retired as the current allocation region). if (hr->in_collection_set()) { // Update the collection set policy information for this region - g1p->update_incremental_cset_info(hr, rs_length); + g1h->collection_set()->update_young_region_prediction(hr, rs_length); } ++regions_visited; diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp index 78e82e7e352..31cf79ed500 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp @@ -55,9 +55,6 @@ private: public: G1YoungRemSetSamplingThread(); double vtime_accum() { return _vtime_accum; } - - virtual void run(); - void stop(); }; #endif // SHARE_VM_GC_G1_G1YOUNGREMSETSAMPLINGTHREAD_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 7bc980e0fee..ac78d2b0e8a 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -233,10 +233,6 @@ "Raise a fatal VM exit out of memory failure in the event " \ " that heap expansion fails due to running out of swap.") \ \ - develop(uintx, G1ConcMarkForceOverflow, 0, \ - "The number of times we'll force an overflow during " \ - "concurrent marking") \ - \ experimental(uintx, G1MaxNewSizePercent, 60, \ "Percentage (0-100) of the heap size to use as default " \ " maximum young gen size.") \ diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 42cb7d5928a..b88145da9c1 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,10 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionTracer.hpp" #include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/liveRange.hpp" #include "gc/shared/space.inline.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.inline.hpp" @@ -695,7 +695,7 @@ public: template void verify_liveness(T* p) { T heap_oop = oopDesc::load_heap_oop(p); - LogHandle(gc, verify) log; + Log(gc, verify) log; if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); bool failed = false; @@ -749,7 +749,7 @@ public: template void verify_remembered_set(T* p) { T heap_oop = oopDesc::load_heap_oop(p); - LogHandle(gc, verify) log; + Log(gc, verify) log; if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); bool failed = false; diff --git a/hotspot/src/share/vm/gc/g1/heapRegionBounds.hpp b/hotspot/src/share/vm/gc/g1/heapRegionBounds.hpp index 30d353454f3..cda26941798 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionBounds.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionBounds.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ #ifndef SHARE_VM_GC_G1_HEAPREGIONBOUNDS_HPP #define SHARE_VM_GC_G1_HEAPREGIONBOUNDS_HPP +#include "memory/allocation.hpp" + class HeapRegionBounds : public AllStatic { private: // Minimum region size; we won't go lower than that. diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index d6cf5c50e6a..5c94f87eafd 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -43,16 +43,12 @@ PtrQueue::~PtrQueue() { void PtrQueue::flush_impl() { if (!_permanent && _buf != NULL) { - if (_index == _sz) { + BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index); + if (is_empty()) { // No work to do. - qset()->deallocate_buffer(_buf); + qset()->deallocate_buffer(node); } else { - // We must NULL out the unused entries, then enqueue. - size_t limit = byte_index_to_index(_index); - for (size_t i = 0; i < limit; ++i) { - _buf[i] = NULL; - } - qset()->enqueue_complete_buffer(_buf); + qset()->enqueue_complete_buffer(node); } _buf = NULL; _index = 0; @@ -74,7 +70,7 @@ void PtrQueue::enqueue_known_active(void* ptr) { assert(_index <= _sz, "Invariant."); } -void PtrQueue::locking_enqueue_completed_buffer(void** buf) { +void PtrQueue::locking_enqueue_completed_buffer(BufferNode* node) { assert(_lock->owned_by_self(), "Required."); // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before @@ -82,7 +78,7 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) { // have the same rank and we may get the "possible deadlock" message _lock->unlock(); - qset()->enqueue_complete_buffer(buf); + qset()->enqueue_complete_buffer(node); // We must relock only because the caller will unlock, for the normal // case. _lock->lock_without_safepoint_check(); @@ -157,10 +153,9 @@ void** PtrQueueSet::allocate_buffer() { return BufferNode::make_buffer_from_node(node); } -void PtrQueueSet::deallocate_buffer(void** buf) { +void PtrQueueSet::deallocate_buffer(BufferNode* node) { assert(_sz > 0, "Didn't set a buffer size."); MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); - BufferNode *node = BufferNode::make_node_from_buffer(buf); node->set_next(_fl_owner->_buf_free_list); _fl_owner->_buf_free_list = node; _fl_owner->_buf_free_list_sz++; @@ -211,10 +206,10 @@ void PtrQueue::handle_zero_index() { // preventing the subsequent the multiple enqueue, and // install a newly allocated buffer below. - void** buf = _buf; // local pointer to completed buffer + BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index); _buf = NULL; // clear shared _buf field - locking_enqueue_completed_buffer(buf); // enqueue completed buffer + locking_enqueue_completed_buffer(node); // enqueue completed buffer // While the current thread was enqueueing the buffer another thread // may have a allocated a new buffer and inserted it into this pointer @@ -224,9 +219,11 @@ void PtrQueue::handle_zero_index() { if (_buf != NULL) return; } else { - if (qset()->process_or_enqueue_complete_buffer(_buf)) { + BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index); + if (qset()->process_or_enqueue_complete_buffer(node)) { // Recycle the buffer. No allocation. - _sz = qset()->buffer_size(); + assert(_buf == BufferNode::make_buffer_from_node(node), "invariant"); + assert(_sz == qset()->buffer_size(), "invariant"); _index = _sz; return; } @@ -238,12 +235,12 @@ void PtrQueue::handle_zero_index() { _index = _sz; } -bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { +bool PtrQueueSet::process_or_enqueue_complete_buffer(BufferNode* node) { if (Thread::current()->is_Java_thread()) { // We don't lock. It is fine to be epsilon-precise here. if (_max_completed_queue == 0 || _max_completed_queue > 0 && _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) { - bool b = mut_process_buffer(buf); + bool b = mut_process_buffer(node); if (b) { // True here means that the buffer hasn't been deallocated and the caller may reuse it. return true; @@ -251,14 +248,12 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { } } // The buffer will be enqueued. The caller will have to get a new one. - enqueue_complete_buffer(buf); + enqueue_complete_buffer(node); return false; } -void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { +void PtrQueueSet::enqueue_complete_buffer(BufferNode* cbn) { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - BufferNode* cbn = BufferNode::make_node_from_buffer(buf); - cbn->set_index(index); cbn->set_next(NULL); if (_completed_buffers_tail == NULL) { assert(_completed_buffers_head == NULL, "Well-formedness"); diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 4d5c5e6c28a..50c23960eca 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -33,6 +33,7 @@ // the addresses of modified old-generation objects. This type supports // this operation. +class BufferNode; class PtrQueueSet; class PtrQueue VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -104,7 +105,7 @@ public: // get into an infinite loop). virtual bool should_enqueue_buffer() { return true; } void handle_zero_index(); - void locking_enqueue_completed_buffer(void** buf); + void locking_enqueue_completed_buffer(BufferNode* node); void enqueue_known_active(void* ptr); @@ -136,6 +137,10 @@ public: return ind / sizeof(void*); } + static size_t index_to_byte_index(size_t ind) { + return ind * sizeof(void*); + } + // To support compiler. protected: @@ -186,10 +191,13 @@ public: // Free a BufferNode. static void deallocate(BufferNode* node); - // Return the BufferNode containing the buffer. - static BufferNode* make_node_from_buffer(void** buffer) { - return reinterpret_cast( - reinterpret_cast(buffer) - buffer_offset()); + // Return the BufferNode containing the buffer, after setting its index. + static BufferNode* make_node_from_buffer(void** buffer, size_t index) { + BufferNode* node = + reinterpret_cast( + reinterpret_cast(buffer) - buffer_offset()); + node->set_index(index); + return node; } // Return the buffer for node. @@ -243,7 +251,7 @@ protected: // A mutator thread does the the work of processing a buffer. // Returns "true" iff the work is complete (and the buffer may be // deallocated). - virtual bool mut_process_buffer(void** buf) { + virtual bool mut_process_buffer(BufferNode* node) { ShouldNotReachHere(); return false; } @@ -267,13 +275,13 @@ public: // Return an empty buffer to the free list. The "buf" argument is // required to be a pointer to the head of an array of length "_sz". - void deallocate_buffer(void** buf); + void deallocate_buffer(BufferNode* node); // Declares that "buf" is a complete buffer. - void enqueue_complete_buffer(void** buf, size_t index = 0); + void enqueue_complete_buffer(BufferNode* node); // To be invoked by the mutator. - bool process_or_enqueue_complete_buffer(void** buf); + bool process_or_enqueue_complete_buffer(BufferNode* node); bool completed_buffers_exist_dirty() { return _n_completed_buffers > 0; diff --git a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp index 378ece5cf99..a339009188d 100644 --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,6 +100,10 @@ inline bool requires_marking(const void* entry, G1CollectedHeap* heap) { return true; } +inline bool retain_entry(const void* entry, G1CollectedHeap* heap) { + return requires_marking(entry, heap) && !heap->isMarkedNext((oop)entry); +} + // This method removes entries from a SATB buffer that will not be // useful to the concurrent marking threads. Entries are retained if // they require marking and are not already marked. Retained entries @@ -114,43 +118,28 @@ void SATBMarkQueue::filter() { return; } - // Used for sanity checking at the end of the loop. - DEBUG_ONLY(size_t entries = 0; size_t retained = 0;) - assert(_index <= _sz, "invariant"); - void** limit = &buf[byte_index_to_index(_index)]; - void** src = &buf[byte_index_to_index(_sz)]; - void** dst = src; - while (limit < src) { - DEBUG_ONLY(entries += 1;) - --src; + // Two-fingered compaction toward the end. + void** src = &buf[byte_index_to_index(_index)]; + void** dst = &buf[byte_index_to_index(_sz)]; + for ( ; src < dst; ++src) { + // Search low to high for an entry to keep. void* entry = *src; - // NULL the entry so that unused parts of the buffer contain NULLs - // at the end. If we are going to retain it we will copy it to its - // final place. If we have retained all entries we have visited so - // far, we'll just end up copying it to the same place. - *src = NULL; - - if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) { - --dst; - assert(*dst == NULL, "filtering destination should be clear"); - *dst = entry; - DEBUG_ONLY(retained += 1;); + if (retain_entry(entry, g1h)) { + // Found keeper. Search high to low for an entry to discard. + while (src < --dst) { + if (!retain_entry(*dst, g1h)) { + *dst = entry; // Replace discard with keeper. + break; + } + } + // If discard search failed (src == dst), the outer loop will also end. } } - size_t new_index = pointer_delta(dst, buf, 1); - -#ifdef ASSERT - size_t entries_calc = (_sz - _index) / sizeof(void*); - assert(entries == entries_calc, "the number of entries we counted " - "should match the number of entries we calculated"); - size_t retained_calc = (_sz - new_index) / sizeof(void*); - assert(retained == retained_calc, "the number of retained entries we counted " - "should match the number of retained entries we calculated"); -#endif // ASSERT - - _index = new_index; + // dst points to the lowest retained entry, or the end of the buffer + // if all the entries were filtered out. + _index = pointer_delta(dst, buf, 1); } // This method will first apply the above filtering to the buffer. If @@ -286,19 +275,11 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) } if (nd != NULL) { void **buf = BufferNode::make_buffer_from_node(nd); - // Skip over NULL entries at beginning (e.g. push end) of buffer. - // Filtering can result in non-full completed buffers; see - // should_enqueue_buffer. - assert(_sz % sizeof(void*) == 0, "invariant"); - size_t limit = SATBMarkQueue::byte_index_to_index(_sz); - for (size_t i = 0; i < limit; ++i) { - if (buf[i] != NULL) { - // Found the end of the block of NULLs; process the remainder. - cl->do_buffer(buf + i, limit - i); - break; - } - } - deallocate_buffer(buf); + size_t index = SATBMarkQueue::byte_index_to_index(nd->index()); + size_t size = SATBMarkQueue::byte_index_to_index(_sz); + assert(index <= size, "invariant"); + cl->do_buffer(buf + index, size - index); + deallocate_buffer(nd); return true; } else { return false; @@ -355,7 +336,7 @@ void SATBMarkQueueSet::abandon_partial_marking() { while (buffers_to_delete != NULL) { BufferNode* nd = buffers_to_delete; buffers_to_delete = nd->next(); - deallocate_buffer(BufferNode::make_buffer_from_node(nd)); + deallocate_buffer(nd); } assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); // So we can safely manipulate these queues. diff --git a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp index e3591f4f7df..2e3642e428b 100644 --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,9 +115,8 @@ public: // If there exists some completed buffer, pop and process it, and // return true. Otherwise return false. Processing a buffer - // consists of applying the closure to the buffer range starting - // with the first non-NULL entry to the end of the buffer; the - // leading entries may be NULL due to filtering. + // consists of applying the closure to the active range of the + // buffer; the leading entries may be excluded due to filtering. bool apply_closure_to_completed_buffer(SATBBufferClosure* cl); #ifndef PRODUCT diff --git a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp index d15bef9254a..de1f23e9155 100644 --- a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp +++ b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" uint SuspendibleThreadSet::_nthreads = 0; @@ -32,6 +33,19 @@ uint SuspendibleThreadSet::_nthreads_stopped = 0; bool SuspendibleThreadSet::_suspend_all = false; double SuspendibleThreadSet::_suspend_all_start = 0.0; +static Semaphore* _synchronize_wakeup = NULL; + +void SuspendibleThreadSet_init() { + assert(_synchronize_wakeup == NULL, "STS already initialized"); + _synchronize_wakeup = new Semaphore(); +} + +bool SuspendibleThreadSet::is_synchronized() { + assert_lock_strong(STS_lock); + assert(_nthreads_stopped <= _nthreads, "invariant"); + return _nthreads_stopped == _nthreads; +} + void SuspendibleThreadSet::join() { assert(!Thread::current()->is_suspendible_thread(), "Thread already joined"); MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); @@ -48,31 +62,30 @@ void SuspendibleThreadSet::leave() { assert(_nthreads > 0, "Invalid"); DEBUG_ONLY(Thread::current()->clear_suspendible_thread();) _nthreads--; - if (_suspend_all) { - ml.notify_all(); + if (_suspend_all && is_synchronized()) { + // This leave completes a request, so inform the requestor. + _synchronize_wakeup->signal(); } } void SuspendibleThreadSet::yield() { assert(Thread::current()->is_suspendible_thread(), "Must have joined"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); if (_suspend_all) { - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - if (_suspend_all) { - _nthreads_stopped++; - if (_nthreads_stopped == _nthreads) { - if (ConcGCYieldTimeout > 0) { - double now = os::elapsedTime(); - guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); - } + _nthreads_stopped++; + if (is_synchronized()) { + if (ConcGCYieldTimeout > 0) { + double now = os::elapsedTime(); + guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); } - ml.notify_all(); - while (_suspend_all) { - ml.wait(Mutex::_no_safepoint_check_flag); - } - assert(_nthreads_stopped > 0, "Invalid"); - _nthreads_stopped--; - ml.notify_all(); + // This yield completes the request, so inform the requestor. + _synchronize_wakeup->signal(); } + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + assert(_nthreads_stopped > 0, "Invalid"); + _nthreads_stopped--; } } @@ -81,18 +94,41 @@ void SuspendibleThreadSet::synchronize() { if (ConcGCYieldTimeout > 0) { _suspend_all_start = os::elapsedTime(); } + { + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(!_suspend_all, "Only one at a time"); + _suspend_all = true; + if (is_synchronized()) { + return; + } + } // Release lock before semaphore wait. + + // Semaphore initial count is zero. To reach here, there must be at + // least one not yielded thread in the set, e.g. is_synchronized() + // was false before the lock was released. A thread in the set will + // signal the semaphore iff it is the last to yield or leave while + // there is an active suspend request. So there will be exactly one + // signal, which will increment the semaphore count to one, which + // will then be consumed by this wait, returning it to zero. No + // thread can exit yield or enter the set until desynchronize is + // called, so there are no further opportunities for the semaphore + // being signaled until we get back here again for some later + // synchronize call. Hence, there is no need to re-check for + // is_synchronized after the wait; it will always be true there. + _synchronize_wakeup->wait(); + +#ifdef ASSERT MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(!_suspend_all, "Only one at a time"); - _suspend_all = true; - while (_nthreads_stopped < _nthreads) { - ml.wait(Mutex::_no_safepoint_check_flag); - } + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); +#endif } void SuspendibleThreadSet::desynchronize() { assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_nthreads_stopped == _nthreads, "Invalid"); + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); _suspend_all = false; ml.notify_all(); } diff --git a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp index 33cbe00f40c..bd440f4e706 100644 --- a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp +++ b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,8 @@ private: static bool _suspend_all; static double _suspend_all_start; + static bool is_synchronized(); + // Add the current thread to the set. May block if a suspension is in progress. static void join(); diff --git a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp index 8d7300854de..62d610d966b 100644 --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,30 +205,18 @@ void VM_G1IncCollectionPause::doit_epilogue() { } void VM_CGC_Operation::acquire_pending_list_lock() { - assert(_needs_pll, "don't call this otherwise"); - // The caller may block while communicating - // with the SLT thread in order to acquire/release the PLL. - SurrogateLockerThread* slt = ConcurrentMarkThread::slt(); - if (slt != NULL) { - slt->manipulatePLL(SurrogateLockerThread::acquirePLL); - } else { - SurrogateLockerThread::report_missing_slt(); - } + _pending_list_locker.lock(); } void VM_CGC_Operation::release_and_notify_pending_list_lock() { - assert(_needs_pll, "don't call this otherwise"); - // The caller may block while communicating - // with the SLT thread in order to acquire/release the PLL. - ConcurrentMarkThread::slt()-> - manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); + _pending_list_locker.unlock(); } void VM_CGC_Operation::doit() { GCIdMark gc_id_mark(_gc_id); GCTraceCPUTime tcpu; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime(Info, gc) t(_printGCMessage, g1h->gc_timer_cm(), GCCause::_no_gc, true); + GCTraceTime(Info, gc) t(_printGCMessage, g1h->concurrent_mark()->gc_timer_cm(), GCCause::_no_gc, true); IsGCActiveMark x; _cl->do_void(); } @@ -236,10 +224,9 @@ void VM_CGC_Operation::doit() { bool VM_CGC_Operation::doit_prologue() { // Note the relative order of the locks must match that in // VM_GC_Operation::doit_prologue() or deadlocks can occur - if (_needs_pll) { + if (_needs_pending_list_lock) { acquire_pending_list_lock(); } - Heap_lock->lock(); return true; } @@ -248,7 +235,7 @@ void VM_CGC_Operation::doit_epilogue() { // Note the relative order of the unlocks must match that in // VM_GC_Operation::doit_epilogue() Heap_lock->unlock(); - if (_needs_pll) { + if (_needs_pending_list_lock) { release_and_notify_pending_list_lock(); } } diff --git a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp index 262e7bd871c..5aab7096586 100644 --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "gc/g1/g1AllocationContext.hpp" #include "gc/shared/gcId.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/vmGCOperations.hpp" // VM_operations for the G1 collector. @@ -102,10 +103,11 @@ public: // Concurrent GC stop-the-world operations such as remark and cleanup; // consider sharing these with CMS's counterparts. class VM_CGC_Operation: public VM_Operation { - VoidClosure* _cl; - const char* _printGCMessage; - bool _needs_pll; - uint _gc_id; + VoidClosure* _cl; + const char* _printGCMessage; + bool _needs_pending_list_lock; + ReferencePendingListLocker _pending_list_locker; + uint _gc_id; protected: // java.lang.ref.Reference support @@ -113,8 +115,8 @@ protected: void release_and_notify_pending_list_lock(); public: - VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pll) - : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll), _gc_id(GCId::current()) { } + VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pending_list_lock) + : _cl(cl), _printGCMessage(printGCMsg), _needs_pending_list_lock(needs_pending_list_lock), _gc_id(GCId::current()) {} virtual VMOp_Type type() const { return VMOp_CGC_Operation; } virtual void doit(); virtual bool doit_prologue(); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp index 62b66559a53..6f6201d45cf 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,67 +27,178 @@ #include "utilities/ostream.hpp" template <> -void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum) { - out->print("%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", title, min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); +size_t WorkerDataArray::uninitialized() { + return (size_t)-1; +} + +template <> +double WorkerDataArray::uninitialized() { + return -1.0; +} + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, double min, double avg, double max, double diff, double sum, bool print_sum) { + out->print(" Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); if (print_sum) { - out->print_cr(", Sum: %4.1lf", sum * MILLIUNITS); - } else { - out->cr(); + out->print(", Sum: %4.1lf", sum * MILLIUNITS); } } template <> -void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum) { - out->print("%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT, title, min, avg, max, diff); +void WorkerDataArray::WDAPrinter::summary(outputStream* out, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum) { + out->print(" Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT, min, avg, max, diff); if (print_sum) { - out->print_cr(", Sum: " SIZE_FORMAT, sum); - } else { - out->cr(); + out->print(", Sum: " SIZE_FORMAT, sum); } } template <> -void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out) { out->print("%-25s", ""); - for (uint i = 0; i < active_threads; ++i) { - out->print(" %4.1lf", phase->get(i) * 1000.0); + for (uint i = 0; i < phase->_length; ++i) { + double value = phase->get(i); + if (value != phase->uninitialized()) { + out->print(" %4.1lf", phase->get(i) * 1000.0); + } else { + out->print(" -"); + } } out->cr(); } template <> -void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out) { out->print("%-25s", ""); - for (uint i = 0; i < active_threads; ++i) { - out->print(" " SIZE_FORMAT, phase->get(i)); + for (uint i = 0; i < phase->_length; ++i) { + size_t value = phase->get(i); + if (value != phase->uninitialized()) { + out->print(" " SIZE_FORMAT, phase->get(i)); + } else { + out->print(" -"); + } } out->cr(); } #ifndef PRODUCT -void WorkerDataArray_test() { - const uint length = 3; - const char* title = "Test array"; - WorkerDataArray array(length, title); - assert(strncmp(array.title(), title, strlen(title)) == 0 , "Expected titles to match"); +#include "memory/resourceArea.hpp" - const size_t expected[length] = {5, 3, 7}; - for (uint i = 0; i < length; i++) { - array.set(i, expected[i]); - } - for (uint i = 0; i < length; i++) { - assert(array.get(i) == expected[i], "Expected elements to match"); - } +void WorkerDataArray_test_verify_string(const char* expected_string, const char* actual_string) { + const size_t expected_len = strlen(expected_string); - assert(array.sum(length) == (5 + 3 + 7), "Expected sums to match"); - assert(array.average(length) == 5.0, "Expected averages to match"); + assert(expected_len == strlen(actual_string), + "Wrong string length, expected " SIZE_FORMAT " but got " SIZE_FORMAT "(Expected '%s' but got: '%s')", + expected_len, strlen(actual_string), expected_string, actual_string); - for (uint i = 0; i < length; i++) { - array.add(i, 1); - } - for (uint i = 0; i < length; i++) { - assert(array.get(i) == expected[i] + 1, "Expected add to increment values"); + // Can't use strncmp here because floating point values use different decimal points for different locales. + // Allow strings to differ in "." vs. "," only. This should still catch most errors. + for (size_t i = 0; i < expected_len; i++) { + char e = expected_string[i]; + char a = actual_string[i]; + if (e != a) { + if ((e == '.' || e == ',') && (a == '.' || a == ',')) { + // Most likely just a difference in locale + } else { + assert(false, "Expected '%s' but got: '%s'", expected_string, actual_string); + } + } } } + +void WorkerDataArray_test_verify_array(WorkerDataArray& array, size_t expected_sum, double expected_avg, const char* expected_summary, const char* exected_details) { + const double epsilon = 0.0001; + assert(array.sum() == expected_sum, "Wrong sum, expected: " SIZE_FORMAT " but got: " SIZE_FORMAT, expected_sum, array.sum()); + assert(fabs(array.average() - expected_avg) < epsilon, "Wrong average, expected: %f but got: %f", expected_avg, array.average()); + + ResourceMark rm; + stringStream out; + array.print_summary_on(&out); + WorkerDataArray_test_verify_string(expected_summary, out.as_string()); + out.reset(); + array.print_details_on(&out); + WorkerDataArray_test_verify_string(exected_details, out.as_string()); +} + +void WorkerDataArray_test_verify_array(WorkerDataArray& array, double expected_sum, double expected_avg, const char* expected_summary, const char* exected_details) { + const double epsilon = 0.0001; + assert(fabs(array.sum() - expected_sum) < epsilon, "Wrong sum, expected: %f but got: %f", expected_sum, array.sum()); + assert(fabs(array.average() - expected_avg) < epsilon, "Wrong average, expected: %f but got: %f", expected_avg, array.average()); + + ResourceMark rm; + stringStream out; + array.print_summary_on(&out); + WorkerDataArray_test_verify_string(expected_summary, out.as_string()); + out.reset(); + array.print_details_on(&out); + WorkerDataArray_test_verify_string(exected_details, out.as_string()); +} + +void WorkerDataArray_test_basic() { + WorkerDataArray array(3, "Test array"); + array.set(0, 5); + array.set(1, 3); + array.set(2, 7); + + WorkerDataArray_test_verify_array(array, 15, 5.0, + "Test array Min: 3, Avg: 5.0, Max: 7, Diff: 4, Sum: 15, Workers: 3\n", + " 5 3 7\n" ); +} + +void WorkerDataArray_test_add() { + WorkerDataArray array(3, "Test array"); + array.set(0, 5); + array.set(1, 3); + array.set(2, 7); + + for (uint i = 0; i < 3; i++) { + array.add(i, 1); + } + + WorkerDataArray_test_verify_array(array, 18, 6.0, + "Test array Min: 4, Avg: 6.0, Max: 8, Diff: 4, Sum: 18, Workers: 3\n", + " 6 4 8\n" ); +} + +void WorkerDataArray_test_with_uninitialized() { + WorkerDataArray array(3, "Test array"); + array.set(0, 5); + array.set(1, WorkerDataArray::uninitialized()); + array.set(2, 7); + + WorkerDataArray_test_verify_array(array, 12, 6, + "Test array Min: 5, Avg: 6.0, Max: 7, Diff: 2, Sum: 12, Workers: 2\n", + " 5 - 7\n" ); +} + +void WorkerDataArray_test_uninitialized() { + WorkerDataArray array(3, "Test array"); + array.set(0, WorkerDataArray::uninitialized()); + array.set(1, WorkerDataArray::uninitialized()); + array.set(2, WorkerDataArray::uninitialized()); + + WorkerDataArray_test_verify_array(array, 0, 0.0, + "Test array skipped\n", + " - - -\n" ); +} + +void WorkerDataArray_test_double_with_uninitialized() { + WorkerDataArray array(3, "Test array"); + array.set(0, 5.1 / MILLIUNITS); + array.set(1, WorkerDataArray::uninitialized()); + array.set(2, 7.2 / MILLIUNITS); + + WorkerDataArray_test_verify_array(array, 12.3 / MILLIUNITS, 6.15 / MILLIUNITS, + "Test array Min: 5.1, Avg: 6.1, Max: 7.2, Diff: 2.1, Sum: 12.3, Workers: 2\n", + " 5.1 - 7.2\n" ); +} + +void WorkerDataArray_test() { + WorkerDataArray_test_basic(); + WorkerDataArray_test_add(); + WorkerDataArray_test_with_uninitialized(); + WorkerDataArray_test_uninitialized(); + WorkerDataArray_test_double_with_uninitialized(); +} + #endif diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp index e1e972327ea..2884c00767a 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,16 +32,13 @@ class outputStream; template class WorkerDataArray : public CHeapObj { + friend class WDAPrinter; T* _data; uint _length; const char* _title; WorkerDataArray* _thread_work_items; - NOT_PRODUCT(inline T uninitialized() const;) - - void set_all(T value); - public: WorkerDataArray(uint length, const char* title); ~WorkerDataArray(); @@ -52,37 +49,38 @@ class WorkerDataArray : public CHeapObj { return _thread_work_items; } + static T uninitialized(); + void set(uint worker_i, T value); T get(uint worker_i) const; void add(uint worker_i, T value); - double average(uint active_threads) const; - T sum(uint active_threads) const; + // The sum() and average() methods below consider uninitialized slots to be 0. + double average() const; + T sum() const; const char* title() const { return _title; } - void clear(); - - void reset() PRODUCT_RETURN; - void verify(uint active_threads) const PRODUCT_RETURN; + void reset(); + void set_all(T value); private: class WDAPrinter { public: - static void summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum); - static void summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); + static void summary(outputStream* out, double min, double avg, double max, double diff, double sum, bool print_sum); + static void summary(outputStream* out, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); - static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); - static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + static void details(const WorkerDataArray* phase, outputStream* out); + static void details(const WorkerDataArray* phase, outputStream* out); }; public: - void print_summary_on(outputStream* out, uint active_threads, bool print_sum = true) const; - void print_details_on(outputStream* out, uint active_threads) const; + void print_summary_on(outputStream* out, bool print_sum = true) const; + void print_details_on(outputStream* out) const; }; #endif // SHARE_VM_GC_G1_WORKERDATAARRAY_HPP diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp index 7b4df8628b8..dfcee0b5d49 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ void WorkerDataArray::set(uint worker_i, T value) { template T WorkerDataArray::get(uint worker_i) const { assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); - assert(_data[worker_i] != uninitialized(), "No data added for worker %d", worker_i); return _data[worker_i]; } @@ -78,24 +77,30 @@ void WorkerDataArray::add(uint worker_i, T value) { } template -double WorkerDataArray::average(uint active_threads) const { - return sum(active_threads) / (double) active_threads; +double WorkerDataArray::average() const { + uint contributing_threads = 0; + for (uint i = 0; i < _length; ++i) { + if (get(i) != uninitialized()) { + contributing_threads++; + } + } + if (contributing_threads == 0) { + return 0.0; + } + return sum() / (double) contributing_threads; } template -T WorkerDataArray::sum(uint active_threads) const { - T s = get(0); - for (uint i = 1; i < active_threads; ++i) { - s += get(i); +T WorkerDataArray::sum() const { + T s = 0; + for (uint i = 0; i < _length; ++i) { + if (get(i) != uninitialized()) { + s += get(i); + } } return s; } -template -void WorkerDataArray::clear() { - set_all(0); -} - template void WorkerDataArray::set_all(T value) { for (uint i = 0; i < _length; i++) { @@ -104,27 +109,42 @@ void WorkerDataArray::set_all(T value) { } template -void WorkerDataArray::print_summary_on(outputStream* out, uint active_threads, bool print_sum) const { - T max = get(0); - T min = max; - T sum = 0; - for (uint i = 1; i < active_threads; ++i) { - T value = get(i); - max = MAX2(max, value); - min = MIN2(min, value); - sum += value; +void WorkerDataArray::print_summary_on(outputStream* out, bool print_sum) const { + out->print("%-25s", title()); + uint start = 0; + while (start < _length && get(start) == uninitialized()) { + start++; + } + if (start < _length) { + T min = get(start); + T max = min; + T sum = 0; + uint contributing_threads = 0; + for (uint i = start; i < _length; ++i) { + T value = get(i); + if (value != uninitialized()) { + max = MAX2(max, value); + min = MIN2(min, value); + sum += value; + contributing_threads++; + } + } + T diff = max - min; + assert(contributing_threads != 0, "Must be since we found a used value for the start index"); + double avg = sum / (double) contributing_threads; + WDAPrinter::summary(out, min, avg, max, diff, sum, print_sum); + out->print_cr(", Workers: %d", contributing_threads); + } else { + // No data for this phase. + out->print_cr(" skipped"); } - T diff = max - min; - double avg = sum / (double) active_threads; - WDAPrinter::summary(out, title(), min, avg, max, diff, sum, print_sum); } template -void WorkerDataArray::print_details_on(outputStream* out, uint active_threads) const { - WDAPrinter::details(this, out, active_threads); +void WorkerDataArray::print_details_on(outputStream* out) const { + WDAPrinter::details(this, out); } -#ifndef PRODUCT template void WorkerDataArray::reset() { set_all(uninitialized()); @@ -133,27 +153,4 @@ void WorkerDataArray::reset() { } } -template -void WorkerDataArray::verify(uint active_threads) const { - assert(active_threads <= _length, "Wrong number of active threads"); - for (uint i = 0; i < active_threads; i++) { - assert(_data[i] != uninitialized(), - "Invalid data for worker %u in '%s'", i, _title); - } - if (_thread_work_items != NULL) { - _thread_work_items->verify(active_threads); - } -} - -template <> -inline size_t WorkerDataArray::uninitialized() const { - return (size_t)-1; -} - -template <> -inline double WorkerDataArray::uninitialized() const { - return -1.0; -} -#endif - #endif // SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp index 25b9d21d4fa..5d57d5cb2f1 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.cpp +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegion.inline.hpp" @@ -153,7 +154,7 @@ YoungList::reset_auxilary_lists() { // The region is a non-empty survivor so let's add it to // the incremental collection set for the next evacuation // pause. - _g1h->g1_policy()->add_region_to_incremental_cset_rhs(curr); + _g1h->collection_set()->add_survivor_regions(curr); young_index_in_cset += 1; } assert((uint) young_index_in_cset == _survivor_length, "post-condition"); diff --git a/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp b/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp index f5c591775ba..e2b6bcb377c 100644 --- a/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp +++ b/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp @@ -120,7 +120,7 @@ size_t AdjoiningGenerations::reserved_byte_size() { } void log_before_expansion(bool old, size_t expand_in_bytes, size_t change_in_bytes, size_t max_size) { - LogHandle(heap, ergo) log; + Log(heap, ergo) log; if (!log.is_debug()) { return; } @@ -133,7 +133,7 @@ void log_before_expansion(bool old, size_t expand_in_bytes, size_t change_in_byt } void log_after_expansion(bool old, size_t max_size) { - LogHandle(heap, ergo) log; + Log(heap, ergo) log; if (!log.is_debug()) { return; } diff --git a/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp b/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp index 3adbe0c24ad..11edbdc8c59 100644 --- a/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp @@ -126,7 +126,7 @@ size_t ASPSOldGen::available_for_contraction() { // Also adjust for inter-generational alignment size_t result_aligned = align_size_down(result, gen_alignment); - LogHandle(gc, ergo) log; + Log(gc, ergo) log; if (log.is_trace()) { size_t working_promoted = (size_t) policy->avg_promoted()->padded_average(); size_t promo_increment = policy->promo_increment(max_contraction); diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp index 4cd339886c2..57e91b6d16c 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp @@ -30,6 +30,7 @@ #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.inline.hpp" @@ -404,12 +405,15 @@ void GCTaskManager::initialize() { for (uint t = 0; t < workers(); t += 1) { set_thread(t, GCTaskThread::create(this, t, processor_assignment[t])); } - if (TraceGCTaskThread) { - tty->print("GCTaskManager::initialize: distribution:"); + Log(gc, task, thread) log; + if (log.is_trace()) { + ResourceMark rm; + outputStream* out = log.trace_stream(); + out->print("GCTaskManager::initialize: distribution:"); for (uint t = 0; t < workers(); t += 1) { - tty->print(" %u", processor_assignment[t]); + out->print(" %u", processor_assignment[t]); } - tty->cr(); + out->cr(); } FREE_C_HEAP_ARRAY(uint, processor_assignment); } diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp index f00faf5b7d1..d81db6900e1 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,14 +107,11 @@ void GCTaskThread::run() { this->initialize_named_thread(); // Bind yourself to your processor. if (processor_id() != GCTaskManager::sentinel_worker()) { - if (TraceGCTaskThread) { - tty->print_cr("GCTaskThread::run: " - " binding to processor %u", processor_id()); - } + log_trace(gc, task, thread)("GCTaskThread::run: binding to processor %u", processor_id()); if (!os::bind_to_processor(processor_id())) { DEBUG_ONLY( - warning("Couldn't bind GCTaskThread %u to processor %u", - which(), processor_id()); + log_warning(gc)("Couldn't bind GCTaskThread %u to processor %u", + which(), processor_id()); ) } } diff --git a/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp b/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp index bfef6826e4d..4db21472ec5 100644 --- a/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp +++ b/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp @@ -58,7 +58,7 @@ void MutableSpace::numa_setup_pages(MemRegion mr, bool clear_space) { } void MutableSpace::pretouch_pages(MemRegion mr) { - os::pretouch_memory((char*)mr.start(), (char*)mr.end()); + os::pretouch_memory(mr.start(), mr.end()); } void MutableSpace::initialize(MemRegion mr, diff --git a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp index 76d2e0abd2d..eb4b07f0410 100644 --- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp @@ -325,8 +325,8 @@ HeapWord* ParallelScavengeHeap::mem_allocate( loop_count++; if ((result == NULL) && (QueuedAllocationWarningCount > 0) && (loop_count % QueuedAllocationWarningCount == 0)) { - warning("ParallelScavengeHeap::mem_allocate retries %d times \n\t" - " size=" SIZE_FORMAT, loop_count, size); + log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count); + log_warning(gc)("\tsize=" SIZE_FORMAT, size); } } diff --git a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp index 8d0768556d6..bc58a0dbaec 100644 --- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp +++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" @@ -166,7 +167,7 @@ void RefProcTaskExecutor::execute(ProcessTask& task) ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); - RegionTaskQueueSet* qset = ParCompactionManager::region_array(); + OopTaskQueueSet* qset = ParCompactionManager::stack_array(); ParallelTaskTerminator terminator(active_gc_threads, qset); GCTaskQueue* q = GCTaskQueue::create(); for(uint i=0; isetup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( @@ -533,26 +535,37 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // This is the point where the entire marking should have completed. assert(_marking_stack.is_empty(), "Marking should have completed"); - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); + { + GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer); - // Unload nmethods. - CodeCache::do_unloading(is_alive_closure(), purged_class); + // Unload classes and purge the SystemDictionary. + bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); - // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(is_alive_closure()); + // Unload nmethods. + CodeCache::do_unloading(is_alive_closure(), purged_class); - // Delete entries for dead interned strings. - StringTable::unlink(is_alive_closure()); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(is_alive_closure()); + } + + { + GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer); + // Delete entries for dead interned strings. + StringTable::unlink(is_alive_closure()); + } + + { + GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", _gc_timer); + // Clean up unreferenced symbols in symbol table. + SymbolTable::unlink(); + } - // Clean up unreferenced symbols in symbol table. - SymbolTable::unlink(); _gc_tracer->report_object_count_after_gc(is_alive_closure()); } void PSMarkSweep::mark_sweep_phase2() { - GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer); // Now all live objects are marked, compute the new object addresses. @@ -570,16 +583,9 @@ void PSMarkSweep::mark_sweep_phase2() { old_gen->precompact(); } -// This should be moved to the shared markSweep code! -class PSAlwaysTrueClosure: public BoolObjectClosure { -public: - bool do_object_b(oop p) { return true; } -}; -static PSAlwaysTrueClosure always_true; - void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); @@ -603,7 +609,7 @@ void PSMarkSweep::mark_sweep_phase3() { // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) // Global (weak) JNI handles - JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure()); + JNIHandles::weak_oops_do(adjust_pointer_closure()); CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); @@ -619,7 +625,7 @@ void PSMarkSweep::mark_sweep_phase3() { void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); - GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer); // All pointers are now adjusted, move objects accordingly @@ -638,7 +644,7 @@ jlong PSMarkSweep::millis_since_last_gc() { jlong ret_val = now - _time_of_last_gc; // XXX See note in genCollectedHeap::millis_since_last_gc(). if (ret_val < 0) { - NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);) + NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);) return 0; } return ret_val; diff --git a/hotspot/src/share/vm/gc/parallel/psMarkSweepDecorator.cpp b/hotspot/src/share/vm/gc/parallel/psMarkSweepDecorator.cpp index 74a1f3e639c..b611d99f176 100644 --- a/hotspot/src/share/vm/gc/parallel/psMarkSweepDecorator.cpp +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweepDecorator.cpp @@ -29,7 +29,6 @@ #include "gc/parallel/psMarkSweep.hpp" #include "gc/parallel/psMarkSweepDecorator.hpp" #include "gc/serial/markSweep.inline.hpp" -#include "gc/shared/liveRange.hpp" #include "gc/shared/spaceDecorator.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" @@ -107,9 +106,6 @@ void PSMarkSweepDecorator::precompact() { HeapWord* end_of_live= q; /* One byte beyond the last byte of the last live object. */ HeapWord* first_dead = space()->end(); /* The first dead object. */ - LiveRange* liveRange = NULL; /* The current live range, recorded in the - first header of preceding free area. */ - _first_dead = first_dead; const intx interval = PrefetchScanIntervalInBytes; @@ -231,17 +227,8 @@ void PSMarkSweepDecorator::precompact() { } } - /* for the previous LiveRange, record the end of the live objects. */ - if (liveRange) { - liveRange->set_end(q); - } - - /* record the current LiveRange object. - * liveRange->start() is overlaid on the mark word. - */ - liveRange = (LiveRange*)q; - liveRange->set_start(end); - liveRange->set_end(end); + // q is a pointer to a dead object. Use this dead memory to store a pointer to the next live object. + (*(HeapWord**)q) = end; /* see if this is the first dead region. */ if (q < first_dead) { @@ -254,9 +241,6 @@ void PSMarkSweepDecorator::precompact() { } assert(q == t, "just checking"); - if (liveRange != NULL) { - liveRange->set_end(q); - } _end_of_live = end_of_live; if (end_of_live < first_dead) { first_dead = end_of_live; @@ -307,9 +291,8 @@ void PSMarkSweepDecorator::adjust_pointers() { if (_first_dead == t) { q = t; } else { - // $$$ This is funky. Using this to read the previously written - // LiveRange. See also use below. - q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); + // The first dead object should contain a pointer to the first live object + q = *(HeapWord**)_first_dead; } } const intx interval = PrefetchScanIntervalInBytes; @@ -325,11 +308,11 @@ void PSMarkSweepDecorator::adjust_pointers() { debug_only(prev_q = q); q += size; } else { - // q is not a live object, so its mark should point at the next - // live object debug_only(prev_q = q); - q = (HeapWord*) oop(q)->mark()->decode_pointer(); - assert(q > prev_q, "we should be moving forward through memory"); + // The first dead object is no longer an object. At that memory address, + // there is a pointer to the first live object that the previous phase found. + q = *(HeapWord**)q; + assert(q > prev_q, "we should be moving forward through memory, q: " PTR_FORMAT ", prev_q: " PTR_FORMAT, p2i(q), p2i(prev_q)); } } diff --git a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp index f567fe03e9a..71d48604ac0 100644 --- a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp @@ -309,7 +309,7 @@ bool PSOldGen::expand_to_reserved() { const size_t remaining_bytes = virtual_space()->uncommitted_size(); if (remaining_bytes > 0) { result = expand_by(remaining_bytes); - DEBUG_ONLY(if (!result) warning("grow to reserve failed")); + DEBUG_ONLY(if (!result) log_warning(gc)("grow to reserve failed")); } return result; } diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp index 92a9ba0c496..a309ccd0c7d 100644 --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp @@ -51,6 +51,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" @@ -195,10 +196,10 @@ const char* PSParallelCompact::space_names[] = { }; void PSParallelCompact::print_region_ranges() { - if (!log_develop_is_enabled(Trace, gc, compaction, phases)) { + if (!log_develop_is_enabled(Trace, gc, compaction)) { return; } - LogHandle(gc, compaction, phases) log; + Log(gc, compaction) log; ResourceMark rm; Universe::print_on(log.trace_stream()); log.trace("space bottom top end new_top"); @@ -225,7 +226,7 @@ print_generic_summary_region(size_t i, const ParallelCompactData::RegionData* c) ParallelCompactData& sd = PSParallelCompact::summary_data(); size_t dci = c->destination() ? sd.addr_to_region_idx(c->destination()) : 0; - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( REGION_IDX_FORMAT " " PTR_FORMAT " " REGION_IDX_FORMAT " " PTR_FORMAT " " REGION_DATA_FORMAT " " REGION_DATA_FORMAT " " @@ -258,14 +259,14 @@ print_generic_summary_data(ParallelCompactData& summary_data, ++i; } - log_develop_trace(gc, compaction, phases)("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize); + log_develop_trace(gc, compaction)("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize); } void print_generic_summary_data(ParallelCompactData& summary_data, SpaceInfo* space_info) { - if (!log_develop_is_enabled(Trace, gc, compaction, phases)) { + if (!log_develop_is_enabled(Trace, gc, compaction)) { return; } @@ -296,7 +297,7 @@ print_initial_summary_data(ParallelCompactData& summary_data, size_t i = summary_data.addr_to_region_idx(space->bottom()); while (i < end_region && summary_data.region(i)->data_size() == region_size) { ParallelCompactData::RegionData* c = summary_data.region(i); - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d", i, p2i(c->destination()), c->partial_obj_size(), c->live_obj_size(), @@ -330,7 +331,7 @@ print_initial_summary_data(ParallelCompactData& summary_data, } ParallelCompactData::RegionData* c = summary_data.region(i); - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d" "%12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10), i, p2i(c->destination()), @@ -346,21 +347,21 @@ print_initial_summary_data(ParallelCompactData& summary_data, // Any remaining regions are empty. Print one more if there is one. if (i < end_region) { ParallelCompactData::RegionData* c = summary_data.region(i); - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d", i, p2i(c->destination()), c->partial_obj_size(), c->live_obj_size(), c->data_size(), c->source_region(), c->destination_count()); } - log_develop_trace(gc, compaction, phases)("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f", - max_reclaimed_ratio_region, max_dead_to_right, max_live_to_right, max_reclaimed_ratio); + log_develop_trace(gc, compaction)("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f", + max_reclaimed_ratio_region, max_dead_to_right, max_live_to_right, max_reclaimed_ratio); } void print_initial_summary_data(ParallelCompactData& summary_data, SpaceInfo* space_info) { - if (!log_develop_is_enabled(Trace, gc, compaction, phases)) { + if (!log_develop_is_enabled(Trace, gc, compaction)) { return; } @@ -621,7 +622,7 @@ ParallelCompactData::summarize_split_space(size_t src_region, sr->partial_obj_size())); const size_t end_idx = addr_to_region_idx(target_end); - log_develop_trace(gc, compaction, phases)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx); + log_develop_trace(gc, compaction)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx); for (size_t idx = beg_idx; idx < end_idx; ++idx) { _region_data[idx].set_source_region(0); } @@ -641,22 +642,22 @@ ParallelCompactData::summarize_split_space(size_t src_region, *target_next = split_destination + partial_obj_size; HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size; - if (log_develop_is_enabled(Trace, gc, compaction, phases)) { + if (log_develop_is_enabled(Trace, gc, compaction)) { const char * split_type = partial_obj_size == 0 ? "easy" : "hard"; - log_develop_trace(gc, compaction, phases)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT, - split_type, p2i(source_next), split_region, partial_obj_size); - log_develop_trace(gc, compaction, phases)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT, - split_type, p2i(split_destination), - addr_to_region_idx(split_destination), - p2i(*target_next)); + log_develop_trace(gc, compaction)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT, + split_type, p2i(source_next), split_region, partial_obj_size); + log_develop_trace(gc, compaction)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT, + split_type, p2i(split_destination), + addr_to_region_idx(split_destination), + p2i(*target_next)); if (partial_obj_size != 0) { HeapWord* const po_beg = split_info.destination(); HeapWord* const po_end = po_beg + split_info.partial_obj_size(); - log_develop_trace(gc, compaction, phases)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT, - split_type, - p2i(po_beg), addr_to_region_idx(po_beg), - p2i(po_end), addr_to_region_idx(po_end)); + log_develop_trace(gc, compaction)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT, + split_type, + p2i(po_beg), addr_to_region_idx(po_beg), + p2i(po_end), addr_to_region_idx(po_end)); } } @@ -670,7 +671,7 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, HeapWord** target_next) { HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next; - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( "sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, p2i(source_beg), p2i(source_end), p2i(source_next_val), @@ -938,7 +939,7 @@ void PSParallelCompact::pre_compact() // at each young gen gc. Do the update unconditionally (even though a // promotion failure does not swap spaces) because an unknown number of young // collections will have swapped the spaces an unknown number of times. - GCTraceTime(Trace, gc, phases) tm("Pre Compact", &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Pre Compact", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -981,7 +982,7 @@ void PSParallelCompact::pre_compact() void PSParallelCompact::post_compact() { - GCTraceTime(Trace, gc, phases) tm("Post Compact", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Post Compact", &_gc_timer); for (unsigned int id = old_space_id; id < last_space_id; ++id) { // Clear the marking bitmap, summary data and split info. @@ -1524,7 +1525,7 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) } } - if (log_develop_is_enabled(Trace, gc, compaction, phases)) { + if (log_develop_is_enabled(Trace, gc, compaction)) { const size_t region_size = ParallelCompactData::RegionSize; HeapWord* const dense_prefix_end = _space_info[id].dense_prefix(); const size_t dp_region = _summary_data.addr_to_region_idx(dense_prefix_end); @@ -1532,7 +1533,7 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) HeapWord* const new_top = _space_info[id].new_top(); const HeapWord* nt_aligned_up = _summary_data.region_align_up(new_top); const size_t cr_words = pointer_delta(nt_aligned_up, dense_prefix_end); - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( "id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " " "dp_region=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " " "cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT, @@ -1548,7 +1549,7 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, SpaceId src_space_id, HeapWord* src_beg, HeapWord* src_end) { - log_develop_trace(gc, compaction, phases)( + log_develop_trace(gc, compaction)( "Summarizing %d [%s] into %d [%s]: " "src=" PTR_FORMAT "-" PTR_FORMAT " " SIZE_FORMAT "-" SIZE_FORMAT " " @@ -1568,7 +1569,7 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - GCTraceTime(Trace, gc, phases) tm("Summary Phase", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); #ifdef ASSERT if (TraceParallelOldGCMarkingPhase) { @@ -1584,7 +1585,7 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, // Quick summarization of each space into itself, to see how much is live. summarize_spaces_quick(); - log_develop_trace(gc, compaction, phases)("summary phase: after summarizing each space to self"); + log_develop_trace(gc, compaction)("summary phase: after summarizing each space to self"); NOT_PRODUCT(print_region_ranges()); NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info)); @@ -1660,7 +1661,7 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, } } - log_develop_trace(gc, compaction, phases)("Summary_phase: after final summarization"); + log_develop_trace(gc, compaction)("Summary_phase: after final summarization"); NOT_PRODUCT(print_region_ranges()); NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info)); } @@ -2042,12 +2043,12 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction, ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them - GCTraceTime(Trace, gc, phases) tm("Marking Phase", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); - TaskQueueSetSuper* qset = ParCompactionManager::region_array(); + TaskQueueSetSuper* qset = ParCompactionManager::stack_array(); ParallelTaskTerminator terminator(active_gc_threads, qset); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -2057,7 +2058,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, ClassLoaderDataGraph::clear_claimed_marks(); { - GCTraceTime(Trace, gc, phases) tm("Par Mark", &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Par Mark", &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; @@ -2086,7 +2087,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, // Process reference objects found during marking { - GCTraceTime(Trace, gc, phases) tm("Reference Processing", &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer); ReferenceProcessorStats stats; if (ref_processor()->processing_is_mt()) { @@ -2103,38 +2104,40 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, gc_tracer->report_gc_reference_stats(stats); } - GCTraceTime(Trace, gc) tm_m("Class Unloading", &_gc_timer); - // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); - // Follow system dictionary roots and unload classes. - bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); + { + GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer); - // Unload nmethods. - CodeCache::do_unloading(is_alive_closure(), purged_class); + // Follow system dictionary roots and unload classes. + bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); - // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(is_alive_closure()); + // Unload nmethods. + CodeCache::do_unloading(is_alive_closure(), purged_class); - // Delete entries for dead interned strings. - StringTable::unlink(is_alive_closure()); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(is_alive_closure()); + } + + { + GCTraceTime(Debug, gc, phases) t("Scrub String Table", &_gc_timer); + // Delete entries for dead interned strings. + StringTable::unlink(is_alive_closure()); + } + + { + GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", &_gc_timer); + // Clean up unreferenced symbols in symbol table. + SymbolTable::unlink(); + } - // Clean up unreferenced symbols in symbol table. - SymbolTable::unlink(); _gc_tracer.report_object_count_after_gc(is_alive_closure()); } -// This should be moved to the shared markSweep code! -class PSAlwaysTrueClosure: public BoolObjectClosure { -public: - bool do_object_b(oop p) { return true; } -}; -static PSAlwaysTrueClosure always_true; - void PSParallelCompact::adjust_roots(ParCompactionManager* cm) { // Adjust the pointers to reflect the new locations - GCTraceTime(Trace, gc, phases) tm("Adjust Roots", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Adjust Roots", &_gc_timer); // Need new claim bits when tracing through and adjusting pointers. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2157,7 +2160,7 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) { // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) // Global (weak) JNI handles - JNIHandles::weak_oops_do(&always_true, &oop_closure); + JNIHandles::weak_oops_do(&oop_closure); CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); @@ -2173,7 +2176,7 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) { // Helper class to print 8 region numbers per line and then print the total at the end. class FillableRegionLogger : public StackObj { private: - LogHandle(gc, compaction) log; + Log(gc, compaction) log; static const int LineLength = 8; size_t _regions[LineLength]; int _next_index; @@ -2375,7 +2378,7 @@ void PSParallelCompact::write_block_fill_histogram() return; } - LogHandle(gc, compaction) log; + Log(gc, compaction) log; ResourceMark rm; outputStream* out = log.trace_stream(); @@ -2408,7 +2411,7 @@ void PSParallelCompact::write_block_fill_histogram() #endif // #ifdef ASSERT void PSParallelCompact::compact() { - GCTraceTime(Trace, gc, phases) tm("Compaction Phase", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Compaction Phase", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); @@ -2467,9 +2470,8 @@ void PSParallelCompact::verify_complete(SpaceId space_id) { for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) { const RegionData* const c = sd.region(cur_region); if (!c->completed()) { - warning("region " SIZE_FORMAT " not filled: " - "destination_count=%u", - cur_region, c->destination_count()); + log_warning(gc)("region " SIZE_FORMAT " not filled: destination_count=%u", + cur_region, c->destination_count()); issued_a_warning = true; } } @@ -2477,9 +2479,8 @@ void PSParallelCompact::verify_complete(SpaceId space_id) { for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) { const RegionData* const c = sd.region(cur_region); if (!c->available()) { - warning("region " SIZE_FORMAT " not empty: " - "destination_count=%u", - cur_region, c->destination_count()); + log_warning(gc)("region " SIZE_FORMAT " not empty: destination_count=%u", + cur_region, c->destination_count()); issued_a_warning = true; } } @@ -3013,7 +3014,7 @@ jlong PSParallelCompact::millis_since_last_gc() { jlong ret_val = now - _time_of_last_gc; // XXX See note in genCollectedHeap::millis_since_last_gc(). if (ret_val < 0) { - NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);) + NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);) return 0; } return ret_val; diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp index a147cd77ad3..a5bf57903d4 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,13 @@ #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psScavenge.inline.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "memory/padded.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp" @@ -41,6 +43,7 @@ PaddedEnd* PSPromotionManager::_manager_array = NULL; OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL; +PreservedMarksSet* PSPromotionManager::_preserved_marks_set = NULL; PSOldGen* PSPromotionManager::_old_gen = NULL; MutableSpace* PSPromotionManager::_young_space = NULL; @@ -50,10 +53,12 @@ void PSPromotionManager::initialize() { _old_gen = heap->old_gen(); _young_space = heap->young_gen()->to_space(); + const uint promotion_manager_num = ParallelGCThreads + 1; + // To prevent false sharing, we pad the PSPromotionManagers // and make sure that the first instance starts at a cache line. assert(_manager_array == NULL, "Attempt to initialize twice"); - _manager_array = PaddedArray::create_unfreeable(ParallelGCThreads + 1); + _manager_array = PaddedArray::create_unfreeable(promotion_manager_num); guarantee(_manager_array != NULL, "Could not initialize promotion manager"); _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); @@ -65,6 +70,14 @@ void PSPromotionManager::initialize() { } // The VMThread gets its own PSPromotionManager, which is not available // for work stealing. + + assert(_preserved_marks_set == NULL, "Attempt to initialize twice"); + _preserved_marks_set = new PreservedMarksSet(true /* in_c_heap */); + guarantee(_preserved_marks_set != NULL, "Could not initialize preserved marks set"); + _preserved_marks_set->init(promotion_manager_num); + for (uint i = 0; i < promotion_manager_num; i += 1) { + _manager_array[i].register_preserved_marks(_preserved_marks_set->get(i)); + } } // Helper functions to get around the circular dependency between @@ -90,6 +103,7 @@ PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() { void PSPromotionManager::pre_scavenge() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + _preserved_marks_set->assert_empty(); _young_space = heap->young_gen()->to_space(); for(uint i=0; iflush_labs(); } + if (!promotion_failure_occurred) { + // If there was no promotion failure, the preserved mark stacks + // should be empty. + _preserved_marks_set->assert_empty(); + } return promotion_failure_occurred; } @@ -133,7 +152,7 @@ PSPromotionManager::print_taskqueue_stats() { if (!log_develop_is_enabled(Trace, gc, task, stats)) { return; } - LogHandle(gc, task, stats) log; + Log(gc, task, stats) log; ResourceMark rm; outputStream* out = log.trace_stream(); out->print_cr("== GC Tasks Stats, GC %3d", @@ -187,6 +206,8 @@ PSPromotionManager::PSPromotionManager() { // let's choose 1.5x the chunk size _min_array_size_for_chunking = 3 * _array_chunk_size / 2; + _preserved_marks = NULL; + reset(); } @@ -211,6 +232,10 @@ void PSPromotionManager::reset() { TASKQUEUE_STATS_ONLY(reset_stats()); } +void PSPromotionManager::register_preserved_marks(PreservedMarks* preserved_marks) { + assert(_preserved_marks == NULL, "do not set it twice"); + _preserved_marks = preserved_marks; +} void PSPromotionManager::drain_stacks_depth(bool totally_drain) { totally_drain = totally_drain || _totally_drain; @@ -422,8 +447,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { push_contents(obj); - // Save the mark if needed - PSScavenge::oop_promotion_failed(obj, obj_mark); + _preserved_marks->push_if_necessary(obj, obj_mark); } else { // We lost, someone else "owns" this object guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed."); diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp index ba51850550d..32159e6a48c 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp @@ -28,6 +28,7 @@ #include "gc/parallel/psPromotionLAB.hpp" #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/preservedMarks.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/allocation.hpp" #include "memory/padded.hpp" @@ -55,6 +56,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC { private: static PaddedEnd* _manager_array; static OopStarTaskQueueSet* _stack_array_depth; + static PreservedMarksSet* _preserved_marks_set; static PSOldGen* _old_gen; static MutableSpace* _young_space; @@ -84,6 +86,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC { uint _array_chunk_size; uint _min_array_size_for_chunking; + PreservedMarks* _preserved_marks; PromotionFailedInfo _promotion_failed_info; // Accessors @@ -176,6 +179,8 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC { oop oop_promotion_failed(oop obj, markOop obj_mark); void reset(); + void register_preserved_marks(PreservedMarks* preserved_marks); + static void restore_preserved_marks() { _preserved_marks_set->restore(); } void flush_labs(); void drain_stacks(bool totally_drain) { diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp index 43467237258..b027d68fa70 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp @@ -68,8 +68,6 @@ uintptr_t PSScavenge::_young_generation_boundary_compressed = 0 elapsedTimer PSScavenge::_accumulated_time; STWGCTimer PSScavenge::_gc_timer; ParallelScavengeTracer PSScavenge::_gc_tracer; -Stack PSScavenge::_preserved_mark_stack; -Stack PSScavenge::_preserved_oop_stack; CollectorCounters* PSScavenge::_counters = NULL; // Define before use @@ -123,14 +121,6 @@ class PSEvacuateFollowersClosure: public VoidClosure { } }; -class PSPromotionFailedClosure : public ObjectClosure { - virtual void do_object(oop obj) { - if (obj->is_forwarded()) { - obj->init_mark(); - } - } -}; - class PSRefProcTaskProxy: public GCTask { typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; ProcessTask & _rp_task; @@ -257,9 +247,6 @@ bool PSScavenge::invoke_no_policy() { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(_preserved_mark_stack.is_empty(), "should be empty"); - assert(_preserved_oop_stack.is_empty(), "should be empty"); - _gc_timer.register_gc_start(); TimeStamp scavenge_entry; @@ -417,7 +404,7 @@ bool PSScavenge::invoke_no_policy() { // Process reference objects discovered during scavenge { - GCTraceTime(Debug, gc, phases) tm("References", &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer); reference_processor()->setup_policy(false); // not always_clear reference_processor()->set_active_mt_degree(active_workers); @@ -446,7 +433,7 @@ bool PSScavenge::invoke_no_policy() { } { - GCTraceTime(Debug, gc, phases) tm("StringTable", &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Scrub String Table", &_gc_timer); // Unlink any dead interned Strings and process the remaining live ones. PSScavengeRootsClosure root_closure(promotion_manager); StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); @@ -656,52 +643,20 @@ bool PSScavenge::invoke_no_policy() { } // This method iterates over all objects in the young generation, -// unforwarding markOops. It then restores any preserved mark oops, -// and clears the _preserved_mark_stack. +// removing all forwarding references. It then restores any preserved marks. void PSScavenge::clean_up_failed_promotion() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); - { - ResourceMark rm; + RemoveForwardedPointerClosure remove_fwd_ptr_closure; + young_gen->object_iterate(&remove_fwd_ptr_closure); - // Unforward all pointers in the young gen. - PSPromotionFailedClosure unforward_closure; - young_gen->object_iterate(&unforward_closure); - - log_trace(gc, ergo)("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size()); - - // Restore any saved marks. - while (!_preserved_oop_stack.is_empty()) { - oop obj = _preserved_oop_stack.pop(); - markOop mark = _preserved_mark_stack.pop(); - obj->set_mark(mark); - } - - // Clear the preserved mark and oop stack caches. - _preserved_mark_stack.clear(true); - _preserved_oop_stack.clear(true); - } + PSPromotionManager::restore_preserved_marks(); // Reset the PromotionFailureALot counters. NOT_PRODUCT(heap->reset_promotion_should_fail();) } -// This method is called whenever an attempt to promote an object -// fails. Some markOops will need preservation, some will not. Note -// that the entire eden is traversed after a failed promotion, with -// all forwarded headers replaced by the default markOop. This means -// it is not necessary to preserve most markOops. -void PSScavenge::oop_promotion_failed(oop obj, markOop obj_mark) { - if (obj_mark->must_be_preserved_for_promotion_failure(obj)) { - // Should use per-worker private stacks here rather than - // locking a common pair of stacks. - ThreadCritical tc; - _preserved_oop_stack.push(obj); - _preserved_mark_stack.push(obj_mark); - } -} - bool PSScavenge::should_attempt_scavenge() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.hpp b/hotspot/src/share/vm/gc/parallel/psScavenge.hpp index 3fb235f043d..e3c870c4297 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.hpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.hpp @@ -79,8 +79,6 @@ class PSScavenge: AllStatic { static HeapWord* _young_generation_boundary; // Used to optimize compressed oops young gen boundary checking. static uintptr_t _young_generation_boundary_compressed; - static Stack _preserved_mark_stack; // List of marks to be restored after failed promotion - static Stack _preserved_oop_stack; // List of oops that need their mark restored. static CollectorCounters* _counters; // collector performance counters static void clean_up_failed_promotion(); @@ -127,9 +125,6 @@ class PSScavenge: AllStatic { // Return true if a collection was done; false otherwise. static bool invoke_no_policy(); - // If an attempt to promote fails, this method is invoked - static void oop_promotion_failed(oop obj, markOop obj_mark); - template static inline bool should_scavenge(T* p); // These call should_scavenge() above and, if it returns true, also check that diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp index 5dab7373a72..f7e98688277 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp @@ -31,6 +31,7 @@ #include "gc/parallel/psScavenge.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "utilities/globalDefinitions.hpp" inline void PSScavenge::save_to_space_top_before_gc() { diff --git a/hotspot/src/share/vm/gc/parallel/psTasks.cpp b/hotspot/src/share/vm/gc/parallel/psTasks.cpp index 2a1584e7578..4f372f9f0b0 100644 --- a/hotspot/src/share/vm/gc/parallel/psTasks.cpp +++ b/hotspot/src/share/vm/gc/parallel/psTasks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ #include "gc/parallel/psTasks.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" #include "runtime/fprofiler.hpp" diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp index 08a21b2634f..a9b404604b0 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp @@ -43,6 +43,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -460,11 +461,11 @@ void DefNewGeneration::compute_new_size() { (HeapWord*)_virtual_space.high()); gch->barrier_set()->resize_covered_region(cmr); - log_debug(gc, heap, ergo)( + log_debug(gc, ergo, heap)( "New generation size " SIZE_FORMAT "K->" SIZE_FORMAT "K [eden=" SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]", new_size_before/K, _virtual_space.committed_size()/K, eden()->capacity()/K, from()->capacity()/K); - log_trace(gc, heap, ergo)( + log_trace(gc, ergo, heap)( " [allowed " SIZE_FORMAT "K extra for %d threads]", thread_increase_size/K, threads_count); } @@ -594,7 +595,7 @@ void DefNewGeneration::collect(bool full, init_assuming_no_promotion_failure(); - GCTraceTime(Trace, gc) tm("DefNew", NULL, gch->gc_cause()); + GCTraceTime(Trace, gc, phases) tm("DefNew", NULL, gch->gc_cause()); gch->trace_heap_before_gc(&gc_tracer); diff --git a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp index 8bb4c203a16..9a3bb7e27de 100644 --- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp +++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp @@ -180,7 +180,7 @@ void GenMarkSweep::deallocate_stacks() { void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", _gc_timer); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -208,6 +208,8 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Process reference objects found during marking { + GCTraceTime(Debug, gc, phases) tm_m("Reference Processing", gc_timer()); + ref_processor()->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( @@ -218,20 +220,30 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // This is the point where the entire marking should have completed. assert(_marking_stack.is_empty(), "Marking should have completed"); - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&is_alive); + { + GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer()); - // Unload nmethods. - CodeCache::do_unloading(&is_alive, purged_class); + // Unload classes and purge the SystemDictionary. + bool purged_class = SystemDictionary::do_unloading(&is_alive); - // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(&is_alive); + // Unload nmethods. + CodeCache::do_unloading(&is_alive, purged_class); - // Delete entries for dead interned strings. - StringTable::unlink(&is_alive); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(&is_alive); + } - // Clean up unreferenced symbols in symbol table. - SymbolTable::unlink(); + { + GCTraceTime(Debug, gc, phases) t("Scrub String Table", gc_timer()); + // Delete entries for dead interned strings. + StringTable::unlink(&is_alive); + } + + { + GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", gc_timer()); + // Clean up unreferenced symbols in symbol table. + SymbolTable::unlink(); + } gc_tracer()->report_object_count_after_gc(&is_alive); } @@ -253,7 +265,7 @@ void GenMarkSweep::mark_sweep_phase2() { GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer); gch->prepare_for_compaction(); } @@ -269,7 +281,7 @@ void GenMarkSweep::mark_sweep_phase3() { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer()); // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); @@ -321,7 +333,7 @@ void GenMarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer); + GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer); GenCompactClosure blk; gch->generation_iterate(&blk, true); diff --git a/hotspot/src/share/vm/gc/shared/barrierSet.cpp b/hotspot/src/share/vm/gc/shared/barrierSet.cpp index 6b60fed1aaa..a45c216554a 100644 --- a/hotspot/src/share/vm/gc/shared/barrierSet.cpp +++ b/hotspot/src/share/vm/gc/shared/barrierSet.cpp @@ -30,10 +30,6 @@ // count is number of array elements being written void BarrierSet::static_write_ref_array_pre(HeapWord* start, size_t count) { assert(count <= (size_t)max_intx, "count too large"); -#if 0 - warning("Pre: \t" INTPTR_FORMAT "[" SIZE_FORMAT "]\t", - start, count); -#endif if (UseCompressedOops) { Universe::heap()->barrier_set()->write_ref_array_pre((narrowOop*)start, (int)count, false); } else { diff --git a/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp b/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp index cbbc36a70e6..1fa414da1ba 100644 --- a/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp @@ -78,10 +78,6 @@ void BarrierSet::write_ref_array(HeapWord* start, size_t count) { // If compressed oops were not being used, these should already be aligned assert(UseCompressedOops || (aligned_start == start && aligned_end == end), "Expected heap word alignment of start and end"); -#if 0 - warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT "," INTPTR_FORMAT ")\t", - start, count, aligned_start, aligned_end); -#endif write_ref_array_work(MemRegion(aligned_start, aligned_end)); } diff --git a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp index dd448d4cf25..9acb3802d3c 100644 --- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp +++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,7 +144,7 @@ bool CardGeneration::grow_to_reserved() { const size_t remaining_bytes = _virtual_space.uncommitted_size(); if (remaining_bytes > 0) { success = grow_by(remaining_bytes); - DEBUG_ONLY(if (!success) warning("grow to reserved failed");) + DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");) } return success; } @@ -254,19 +254,22 @@ void CardGeneration::compute_new_size() { if (capacity_after_gc > maximum_desired_capacity) { // Capacity too large, compute shrinking size shrink_bytes = capacity_after_gc - maximum_desired_capacity; - // We don't want shrink all the way back to initSize if people call - // System.gc(), because some programs do that between "phases" and then - // we'd just have to grow the heap up again for the next phase. So we - // damp the shrinking: 0% on the first call, 10% on the second call, 40% - // on the third call, and 100% by the fourth call. But if we recompute - // size without shrinking, it goes back to 0%. - shrink_bytes = shrink_bytes / 100 * current_shrink_factor; - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - if (current_shrink_factor == 0) { - _shrink_factor = 10; - } else { - _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); + if (ShrinkHeapInSteps) { + // If ShrinkHeapInSteps is true (the default), + // we don't want to shrink all the way back to initSize if people call + // System.gc(), because some programs do that between "phases" and then + // we'd just have to grow the heap up again for the next phase. So we + // damp the shrinking: 0% on the first call, 10% on the second call, 40% + // on the third call, and 100% by the fourth call. But if we recompute + // size without shrinking, it goes back to 0%. + shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + if (current_shrink_factor == 0) { + _shrink_factor = 10; + } else { + _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); + } } + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", initial_size() / (double) K, maximum_desired_capacity / (double) K); log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp index ec37fb7cd9f..e40cc62ca47 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp @@ -500,16 +500,14 @@ void CardTableModRefBS::verify_region(MemRegion mr, bool failed = (val_equals) ? (curr_val != val) : (curr_val == val); if (failed) { if (!failures) { - tty->cr(); - tty->print_cr("== CT verification failed: [" INTPTR_FORMAT "," INTPTR_FORMAT "]", p2i(start), p2i(end)); - tty->print_cr("== %sexpecting value: %d", - (val_equals) ? "" : "not ", val); + log_error(gc, verify)("== CT verification failed: [" INTPTR_FORMAT "," INTPTR_FORMAT "]", p2i(start), p2i(end)); + log_error(gc, verify)("== %sexpecting value: %d", (val_equals) ? "" : "not ", val); failures = true; } - tty->print_cr("== card " PTR_FORMAT " [" PTR_FORMAT "," PTR_FORMAT "], " - "val: %d", p2i(curr), p2i(addr_for(curr)), - p2i((HeapWord*) (((size_t) addr_for(curr)) + card_size)), - (int) curr_val); + log_error(gc, verify)("== card " PTR_FORMAT " [" PTR_FORMAT "," PTR_FORMAT "], val: %d", + p2i(curr), p2i(addr_for(curr)), + p2i((HeapWord*) (((size_t) addr_for(curr)) + card_size)), + (int) curr_val); } } guarantee(!failures, "there should not have been any failures"); diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp index 1ede220ab61..89084ca8ac2 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,14 +89,6 @@ class CardTableModRefBS: public ModRefBarrierSet { MemRegion _guard_region; protected: - // Initialization utilities; covered_words is the size of the covered region - // in, um, words. - inline size_t cards_required(size_t covered_words) { - // Add one for a guard card, used to detect errors. - const size_t words = align_size_up(covered_words, card_size_in_words); - return words / card_size_in_words + 1; - } - inline size_t compute_byte_map_size(); // Finds and return the index of the region, if any, to which the given @@ -172,6 +164,14 @@ public: bool has_write_ref_pre_barrier() { return false; } + // Initialization utilities; covered_words is the size of the covered region + // in, um, words. + inline size_t cards_required(size_t covered_words) { + // Add one for a guard card, used to detect errors. + const size_t words = align_size_up(covered_words, card_size_in_words); + return words / card_size_in_words + 1; + } + protected: CardTableModRefBS(MemRegion whole_heap, const BarrierSet::FakeRtti& fake_rtti); diff --git a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp index b26d8739531..5e28170a2aa 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -325,17 +325,17 @@ void CardTableRS::younger_refs_in_space_iterate(Space* sp, // In the case of CMS+ParNew, issue a warning if (!ur.contains(urasm)) { assert(UseConcMarkSweepGC, "Tautology: see assert above"); - warning("CMS+ParNew: Did you forget to call save_marks()? " - "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end())); + log_warning(gc)("CMS+ParNew: Did you forget to call save_marks()? " + "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end())); MemRegion ur2 = sp->used_region(); MemRegion urasm2 = sp->used_region_at_save_marks(); if (!ur.equals(ur2)) { - warning("CMS+ParNew: Flickering used_region()!!"); + log_warning(gc)("CMS+ParNew: Flickering used_region()!!"); } if (!urasm.equals(urasm2)) { - warning("CMS+ParNew: Flickering used_region_at_save_marks()!!"); + log_warning(gc)("CMS+ParNew: Flickering used_region_at_save_marks()!!"); } ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index f132d75e860..cfd55ad3dc7 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -35,6 +35,7 @@ #include "gc/shared/vmGCOperations.hpp" #include "logging/log.hpp" #include "memory/metaspace.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" @@ -213,7 +214,7 @@ void CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { do_full_collection(false); // don't clear all soft refs break; } - case GCCause::_last_ditch_collection: { + case GCCause::_metadata_GC_clear_soft_refs: { HandleMark hm; do_full_collection(true); // do clear all soft refs break; @@ -580,7 +581,7 @@ void CollectedHeap::full_gc_dump(GCTimer* timer, bool before) { HeapDumper::dump_heap(); } - LogHandle(gc, classhisto) log; + Log(gc, classhisto) log; if (log.is_trace()) { GCTraceTime(Trace, gc, classhisto) tm(before ? "Class Histogram (before full gc)" : "Class Histogram (after full gc)", timer); ResourceMark rm; diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp index 613397b02d6..4c0e8d9cb1b 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp @@ -438,6 +438,12 @@ class CollectedHeap : public CHeapObj { // remembered set. virtual void flush_deferred_store_barrier(JavaThread* thread); + // Should return true if the reference pending list lock is + // acquired from non-Java threads, such as a concurrent GC thread. + virtual bool needs_reference_pending_list_locker_thread() const { + return false; + } + // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the // "CollectedHeap" supports. diff --git a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp index bdfe9688818..1cb05979fac 100644 --- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp @@ -96,6 +96,9 @@ void CollectorPolicy::initialize_flags() { } // Check heap parameter properties + if (MaxHeapSize < 2 * M) { + vm_exit_during_initialization("Too small maximum heap"); + } if (InitialHeapSize < M) { vm_exit_during_initialization("Too small initial heap"); } diff --git a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp index 1e44c62f7dc..322931e977d 100644 --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp @@ -37,12 +37,12 @@ ConcurrentGCThread::ConcurrentGCThread() : _should_terminate(false), _has_terminated(false) { }; -void ConcurrentGCThread::create_and_start() { +void ConcurrentGCThread::create_and_start(ThreadPriority prio) { if (os::create_thread(this, os::cgc_thread)) { // XXX: need to set this to low priority // unless "aggressive mode" set; priority // should be just less than that of VMThread. - os::set_priority(this, NearMaxPriority); + os::set_priority(this, prio); if (!_should_terminate && !DisableStartThread) { os::start_thread(this); } @@ -75,130 +75,30 @@ void ConcurrentGCThread::terminate() { } } -static void _sltLoop(JavaThread* thread, TRAPS) { - SurrogateLockerThread* slt = (SurrogateLockerThread*)thread; - slt->loop(); +void ConcurrentGCThread::run() { + initialize_in_thread(); + wait_for_universe_init(); + + run_service(); + + terminate(); } -SurrogateLockerThread::SurrogateLockerThread() : - JavaThread(&_sltLoop), - _monitor(Mutex::nonleaf, "SLTMonitor", false, - Monitor::_safepoint_check_sometimes), - _buffer(empty) -{} - -SurrogateLockerThread* SurrogateLockerThread::make(TRAPS) { - Klass* k = - SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), - true, CHECK_NULL); - instanceKlassHandle klass (THREAD, k); - instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL); - - const char thread_name[] = "Surrogate Locker Thread (Concurrent GC)"; - Handle string = java_lang_String::create_from_str(thread_name, CHECK_NULL); - - // Initialize thread_oop to put it into the system threadGroup - Handle thread_group (THREAD, Universe::system_thread_group()); - JavaValue result(T_VOID); - JavaCalls::call_special(&result, thread_oop, - klass, - vmSymbols::object_initializer_name(), - vmSymbols::threadgroup_string_void_signature(), - thread_group, - string, - CHECK_NULL); - - SurrogateLockerThread* res; +void ConcurrentGCThread::stop() { + // it is ok to take late safepoints here, if needed { - MutexLocker mu(Threads_lock); - res = new SurrogateLockerThread(); - - // At this point it may be possible that no osthread was created for the - // JavaThread due to lack of memory. We would have to throw an exception - // in that case. However, since this must work and we do not allow - // exceptions anyway, check and abort if this fails. - if (res == NULL || res->osthread() == NULL) { - vm_exit_during_initialization("java.lang.OutOfMemoryError", - os::native_thread_creation_failed_msg()); - } - java_lang_Thread::set_thread(thread_oop(), res); - java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); - java_lang_Thread::set_daemon(thread_oop()); - - res->set_threadObj(thread_oop()); - Threads::add(res); - Thread::start(res); + MutexLockerEx mu(Terminator_lock); + assert(!_has_terminated, "stop should only be called once"); + assert(!_should_terminate, "stop should only be called once"); + _should_terminate = true; } - os::naked_yield(); // This seems to help with initial start-up of SLT - return res; -} -void SurrogateLockerThread::report_missing_slt() { - vm_exit_during_initialization( - "GC before GC support fully initialized: " - "SLT is needed but has not yet been created."); - ShouldNotReachHere(); -} + stop_service(); -void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) { - MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); - assert(_buffer == empty, "Should be empty"); - assert(msg != empty, "empty message"); - assert(!Heap_lock->owned_by_self(), "Heap_lock owned by requesting thread"); - - _buffer = msg; - while (_buffer != empty) { - _monitor.notify(); - _monitor.wait(Mutex::_no_safepoint_check_flag); + { + MutexLockerEx mu(Terminator_lock); + while (!_has_terminated) { + Terminator_lock->wait(); + } } } - -// ======= Surrogate Locker Thread ============= - -void SurrogateLockerThread::loop() { - BasicLock pll_basic_lock; - SLT_msg_type msg; - debug_only(unsigned int owned = 0;) - - while (/* !isTerminated() */ 1) { - { - MutexLocker x(&_monitor); - // Since we are a JavaThread, we can't be here at a safepoint. - assert(!SafepointSynchronize::is_at_safepoint(), - "SLT is a JavaThread"); - // wait for msg buffer to become non-empty - while (_buffer == empty) { - _monitor.notify(); - _monitor.wait(); - } - msg = _buffer; - } - switch(msg) { - case acquirePLL: { - InstanceRefKlass::acquire_pending_list_lock(&pll_basic_lock); - debug_only(owned++;) - break; - } - case releaseAndNotifyPLL: { - assert(owned > 0, "Don't have PLL"); - InstanceRefKlass::release_and_notify_pending_list_lock(&pll_basic_lock); - debug_only(owned--;) - break; - } - case empty: - default: { - guarantee(false,"Unexpected message in _buffer"); - break; - } - } - { - MutexLocker x(&_monitor); - // Since we are a JavaThread, we can't be here at a safepoint. - assert(!SafepointSynchronize::is_at_safepoint(), - "SLT is a JavaThread"); - _buffer = empty; - _monitor.notify(); - } - } - assert(!_monitor.owned_by_self(), "Should unlock before exit."); -} diff --git a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp index a6dc3b5c1b3..6b7b3d4298f 100644 --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp @@ -31,13 +31,9 @@ class ConcurrentGCThread: public NamedThread { friend class VMStructs; -protected: bool volatile _should_terminate; bool _has_terminated; - // Create and start the thread (setting it's priority high.) - void create_and_start(); - // Do initialization steps in the thread: record stack base and size, // init thread local storage, set JNI handle block. void initialize_in_thread(); @@ -49,44 +45,29 @@ protected: // concurrent work. void terminate(); +protected: + // Create and start the thread (setting it's priority.) + void create_and_start(ThreadPriority prio = NearMaxPriority); + + // Do the specific GC work. Called by run() after initialization complete. + virtual void run_service() = 0; + + // Shut down the specific GC work. Called by stop() as part of termination protocol. + virtual void stop_service() = 0; + public: ConcurrentGCThread(); // Tester bool is_ConcurrentGC_thread() const { return true; } -}; -// The SurrogateLockerThread is used by concurrent GC threads for -// manipulating Java monitors, in particular, currently for -// manipulating the pending_list_lock. XXX -class SurrogateLockerThread: public JavaThread { - friend class VMStructs; - public: - enum SLT_msg_type { - empty = 0, // no message - acquirePLL, // acquire pending list lock - releaseAndNotifyPLL // notify and release pending list lock - }; - private: - // the following are shared with the CMSThread - SLT_msg_type _buffer; // communication buffer - Monitor _monitor; // monitor controlling buffer - BasicLock _basicLock; // used for PLL locking + virtual void run(); - public: - static SurrogateLockerThread* make(TRAPS); - - // Terminate VM with error message that SLT needed but not yet created. - static void report_missing_slt(); - - SurrogateLockerThread(); - - bool is_hidden_from_external_view() const { return true; } - - void loop(); // main method - - void manipulatePLL(SLT_msg_type msg); + // shutdown following termination protocol + virtual void stop(); + bool should_terminate() { return _should_terminate; } + bool has_terminated() { return _has_terminated; } }; #endif // SHARE_VM_GC_SHARED_CONCURRENTGCTHREAD_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcCause.cpp b/hotspot/src/share/vm/gc/shared/gcCause.cpp index 526e4fc90cb..91bb436c547 100644 --- a/hotspot/src/share/vm/gc/shared/gcCause.cpp +++ b/hotspot/src/share/vm/gc/shared/gcCause.cpp @@ -57,6 +57,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _wb_conc_mark: return "WhiteBox Initiated Concurrent Mark"; + case _wb_full_gc: + return "WhiteBox Initiated Full GC"; + case _update_allocation_context_stats_inc: case _update_allocation_context_stats_full: return "Update Allocation Context Stats"; @@ -73,6 +76,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _metadata_GC_threshold: return "Metadata GC Threshold"; + case _metadata_GC_clear_soft_refs: + return "Metadata GC Clear Soft References"; + case _cms_generation_full: return "CMS Generation Full"; @@ -100,9 +106,6 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _g1_humongous_allocation: return "G1 Humongous Allocation"; - case _last_ditch_collection: - return "Last ditch collection"; - case _dcmd_gc_run: return "Diagnostic Command"; diff --git a/hotspot/src/share/vm/gc/shared/gcCause.hpp b/hotspot/src/share/vm/gc/shared/gcCause.hpp index bc9e83c62e8..3ff7b53e92a 100644 --- a/hotspot/src/share/vm/gc/shared/gcCause.hpp +++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp @@ -33,6 +33,9 @@ // use of this class grows, we should split it into public // and implementation-private "causes". // +// The definitions in the SA code should be kept in sync +// with the definitions here. +// class GCCause : public AllStatic { public: @@ -48,6 +51,7 @@ class GCCause : public AllStatic { _heap_dump, _wb_young_gc, _wb_conc_mark, + _wb_full_gc, _update_allocation_context_stats_inc, _update_allocation_context_stats_full, @@ -60,6 +64,7 @@ class GCCause : public AllStatic { _tenured_generation_full, _metadata_GC_threshold, + _metadata_GC_clear_soft_refs, _cms_generation_full, _cms_initial_mark, @@ -73,8 +78,6 @@ class GCCause : public AllStatic { _g1_inc_collection_pause, _g1_humongous_allocation, - _last_ditch_collection, - _dcmd_gc_run, _last_gc_cause @@ -103,22 +106,18 @@ class GCCause : public AllStatic { // _allocation_failure is the generic cause a collection which could result // in the collection of the tenured generation if there is not enough space // in the tenured generation to support a young GC. - // _last_ditch_collection is a collection done to include SoftReferences. return (cause == GCCause::_tenured_generation_full || cause == GCCause::_cms_generation_full || cause == GCCause::_adaptive_size_policy || - cause == GCCause::_allocation_failure || - cause == GCCause::_last_ditch_collection); + cause == GCCause::_allocation_failure); } // Causes for collection of the young generation inline static bool is_allocation_failure_gc(GCCause::Cause cause) { // _allocation_failure is the generic cause a collection for allocation failure // _adaptive_size_policy is for a collecton done before a full GC - // _last_ditch_collection is a collection done to include SoftReferences. return (cause == GCCause::_allocation_failure || - cause == GCCause::_adaptive_size_policy || - cause == GCCause::_last_ditch_collection); + cause == GCCause::_adaptive_size_policy); } // Return a string describing the GCCause. diff --git a/hotspot/src/share/vm/gc/shared/gcLocker.cpp b/hotspot/src/share/vm/gc/shared/gcLocker.cpp index 115115d0a61..cc847261efd 100644 --- a/hotspot/src/share/vm/gc/shared/gcLocker.cpp +++ b/hotspot/src/share/vm/gc/shared/gcLocker.cpp @@ -51,10 +51,10 @@ void GCLocker::verify_critical_count() { } } if (_jni_lock_count != count) { - tty->print_cr("critical counts don't match: %d != %d", _jni_lock_count, count); + log_error(gc, verify)("critical counts don't match: %d != %d", _jni_lock_count, count); for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) { if (thr->in_critical()) { - tty->print_cr(INTPTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical()); + log_error(gc, verify)(INTPTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical()); } } } @@ -75,7 +75,7 @@ void GCLocker::decrement_debug_jni_lock_count() { #endif void GCLocker::log_debug_jni(const char* msg) { - LogHandle(gc, jni) log; + Log(gc, jni) log; if (log.is_debug()) { ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 log.debug("%s Thread \"%s\" %d locked.", msg, Thread::current()->name(), _jni_lock_count); diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.cpp b/hotspot/src/share/vm/gc/shared/gcTrace.cpp index 10da185584e..b275feed4b9 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,4 +242,12 @@ void G1NewTracer::report_adaptive_ihop_statistics(size_t threshold, prediction_active); } +void G1OldTracer::report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp) { + _shared_gc_info.set_start_timestamp(timestamp); +} + +void G1OldTracer::set_gc_cause(GCCause::Cause cause) { + _shared_gc_info.set_cause(cause); +} + #endif diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.hpp b/hotspot/src/share/vm/gc/shared/gcTrace.hpp index bcacbb9b12b..d45526e87d3 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ class GCTracer : public ResourceObj { protected: GCTracer(GCName name) : _shared_gc_info(name) {} - void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp); + virtual void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp); virtual void report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions); private: @@ -297,8 +297,11 @@ class CMSTracer : public OldGCTracer { }; class G1OldTracer : public OldGCTracer { + protected: + void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp); public: G1OldTracer() : OldGCTracer(G1Old) {} + void set_gc_cause(GCCause::Cause cause); }; #endif // SHARE_VM_GC_SHARED_GCTRACE_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp index b6555dff2ce..b6692df9a20 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp @@ -26,6 +26,8 @@ #define SHARE_VM_GC_SHARED_GCTRACETIME_HPP #include "logging/log.hpp" +#include "logging/logHandle.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.hpp" #include "utilities/ticks.hpp" @@ -41,10 +43,10 @@ class GCTraceCPUTime : public StackObj { class GCTimer; -template class GCTraceTimeImpl : public StackObj { private: + LogTargetHandle _out_start; + LogTargetHandle _out_stop; bool _enabled; Ticks _start_ticks; const char* _title; @@ -57,10 +59,18 @@ class GCTraceTimeImpl : public StackObj { void time_stamp(Ticks& ticks); public: - GCTraceTimeImpl(const char* title, GCTimer* timer = NULL, GCCause::Cause gc_cause = GCCause::_no_gc, bool log_heap_usage = false); + GCTraceTimeImpl(LogTargetHandle out_start, LogTargetHandle out_end, const char* title, GCTimer* timer = NULL, GCCause::Cause gc_cause = GCCause::_no_gc, bool log_heap_usage = false); ~GCTraceTimeImpl(); }; +template +class GCTraceTimeImplWrapper : public StackObj { + GCTraceTimeImpl _impl; +public: + GCTraceTimeImplWrapper(const char* title, GCTimer* timer = NULL, GCCause::Cause gc_cause = GCCause::_no_gc, bool log_heap_usage = false); + ~GCTraceTimeImplWrapper(); +}; + // Similar to GCTraceTimeImpl but is intended for concurrent phase logging, // which is a bit simpler and should always print the start line, i.e. not add the "start" tag. template " SIZE_FORMAT "M(" SIZE_FORMAT "M)" -template -void GCTraceTimeImpl::log_start(jlong start_counter) { - if (Log::is_level(Level)) { - FormatBuffer<> start_msg("%s", _title); +inline void GCTraceTimeImpl::log_start(jlong start_counter) { + if (_out_start.is_enabled()) { + LogStream out(_out_start); + + out.print("%s", _title); if (_gc_cause != GCCause::_no_gc) { - start_msg.append(" (%s)", GCCause::to_string(_gc_cause)); - } - start_msg.append(" (%.3fs)", TimeHelper::counter_to_seconds(start_counter)); - // Make sure to put the "start" tag last in the tag set - STATIC_ASSERT(T0 != LogTag::__NO_TAG); // Need some tag to log on. - STATIC_ASSERT(T4 == LogTag::__NO_TAG); // Need to leave at least the last tag for the "start" tag in log_start() - if (T1 == LogTag::__NO_TAG) { - Log::template write("%s", start_msg.buffer()); - } else if (T2 == LogTag::__NO_TAG) { - Log::template write("%s", start_msg.buffer()); - } else if (T3 == LogTag::__NO_TAG) { - Log::template write("%s", start_msg.buffer()); - } else { - Log::template write("%s", start_msg.buffer()); + out.print(" (%s)", GCCause::to_string(_gc_cause)); } + out.print_cr(" (%.3fs)", TimeHelper::counter_to_seconds(start_counter)); } } -template -void GCTraceTimeImpl::log_stop(jlong start_counter, jlong stop_counter) { +inline void GCTraceTimeImpl::log_stop(jlong start_counter, jlong stop_counter) { double duration_in_ms = TimeHelper::counter_to_millis(stop_counter - start_counter); double start_time_in_secs = TimeHelper::counter_to_seconds(start_counter); double stop_time_in_secs = TimeHelper::counter_to_seconds(stop_counter); - FormatBuffer<> stop_msg("%s", _title); + + LogStream out(_out_stop); + + out.print("%s", _title); + if (_gc_cause != GCCause::_no_gc) { - stop_msg.append(" (%s)", GCCause::to_string(_gc_cause)); + out.print(" (%s)", GCCause::to_string(_gc_cause)); } - if (_heap_usage_before == SIZE_MAX) { - Log::template write("%s " LOG_STOP_TIME_FORMAT, - stop_msg.buffer(), start_time_in_secs, stop_time_in_secs, duration_in_ms); - } else { + + if (_heap_usage_before != SIZE_MAX) { CollectedHeap* heap = Universe::heap(); size_t used_before_m = _heap_usage_before / M; size_t used_m = heap->used() / M; size_t capacity_m = heap->capacity() / M; - Log::template write("%s " LOG_STOP_HEAP_FORMAT " " LOG_STOP_TIME_FORMAT, - stop_msg.buffer(), used_before_m, used_m, capacity_m, start_time_in_secs, stop_time_in_secs, duration_in_ms); + out.print(" " LOG_STOP_HEAP_FORMAT, used_before_m, used_m, capacity_m); } + + out.print_cr(" " LOG_STOP_TIME_FORMAT, start_time_in_secs, stop_time_in_secs, duration_in_ms); } -template -void GCTraceTimeImpl::time_stamp(Ticks& ticks) { +inline void GCTraceTimeImpl::time_stamp(Ticks& ticks) { if (_enabled || _timer != NULL) { ticks.stamp(); } } -template -GCTraceTimeImpl::GCTraceTimeImpl(const char* title, GCTimer* timer, GCCause::Cause gc_cause, bool log_heap_usage) : - _enabled(Log::is_level(Level)), +inline GCTraceTimeImpl::GCTraceTimeImpl(LogTargetHandle out_start, LogTargetHandle out_stop, const char* title, GCTimer* timer, GCCause::Cause gc_cause, bool log_heap_usage) : + _enabled(out_stop.is_enabled()), + _out_start(out_start), + _out_stop(out_stop), _start_ticks(), _heap_usage_before(SIZE_MAX), _title(title), @@ -111,8 +102,7 @@ GCTraceTimeImpl::GCTraceTimeImpl(const char } } -template -GCTraceTimeImpl::~GCTraceTimeImpl() { +inline GCTraceTimeImpl::~GCTraceTimeImpl() { Ticks stop_ticks; time_stamp(stop_ticks); if (_enabled) { @@ -125,9 +115,9 @@ GCTraceTimeImpl::~GCTraceTimeImpl() { template GCTraceConcTimeImpl::GCTraceConcTimeImpl(const char* title) : - _enabled(Log::is_level(Level)), _start_time(os::elapsed_counter()), _title(title) { + _enabled(LogImpl::is_level(Level)), _start_time(os::elapsed_counter()), _title(title) { if (_enabled) { - Log::template write("%s (%.3fs)", _title, TimeHelper::counter_to_seconds(_start_time)); + LogImpl::template write("%s (%.3fs)", _title, TimeHelper::counter_to_seconds(_start_time)); } } @@ -135,7 +125,7 @@ template ::~GCTraceConcTimeImpl() { if (_enabled) { jlong stop_time = os::elapsed_counter(); - Log::template write("%s " LOG_STOP_TIME_FORMAT, + LogImpl::template write("%s " LOG_STOP_TIME_FORMAT, _title, TimeHelper::counter_to_seconds(_start_time), TimeHelper::counter_to_seconds(stop_time), @@ -143,7 +133,34 @@ GCTraceConcTimeImpl::~GCTraceConcTimeImpl() } } -#define GCTraceTime(Level, ...) GCTraceTimeImpl +// Figure out the first __NO_TAG position and replace it with 'start'. +#define INJECT_START_TAG(T1, T2, T3, T4) \ + (( T1 == LogTag::__NO_TAG) ? PREFIX_LOG_TAG(start) : T1), \ + ((T1 != LogTag::__NO_TAG && T2 == LogTag::__NO_TAG) ? PREFIX_LOG_TAG(start) : T2), \ + ((T2 != LogTag::__NO_TAG && T3 == LogTag::__NO_TAG) ? PREFIX_LOG_TAG(start) : T3), \ + ((T3 != LogTag::__NO_TAG && T4 == LogTag::__NO_TAG) ? PREFIX_LOG_TAG(start) : T4) + +template +GCTraceTimeImplWrapper::GCTraceTimeImplWrapper( + const char* title, GCTimer* timer, GCCause::Cause gc_cause, bool log_heap_usage) + : _impl( + LogTargetHandle::create(), + LogTargetHandle::create(), + title, + timer, + gc_cause, + log_heap_usage) { + + STATIC_ASSERT(T0 != LogTag::__NO_TAG); // Need some tag to log on. + STATIC_ASSERT(T4 == LogTag::__NO_TAG); // Need to leave at least the last tag for the "start" tag in log_start() +} + +#undef INJECT_START_TAG + +template +GCTraceTimeImplWrapper::~GCTraceTimeImplWrapper() {} + +#define GCTraceTime(Level, ...) GCTraceTimeImplWrapper #define GCTraceConcTime(Level, ...) GCTraceConcTimeImpl #endif // SHARE_VM_GC_SHARED_GCTRACETIME_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 86fdeed91ea..7f76efbcd10 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -295,7 +295,8 @@ HeapWord* GenCollectedHeap::mem_allocate(size_t size, } bool GenCollectedHeap::must_clear_all_soft_refs() { - return _gc_cause == GCCause::_last_ditch_collection; + return _gc_cause == GCCause::_metadata_GC_clear_soft_refs || + _gc_cause == GCCause::_wb_full_gc; } bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { @@ -315,7 +316,7 @@ void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t siz bool is_tlab, bool run_verification, bool clear_soft_refs, bool restore_marks_for_biased_locking) { FormatBuffer<> title("Collect gen: %s", gen->short_name()); - GCTraceTime(Debug, gc) t1(title); + GCTraceTime(Trace, gc, phases) t1(title); TraceCollectorStats tcs(gen->counters()); TraceMemoryManagerStats tmms(gen->kind(),gc_cause()); @@ -684,15 +685,8 @@ void GenCollectedHeap::gen_process_roots(StrongRootsScope* scope, _process_strong_tasks->all_tasks_completed(scope->n_threads()); } - -class AlwaysTrueClosure: public BoolObjectClosure { -public: - bool do_object_b(oop p) { return true; } -}; -static AlwaysTrueClosure always_true; - void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) { - JNIHandles::weak_oops_do(&always_true, root_closure); + JNIHandles::weak_oops_do(root_closure); _young_gen->ref_processor()->weak_oops_do(root_closure); _old_gen->ref_processor()->weak_oops_do(root_closure); } @@ -1272,7 +1266,7 @@ jlong GenCollectedHeap::millis_since_last_gc() { // back a time later than 'now'. jlong retVal = now - tolgc_cl.time(); if (retVal < 0) { - NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, retVal);) + NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, retVal);) return 0; } return retVal; @@ -1281,7 +1275,7 @@ jlong GenCollectedHeap::millis_since_last_gc() { void GenCollectedHeap::stop() { #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { - ConcurrentMarkSweepThread::stop(); + ConcurrentMarkSweepThread::cmst()->stop(); } #endif } diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp index 7b8f2bafd1a..f4a7e252942 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,6 +281,10 @@ public: return UseConcMarkSweepGC; } + virtual bool needs_reference_pending_list_locker_thread() const { + return UseConcMarkSweepGC; + } + // We don't need barriers for stores to objects in the // young gen and, a fortiori, for initializing stores to // objects therein. This applies to DefNew+Tenured and ParNew+CMS diff --git a/hotspot/src/share/vm/gc/shared/generation.hpp b/hotspot/src/share/vm/gc/shared/generation.hpp index 6b60291d129..d71e6a1f220 100644 --- a/hotspot/src/share/vm/gc/shared/generation.hpp +++ b/hotspot/src/share/vm/gc/shared/generation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/universe.hpp" @@ -377,7 +378,7 @@ class Generation: public CHeapObj { // have to guard against non-monotonicity. NOT_PRODUCT( if (now < _time_of_last_gc) { - warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now); + log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now); } ) return _time_of_last_gc; diff --git a/hotspot/src/share/vm/gc/shared/plab.cpp b/hotspot/src/share/vm/gc/shared/plab.cpp index 1743bffb089..b95260d7f12 100644 --- a/hotspot/src/share/vm/gc/shared/plab.cpp +++ b/hotspot/src/share/vm/gc/shared/plab.cpp @@ -136,7 +136,7 @@ void PLABStats::log_sizing(size_t calculated_words, size_t net_desired_words) { // Calculates plab size for current number of gc worker threads. size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { - return MAX2(min_size(), (size_t)align_object_size(_desired_net_plab_sz / no_of_gc_workers)); + return (size_t)align_object_size(MIN2(MAX2(min_size(), _desired_net_plab_sz / no_of_gc_workers), max_size())); } // Compute desired plab size for one gc worker thread and latch result for later @@ -175,14 +175,9 @@ void PLABStats::adjust_desired_plab_sz() { size_t recent_plab_sz = used / target_refills; // Take historical weighted average _filter.sample(recent_plab_sz); - // Clip from above and below, and align to object boundary - size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average()); - new_plab_sz = MIN2(max_size(), new_plab_sz); - new_plab_sz = align_object_size(new_plab_sz); - // Latch the result - _desired_net_plab_sz = new_plab_sz; + _desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average()); - log_sizing(recent_plab_sz, new_plab_sz); + log_sizing(recent_plab_sz, _desired_net_plab_sz); reset(); } diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp index a82c8dd7bd4..e6950ff78b6 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp @@ -62,9 +62,14 @@ void PreservedMarksSet::init(uint num) { } void PreservedMarksSet::restore() { + size_t total_size = 0; for (uint i = 0; i < _num; i += 1) { + total_size += get(i)->size(); get(i)->restore(); } + assert_empty(); + + log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size); } void PreservedMarksSet::reclaim() { diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp index 42576d18f38..729f0666b17 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp @@ -53,6 +53,7 @@ private: public: bool is_empty() const { return _stack.is_empty(); } + size_t size() const { return _stack.size(); } inline void push_if_necessary(oop obj, markOop m); // Iterate over the stack, restore the preserved marks, then reclaim // the memory taken up by stack chunks. @@ -65,7 +66,7 @@ public: virtual void do_object(oop obj); }; -class PreservedMarksSet VALUE_OBJ_CLASS_SPEC { +class PreservedMarksSet : public CHeapObj { private: // true -> _stacks will be allocated in the C heap // false -> _stacks will be allocated in the resource arena diff --git a/hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp new file mode 100644 index 00000000000..0c35d65aeee --- /dev/null +++ b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/referencePendingListLocker.hpp" +#include "memory/universe.hpp" +#include "runtime/javaCalls.hpp" +#include "utilities/preserveException.hpp" + +ReferencePendingListLockerThread::ReferencePendingListLockerThread() : + JavaThread(&start), + _monitor(Monitor::nonleaf, "ReferencePendingListLocker", false, Monitor::_safepoint_check_sometimes), + _message(NONE) {} + +ReferencePendingListLockerThread* ReferencePendingListLockerThread::create(TRAPS) { + // Create Java thread objects + instanceKlassHandle thread_klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL); + instanceHandle thread_object = thread_klass->allocate_instance_handle(CHECK_NULL); + Handle thread_name = java_lang_String::create_from_str("Reference Pending List Locker", CHECK_NULL); + Handle thread_group = Universe::system_thread_group(); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, + thread_object, + thread_klass, + vmSymbols::object_initializer_name(), + vmSymbols::threadgroup_string_void_signature(), + thread_group, + thread_name, + CHECK_NULL); + + { + MutexLocker ml(Threads_lock); + + // Allocate thread + ReferencePendingListLockerThread* thread = new ReferencePendingListLockerThread(); + if (thread == NULL || thread->osthread() == NULL) { + vm_exit_during_initialization("java.lang.OutOfMemoryError", + os::native_thread_creation_failed_msg()); + } + + // Initialize thread + java_lang_Thread::set_thread(thread_object(), thread); + java_lang_Thread::set_priority(thread_object(), NearMaxPriority); + java_lang_Thread::set_daemon(thread_object()); + thread->set_threadObj(thread_object()); + + // Start thread + Threads::add(thread); + Thread::start(thread); + + return thread; + } +} + +void ReferencePendingListLockerThread::start(JavaThread* thread, TRAPS) { + ReferencePendingListLockerThread* locker_thread = static_cast(thread); + locker_thread->receive_and_handle_messages(); +} + +bool ReferencePendingListLockerThread::is_hidden_from_external_view() const { + return true; +} + +void ReferencePendingListLockerThread::send_message(Message message) { + assert(message != NONE, "Should not be none"); + MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); + + // Wait for completion of current message + while (_message != NONE) { + ml.wait(Monitor::_no_safepoint_check_flag); + } + + // Send new message + _message = message; + ml.notify_all(); + + // Wait for completion of new message + while (_message != NONE) { + ml.wait(Monitor::_no_safepoint_check_flag); + } +} + +void ReferencePendingListLockerThread::receive_and_handle_messages() { + ReferencePendingListLocker pending_list_locker; + MonitorLockerEx ml(&_monitor); + + // Main loop, never terminates + for (;;) { + // Wait for message + while (_message == NONE) { + ml.wait(); + } + + // Handle message + if (_message == LOCK) { + pending_list_locker.lock(); + } else if (_message == UNLOCK) { + pending_list_locker.unlock(); + } else { + ShouldNotReachHere(); + } + + // Clear message + _message = NONE; + ml.notify_all(); + } +} + +void ReferencePendingListLockerThread::lock() { + send_message(LOCK); +} + +void ReferencePendingListLockerThread::unlock() { + send_message(UNLOCK); +} + +bool ReferencePendingListLocker::_is_initialized = false; +ReferencePendingListLockerThread* ReferencePendingListLocker::_locker_thread = NULL; + +void ReferencePendingListLocker::initialize(bool needs_locker_thread, TRAPS) { + if (needs_locker_thread) { + _locker_thread = ReferencePendingListLockerThread::create(CHECK); + } + + _is_initialized = true; +} + +bool ReferencePendingListLocker::is_initialized() { + return _is_initialized; +} + +bool ReferencePendingListLocker::is_locked_by_self() { + oop pending_list_lock = java_lang_ref_Reference::pending_list_lock(); + if (pending_list_lock == NULL) { + return false; + } + + JavaThread* thread = JavaThread::current(); + Handle handle(thread, pending_list_lock); + return ObjectSynchronizer::current_thread_holds_lock(thread, handle); +} + +void ReferencePendingListLocker::lock() { + assert(!Heap_lock->owned_by_self(), "Heap_lock must not be owned by requesting thread"); + + if (Thread::current()->is_Java_thread()) { + assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); + + // We may enter this with a pending exception + PRESERVE_EXCEPTION_MARK; + + HandleMark hm; + Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); + + // Lock + ObjectSynchronizer::fast_enter(handle, &_basic_lock, false, THREAD); + + assert(is_locked_by_self(), "Locking failed"); + + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } + } else { + // Delegate operation to locker thread + assert(_locker_thread != NULL, "Locker thread not created"); + _locker_thread->lock(); + } +} + +void ReferencePendingListLocker::unlock() { + if (Thread::current()->is_Java_thread()) { + assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); + + // We may enter this with a pending exception + PRESERVE_EXCEPTION_MARK; + + HandleMark hm; + Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); + + assert(is_locked_by_self(), "Should be locked by self"); + + // Notify waiters if the pending list is non-empty + if (java_lang_ref_Reference::pending_list() != NULL) { + ObjectSynchronizer::notifyall(handle, THREAD); + } + + // Unlock + ObjectSynchronizer::fast_exit(handle(), &_basic_lock, THREAD); + + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } + } else { + // Delegate operation to locker thread + assert(_locker_thread != NULL, "Locker thread not created"); + _locker_thread->unlock(); + } +} diff --git a/hotspot/src/share/vm/gc/shared/referencePendingListLocker.hpp b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.hpp new file mode 100644 index 00000000000..62cf7eed995 --- /dev/null +++ b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP +#define SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP + +#include "memory/allocation.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/mutex.hpp" +#include "runtime/thread.hpp" +#include "utilities/exceptions.hpp" + +// +// The ReferencePendingListLockerThread locks and unlocks the reference +// pending list lock on behalf a non-Java thread, typically a concurrent +// GC thread. This interface should not be directly accessed. All uses +// should instead go through the ReferencePendingListLocker, which calls +// this thread if needed. +// +class ReferencePendingListLockerThread : public JavaThread { +private: + enum Message { + NONE, + LOCK, + UNLOCK + }; + + Monitor _monitor; + Message _message; + + ReferencePendingListLockerThread(); + + static void start(JavaThread* thread, TRAPS); + + void send_message(Message message); + void receive_and_handle_messages(); + +public: + static ReferencePendingListLockerThread* create(TRAPS); + + virtual bool is_hidden_from_external_view() const; + + void lock(); + void unlock(); +}; + +// +// The ReferencePendingListLocker is the main interface for locking and +// unlocking the reference pending list lock, which needs to be held by +// the GC when adding references to the pending list. Since this is a +// Java-level monitor it can only be locked/unlocked by a Java thread. +// For this reason there is an option to spawn a helper thread, the +// ReferencePendingListLockerThread, during initialization. If a helper +// thread is spawned all lock operations from non-Java threads will be +// delegated to the helper thread. The helper thread is typically needed +// by concurrent GCs. +// +class ReferencePendingListLocker VALUE_OBJ_CLASS_SPEC { +private: + static bool _is_initialized; + static ReferencePendingListLockerThread* _locker_thread; + BasicLock _basic_lock; + +public: + static void initialize(bool needs_locker_thread, TRAPS); + static bool is_initialized(); + + static bool is_locked_by_self(); + + void lock(); + void unlock(); +}; + +#endif // SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 7b3616ff168..22ed7b25d81 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -33,6 +33,7 @@ #include "gc/shared/referenceProcessor.inline.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" @@ -134,7 +135,7 @@ void ReferenceProcessor::verify_no_references_recorded() { guarantee(!_discovering_refs, "Discovering refs?"); for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { guarantee(_discovered_refs[i].is_empty(), - "Found non-empty discovered list"); + "Found non-empty discovered list at %u", i); } } #endif @@ -161,8 +162,8 @@ void ReferenceProcessor::update_soft_ref_master_clock() { NOT_PRODUCT( if (now < _soft_ref_timestamp_clock) { - warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, - _soft_ref_timestamp_clock, now); + log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, + _soft_ref_timestamp_clock, now); } ) // The values of now and _soft_ref_timestamp_clock are set using @@ -266,11 +267,6 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( #ifndef PRODUCT // Calculate the number of jni handles. size_t ReferenceProcessor::count_jni_refs() { - class AlwaysAliveClosure: public BoolObjectClosure { - public: - virtual bool do_object_b(oop obj) { return true; } - }; - class CountHandleClosure: public OopClosure { private: size_t _count; @@ -281,8 +277,7 @@ size_t ReferenceProcessor::count_jni_refs() { size_t count() { return _count; } }; CountHandleClosure global_handle_count; - AlwaysAliveClosure always_alive; - JNIHandles::weak_oops_do(&always_alive, &global_handle_count); + JNIHandles::weak_oops_do(&global_handle_count); return global_handle_count.count(); } #endif @@ -645,9 +640,7 @@ public: OopClosure& keep_alive, VoidClosure& complete_gc) { - Thread* thr = Thread::current(); - int refs_list_index = ((WorkerThread*)thr)->id(); - _ref_processor.process_phase1(_refs_lists[refs_list_index], _policy, + _ref_processor.process_phase1(_refs_lists[i], _policy, &is_alive, &keep_alive, &complete_gc); } private: @@ -683,11 +676,6 @@ public: OopClosure& keep_alive, VoidClosure& complete_gc) { - // Don't use "refs_list_index" calculated in this way because - // balance_queues() has moved the Ref's into the first n queues. - // Thread* thr = Thread::current(); - // int refs_list_index = ((WorkerThread*)thr)->id(); - // _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent, _ref_processor.process_phase3(_refs_lists[i], _clear_referent, &is_alive, &keep_alive, &complete_gc); } @@ -696,19 +684,30 @@ private: }; #ifndef PRODUCT -void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) { +void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_refs) { if (!log_is_enabled(Trace, gc, ref)) { return; } stringStream st; - for (uint i = 0; i < _max_num_q; ++i) { + for (uint i = 0; i < active_length; ++i) { st.print(SIZE_FORMAT " ", ref_lists[i].length()); } log_develop_trace(gc, ref)("%s= " SIZE_FORMAT, st.as_string(), total_refs); +#ifdef ASSERT + for (uint i = active_length; i < _max_num_q; i++) { + assert(ref_lists[i].length() == 0, SIZE_FORMAT " unexpected References in %u", + ref_lists[i].length(), i); + } +#endif } #endif +void ReferenceProcessor::set_active_mt_degree(uint v) { + _num_q = v; + _next_id = 0; +} + // Balances reference queues. // Move entries from all queues[0, 1, ..., _max_num_q-1] to // queues[0, 1, ..., _num_q-1] because only the first _num_q @@ -721,8 +720,8 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) for (uint i = 0; i < _max_num_q; ++i) { total_refs += ref_lists[i].length(); - } - log_reflist_counts(ref_lists, total_refs); + } + log_reflist_counts(ref_lists, _max_num_q, total_refs); size_t avg_refs = total_refs / _num_q + 1; uint to_idx = 0; for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) { @@ -784,10 +783,10 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) } #ifdef ASSERT size_t balanced_total_refs = 0; - for (uint i = 0; i < _max_num_q; ++i) { + for (uint i = 0; i < _num_q; ++i) { balanced_total_refs += ref_lists[i].length(); - } - log_reflist_counts(ref_lists, balanced_total_refs); + } + log_reflist_counts(ref_lists, _num_q, balanced_total_refs); assert(total_refs == balanced_total_refs, "Balancing was incomplete"); #endif } @@ -881,7 +880,7 @@ inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) id = next_id(); } } - assert(id < _max_num_q, "Id is out-of-bounds (call Freud?)"); + assert(id < _max_num_q, "Id is out-of-bounds id %u and max id %u)", id, _max_num_q); // Get the discovered queue to which we will add DiscoveredList* list = NULL; diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp index b7656845c72..125f55bde72 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp @@ -225,7 +225,7 @@ class ReferenceProcessor : public CHeapObj { uint num_q() { return _num_q; } uint max_num_q() { return _max_num_q; } - void set_active_mt_degree(uint v) { _num_q = v; } + void set_active_mt_degree(uint v); DiscoveredList* discovered_refs() { return _discovered_refs; } @@ -326,9 +326,11 @@ class ReferenceProcessor : public CHeapObj { // round-robin mod _num_q (not: _not_ mode _max_num_q) uint next_id() { uint id = _next_id; + assert(!_discovery_is_mt, "Round robin should only be used in serial discovery"); if (++_next_id == _num_q) { _next_id = 0; } + assert(_next_id < _num_q, "_next_id %u _num_q %u _max_num_q %u", _next_id, _num_q, _max_num_q); return id; } DiscoveredList* get_discovered_list(ReferenceType rt); @@ -340,7 +342,7 @@ class ReferenceProcessor : public CHeapObj { // Calculate the number of jni handles. size_t count_jni_refs(); - void log_reflist_counts(DiscoveredList ref_lists[], size_t total_count) PRODUCT_RETURN; + void log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_count) PRODUCT_RETURN; // Balances reference queues. void balance_queues(DiscoveredList ref_lists[]); diff --git a/hotspot/src/share/vm/gc/shared/space.cpp b/hotspot/src/share/vm/gc/shared/space.cpp index fe339a08412..5a020b1f74f 100644 --- a/hotspot/src/share/vm/gc/shared/space.cpp +++ b/hotspot/src/share/vm/gc/shared/space.cpp @@ -30,7 +30,6 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/liveRange.hpp" #include "gc/shared/space.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" diff --git a/hotspot/src/share/vm/gc/shared/space.inline.hpp b/hotspot/src/share/vm/gc/shared/space.inline.hpp index 7b27598e286..24cfb6213e8 100644 --- a/hotspot/src/share/vm/gc/shared/space.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/space.inline.hpp @@ -28,7 +28,6 @@ #include "gc/serial/markSweep.inline.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/generation.hpp" -#include "gc/shared/liveRange.hpp" #include "gc/shared/space.hpp" #include "gc/shared/spaceDecorator.hpp" #include "memory/universe.hpp" @@ -117,9 +116,6 @@ inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* c HeapWord* end_of_live= q; // One byte beyond the last byte of the last // live object. HeapWord* first_dead = space->end(); // The first dead object. - LiveRange* liveRange = NULL; // The current live range, recorded in the - // first header of preceding free area. - space->_first_dead = first_dead; const intx interval = PrefetchScanIntervalInBytes; @@ -158,16 +154,8 @@ inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* c // otherwise, it really is a free region. - // for the previous LiveRange, record the end of the live objects. - if (liveRange) { - liveRange->set_end(q); - } - - // record the current LiveRange object. - // liveRange->start() is overlaid on the mark word. - liveRange = (LiveRange*)q; - liveRange->set_start(end); - liveRange->set_end(end); + // q is a pointer to a dead object. Use this dead memory to store a pointer to the next live object. + (*(HeapWord**)q) = end; // see if this is the first dead region. if (q < first_dead) { @@ -180,9 +168,6 @@ inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* c } assert(q == t, "just checking"); - if (liveRange != NULL) { - liveRange->set_end(q); - } space->_end_of_live = end_of_live; if (end_of_live < first_dead) { first_dead = end_of_live; @@ -227,9 +212,9 @@ inline void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space) { if (space->_first_dead == t) { q = t; } else { - // $$$ This is funky. Using this to read the previously written - // LiveRange. See also use below. - q = (HeapWord*)oop(space->_first_dead)->mark()->decode_pointer(); + // The first dead object is no longer an object. At that memory address, + // there is a pointer to the first live object that the previous phase found. + q = *((HeapWord**)(space->_first_dead)); } } @@ -247,11 +232,10 @@ inline void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space) { debug_only(prev_q = q); q += size; } else { - // q is not a live object, so its mark should point at the next - // live object debug_only(prev_q = q); - q = (HeapWord*) oop(q)->mark()->decode_pointer(); - assert(q > prev_q, "we should be moving forward through memory"); + // q is not a live object, instead it points at the next live object + q = *(HeapWord**)q; + assert(q > prev_q, "we should be moving forward through memory, q: " PTR_FORMAT ", prev_q: " PTR_FORMAT, p2i(q), p2i(prev_q)); } } diff --git a/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp b/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp index 636f09ba1e9..417c22a5778 100644 --- a/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp +++ b/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp @@ -84,9 +84,7 @@ void SpaceMangler::mangle_unused_area_complete() { void SpaceMangler::mangle_region(MemRegion mr) { assert(ZapUnusedHeapArea, "Mangling should not be in use"); #ifdef ASSERT - log_develop_trace(gc)("Mangling [" PTR_FORMAT " to " PTR_FORMAT ")", p2i(mr.start()), p2i(mr.end())); Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord); - log_develop_trace(gc)("Mangling done."); #endif } diff --git a/hotspot/src/share/vm/gc/shared/taskqueue.hpp b/hotspot/src/share/vm/gc/shared/taskqueue.hpp index 34cda1dbc33..e61a6c2451b 100644 --- a/hotspot/src/share/vm/gc/shared/taskqueue.hpp +++ b/hotspot/src/share/vm/gc/shared/taskqueue.hpp @@ -248,7 +248,6 @@ public: template class GenericTaskQueue: public TaskQueueSuper { - ArrayAllocator _array_allocator; protected: typedef typename TaskQueueSuper::Age Age; typedef typename TaskQueueSuper::idx_t idx_t; diff --git a/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp b/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp index bb6f5164ed4..8ba1577002c 100644 --- a/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp @@ -44,12 +44,13 @@ inline GenericTaskQueueSet::GenericTaskQueueSet(int n) : _n(n) { template inline void GenericTaskQueue::initialize() { - _elems = _array_allocator.allocate(N); + _elems = ArrayAllocator::allocate(N); } template inline GenericTaskQueue::~GenericTaskQueue() { - FREE_C_HEAP_ARRAY(E, _elems); + assert(false, "This code is currently never called"); + ArrayAllocator::free(const_cast(_elems), N); } template diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp index d2b688ffc5b..0c975d1e269 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp @@ -242,7 +242,7 @@ size_t ThreadLocalAllocBuffer::initial_desired_size() { } void ThreadLocalAllocBuffer::print_stats(const char* tag) { - LogHandle(gc, tlab) log; + Log(gc, tlab) log; if (!log.is_trace()) { return; } @@ -385,7 +385,7 @@ void GlobalTLABStats::publish() { } void GlobalTLABStats::print() { - LogHandle(gc, tlab) log; + Log(gc, tlab) log; if (!log.is_debug()) { return; } diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp index 8c1178b8cdf..9026887f66d 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ inline size_t ThreadLocalAllocBuffer::compute_size(size_t obj_size) { // unsafe_max_tlab_alloc is just a hint. const size_t available_size = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; - size_t new_tlab_size = MIN2(available_size, desired_size() + aligned_obj_size); + size_t new_tlab_size = MIN3(available_size, desired_size() + aligned_obj_size, max_size()); // Make sure there's enough room for object and filler int[]. const size_t obj_plus_filler_size = aligned_obj_size + alignment_reserve(); diff --git a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp index 755681afe8a..004a5f4f285 100644 --- a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,10 +30,8 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/vmGCOperations.hpp" -#include "memory/oopFactory.hpp" #include "logging/log.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/instanceRefKlass.hpp" +#include "memory/oopFactory.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -64,14 +62,11 @@ void VM_GC_Operation::notify_gc_end() { } void VM_GC_Operation::acquire_pending_list_lock() { - // we may enter this with pending exception set - InstanceRefKlass::acquire_pending_list_lock(&_pending_list_basic_lock); + _pending_list_locker.lock(); } - void VM_GC_Operation::release_and_notify_pending_list_lock() { - - InstanceRefKlass::release_and_notify_pending_list_lock(&_pending_list_basic_lock); + _pending_list_locker.unlock(); } // Allocations may fail in several threads at about the same time, @@ -160,7 +155,7 @@ void VM_GC_HeapInspection::doit() { // be about to attempt holds value for us only // if it happens now and not if it happens in the eventual // future. - warning("GC locker is held; pre-dump GC was skipped"); + log_warning(gc)("GC locker is held; pre-dump GC was skipped"); } } HeapInspection inspect(_csv_format, _print_help, _print_class_stats, @@ -276,12 +271,8 @@ void VM_CollectForMetadataAllocation::doit() { return; } - // If expansion failed, do a last-ditch collection and try allocating - // again. A last-ditch collection will clear softrefs. This - // behavior is similar to the last-ditch collection done for perm - // gen when it was full and a collection for failed allocation - // did not free perm gen space. - heap->collect_as_vm_thread(GCCause::_last_ditch_collection); + // If expansion failed, do a collection clearing soft references. + heap->collect_as_vm_thread(GCCause::_metadata_GC_clear_soft_refs); _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype); if (_result != NULL) { return; diff --git a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp index e43a3889bac..fe742964b56 100644 --- a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "memory/heapInspection.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/handles.hpp" @@ -69,8 +70,10 @@ // class VM_GC_Operation: public VM_Operation { + private: + ReferencePendingListLocker _pending_list_locker; + protected: - BasicLock _pending_list_basic_lock; // for refs pending list notification (PLL) uint _gc_count_before; // gc count before acquiring PLL uint _full_gc_count_before; // full gc count before acquiring PLL bool _full; // whether a "full" collection diff --git a/hotspot/src/share/vm/gc/shared/workgroup.cpp b/hotspot/src/share/vm/gc/shared/workgroup.cpp index 41b3b9a8ef8..a8da10db4cc 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,12 +40,7 @@ // initialization of the workers and report such to the // caller. bool AbstractWorkGang::initialize_workers() { - - if (TraceWorkGang) { - tty->print_cr("Constructing work gang %s with %d threads", - name(), - total_workers()); - } + log_develop_trace(gc, workgang)("Constructing work gang %s with %u threads", name(), total_workers()); _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal); if (_workers == NULL) { vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array."); @@ -279,10 +274,7 @@ void AbstractGangWorker::initialize() { this->initialize_named_thread(); assert(_gang != NULL, "No gang to run in"); os::set_priority(this, NearMaxPriority); - if (TraceWorkGang) { - tty->print_cr("Running gang worker for gang %s id %u", - gang()->name(), id()); - } + log_develop_trace(gc, workgang)("Running gang worker for gang %s id %u", gang()->name(), id()); // The VM thread should not execute here because MutexLocker's are used // as (opposed to MutexLockerEx's). assert(!Thread::current()->is_VM_thread(), "VM thread should not be part" @@ -311,27 +303,14 @@ void GangWorker::signal_task_done() { gang()->dispatcher()->worker_done_with_task(); } -void GangWorker::print_task_started(WorkData data) { - if (TraceWorkGang) { - tty->print_cr("Running work gang %s task %s worker %u", name(), data._task->name(), data._worker_id); - } -} - -void GangWorker::print_task_done(WorkData data) { - if (TraceWorkGang) { - tty->print_cr("\nFinished work gang %s task %s worker %u", name(), data._task->name(), data._worker_id); - Thread* me = Thread::current(); - tty->print_cr(" T: " PTR_FORMAT " VM_thread: %d", p2i(me), me->is_VM_thread()); - } -} - void GangWorker::run_task(WorkData data) { - print_task_started(data); - GCIdMark gc_id_mark(data._task->gc_id()); + log_develop_trace(gc, workgang)("Running work gang: %s task: %s worker: %u", name(), data._task->name(), data._worker_id); + data._task->work(data._worker_id); - print_task_done(data); + log_develop_trace(gc, workgang)("Finished work gang: %s task: %s worker: %u thread: " PTR_FORMAT, + name(), data._task->name(), data._worker_id, p2i(Thread::current())); } void GangWorker::loop() { diff --git a/hotspot/src/share/vm/gc/shared/workgroup.hpp b/hotspot/src/share/vm/gc/shared/workgroup.hpp index c28579ef471..ee6b7be4c14 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,7 +152,7 @@ class AbstractWorkGang : public CHeapObj { _active_workers = MAX2(1U, _active_workers); assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, "Unless dynamic should use total workers"); - log_info(gc, task)("GC Workers: %d", _active_workers); + log_info(gc, task)("GC Workers: using %d out of %d", _active_workers, _total_workers); } // Return the Ith worker. @@ -234,9 +234,6 @@ private: void run_task(WorkData work); void signal_task_done(); - void print_task_started(WorkData data); - void print_task_done(WorkData data); - WorkGang* gang() const { return (WorkGang*)_gang; } }; diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 983b0b71ad4..dbe5355b1df 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -138,11 +138,11 @@ BytecodeHistogram::_counters[(Bytecodes::Code)opcode]++; \ if (StopInterpreterAt && StopInterpreterAt == BytecodeCounter::_counter_value) os::breakpoint(); \ if (TraceBytecodes) { \ - CALL_VM((void)SharedRuntime::trace_bytecode(THREAD, 0, \ - topOfStack[Interpreter::expr_index_at(1)], \ - topOfStack[Interpreter::expr_index_at(2)]), \ - handle_exception); \ - } \ + CALL_VM((void)InterpreterRuntime::trace_bytecode(THREAD, 0, \ + topOfStack[Interpreter::expr_index_at(1)], \ + topOfStack[Interpreter::expr_index_at(2)]), \ + handle_exception); \ + } \ } #endif @@ -632,9 +632,11 @@ BytecodeInterpreter::run(interpreterState istate) { if (_compiling) { MethodCounters* mcs; GET_METHOD_COUNTERS(mcs); +#if COMPILER2_OR_JVMCI if (ProfileInterpreter) { METHOD->increment_interpreter_invocation_count(THREAD); } +#endif mcs->invocation_counter()->increment(); if (mcs->invocation_counter()->reached_InvocationLimit(mcs->backedge_counter())) { CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception); diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp index 2dcef77ef53..b8230af659c 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp @@ -27,7 +27,8 @@ #include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "runtime/logTimer.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/timerTrace.hpp" #ifdef CC_INTERP @@ -43,7 +44,7 @@ void CppInterpreter::initialize() { // generate interpreter { ResourceMark rm; - TraceStartupTime timer("Interpreter generation"); + TraceTime timer("Interpreter generation", TRACETIME_LOG(Info, startuptime)); int code_size = InterpreterCodeSize; NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index acc45335158..e36b76dda60 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -37,6 +37,7 @@ #include "interpreter/templateTable.hpp" #include "logging/log.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/constantPool.hpp" #include "oops/instanceKlass.hpp" @@ -173,9 +174,6 @@ IRT_END IRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* thread, ConstantPool* pool, int index, jint size)) - // Note: no oopHandle for pool & klass needed since they are not used - // anymore after new_objArray() and no GC can happen before. - // (This may have to change if this code changes!) Klass* klass = pool->klass_at(index, CHECK); objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); thread->set_vm_result(obj); @@ -523,8 +521,10 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea #ifndef CC_INTERP continuation = Interpreter::remove_activation_entry(); #endif +#if COMPILER2_OR_JVMCI // Count this for compilation purposes h_method->interpreter_throwout_increment(THREAD); +#endif } else { // handler in this method => change bci/bcp to handler bci/bcp and continue there handler_pc = h_method->code_base() + handler_bci; @@ -1414,3 +1414,17 @@ IRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* thread, } IRT_END #endif // INCLUDE_JVMTI + +#ifndef PRODUCT +// This must be a IRT_LEAF function because the interpreter must save registers on x86 to +// call this, which changes rsp and makes the interpreter's expression stack not walkable. +// The generated code still uses call_VM because that will set up the frame pointer for +// bcp and method. +IRT_LEAF(intptr_t, InterpreterRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2)) + const frame f = thread->last_frame(); + assert(f.is_interpreted_frame(), "must be an interpreted frame"); + methodHandle mh(thread, f.interpreter_frame_method()); + BytecodeTracer::trace(mh, f.interpreter_frame_bcp(), tos, tos2); + return preserve_this_value; +IRT_END +#endif // !PRODUCT diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp index 8212ccc1f59..02fc2cf3b2e 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,9 @@ class InterpreterRuntime: AllStatic { static void popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address); #endif + // bytecode tracing is only used by the TraceBytecodes + static intptr_t trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2) PRODUCT_RETURN0; + // Platform dependent stuff #ifdef TARGET_ARCH_x86 # include "interpreterRT_x86.hpp" diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 6bae45b4661..eb29da892a6 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -757,9 +757,9 @@ static void trace_method_resolution(const char* prefix, ResourceMark rm; outputStream* st; if (logitables) { - st = LogHandle(itables)::trace_stream(); + st = Log(itables)::trace_stream(); } else { - st = LogHandle(vtables)::trace_stream(); + st = Log(vtables)::trace_stream(); } st->print("%s%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", prefix, diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 8c2363be0d8..a059bd5871f 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -31,7 +31,7 @@ #include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "memory/resourceArea.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #ifndef CC_INTERP @@ -49,7 +49,7 @@ void TemplateInterpreter::initialize() { // generate interpreter { ResourceMark rm; - TraceStartupTime timer("Interpreter generation"); + TraceTime timer("Interpreter generation", TRACETIME_LOG(Info, startuptime)); int code_size = InterpreterCodeSize; NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space #if INCLUDE_JVMTI diff --git a/hotspot/src/share/vm/interpreter/templateTable.cpp b/hotspot/src/share/vm/interpreter/templateTable.cpp index c71ebd28263..ebca67320bd 100644 --- a/hotspot/src/share/vm/interpreter/templateTable.cpp +++ b/hotspot/src/share/vm/interpreter/templateTable.cpp @@ -26,7 +26,7 @@ #include "gc/shared/collectedHeap.hpp" #include "interpreter/interp_masm.hpp" #include "interpreter/templateTable.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #ifdef CC_INTERP @@ -245,7 +245,7 @@ void TemplateTable::initialize() { if (_is_initialized) return; // Initialize table - TraceStartupTime timer("TemplateTable initialization"); + TraceTime timer("TemplateTable initialization", TRACETIME_LOG(Info, startuptime)); _bs = Universe::heap()->barrier_set(); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp index e84d4b319c5..3e948e3533c 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ #include "precompiled.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/handles.hpp" diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 6ebf89a58d7..6ff1897124a 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -27,6 +27,7 @@ #include "code/scopeDesc.hpp" #include "interpreter/linkResolver.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/generateOopMap.hpp" #include "oops/fieldStreams.hpp" #include "oops/oop.inline.hpp" @@ -48,6 +49,7 @@ #include "gc/g1/heapRegion.hpp" #include "runtime/javaCalls.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.hpp" #include "runtime/vframe_hp.hpp" #include "runtime/vmStructs.hpp" @@ -1432,65 +1434,65 @@ C2V_END #define METASPACE_METHOD_DATA "J" JNINativeMethod CompilerToVM::methods[] = { - {CC"getBytecode", CC"("HS_RESOLVED_METHOD")[B", FN_PTR(getBytecode)}, - {CC"getExceptionTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getExceptionTableStart)}, - {CC"getExceptionTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getExceptionTableLength)}, - {CC"findUniqueConcreteMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")"HS_RESOLVED_METHOD, FN_PTR(findUniqueConcreteMethod)}, - {CC"getImplementor", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_KLASS, FN_PTR(getImplementor)}, - {CC"getStackTraceElement", CC"("HS_RESOLVED_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, - {CC"methodIsIgnoredBySecurityStackWalk", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, - {CC"doNotInlineOrCompile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(doNotInlineOrCompile)}, - {CC"canInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(canInlineMethod)}, - {CC"shouldInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(shouldInlineMethod)}, - {CC"lookupType", CC"("STRING CLASS"Z)"HS_RESOLVED_KLASS, FN_PTR(lookupType)}, - {CC"lookupNameInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameInPool)}, - {CC"lookupNameAndTypeRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, - {CC"lookupSignatureInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureInPool)}, - {CC"lookupKlassRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, - {CC"lookupKlassInPool", CC"("HS_CONSTANT_POOL"I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, - {CC"lookupAppendixInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, - {CC"lookupMethodInPool", CC"("HS_CONSTANT_POOL"IB)"HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, - {CC"constantPoolRemapInstructionOperandFromCache", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, - {CC"resolveConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)}, - {CC"resolvePossiblyCachedConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, - {CC"resolveTypeInPool", CC"("HS_CONSTANT_POOL"I)"HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, - {CC"resolveFieldInPool", CC"("HS_CONSTANT_POOL"IB[J)"HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, - {CC"resolveInvokeDynamicInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamicInPool)}, - {CC"resolveInvokeHandleInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeHandleInPool)}, - {CC"resolveMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, - {CC"getVtableIndexForInterfaceMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")I", FN_PTR(getVtableIndexForInterfaceMethod)}, - {CC"getClassInitializer", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, - {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_KLASS")Z", FN_PTR(hasFinalizableSubclass)}, - {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, - {CC"getResolvedJavaMethodAtSlot", CC"("CLASS"I)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethodAtSlot)}, - {CC"getResolvedJavaMethod", CC"(Ljava/lang/Object;J)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, - {CC"getConstantPool", CC"(Ljava/lang/Object;J)"HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, - {CC"getResolvedJavaType", CC"(Ljava/lang/Object;JZ)"HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, - {CC"initializeConfiguration", CC"("HS_CONFIG")J", FN_PTR(initializeConfiguration)}, - {CC"installCode", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE HS_SPECULATION_LOG")I", FN_PTR(installCode)}, - {CC"getMetadata", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA")I", FN_PTR(getMetadata)}, - {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)}, - {CC"disassembleCodeBlob", CC"("INSTALLED_CODE")"STRING, FN_PTR(disassembleCodeBlob)}, - {CC"executeInstalledCode", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeInstalledCode)}, - {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, - {CC"getLocalVariableTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getLocalVariableTableStart)}, - {CC"getLocalVariableTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getLocalVariableTableLength)}, - {CC"reprofile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(reprofile)}, - {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, - {CC"readUncompressedOop", CC"(J)"OBJECT, FN_PTR(readUncompressedOop)}, - {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, - {CC"allocateCompileId", CC"("HS_RESOLVED_METHOD"I)I", FN_PTR(allocateCompileId)}, - {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, - {CC"hasCompiledCodeForOSR", CC"("HS_RESOLVED_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)}, - {CC"getSymbol", CC"(J)"STRING, FN_PTR(getSymbol)}, - {CC"lookupSymbol", CC"("STRING")J", FN_PTR(lookupSymbol)}, - {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "["RESOLVED_METHOD"I)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, - {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)}, - {CC"shouldDebugNonSafepoints", CC"()Z", FN_PTR(shouldDebugNonSafepoints)}, - {CC"writeDebugOutput", CC"([BII)V", FN_PTR(writeDebugOutput)}, - {CC"flushDebugOutput", CC"()V", FN_PTR(flushDebugOutput)}, - {CC"methodDataProfileDataSize", CC"(JI)I", FN_PTR(methodDataProfileDataSize)}, - {CC"interpreterFrameSize", CC"("BYTECODE_FRAME")I", FN_PTR(interpreterFrameSize)}, + {CC "getBytecode", CC "(" HS_RESOLVED_METHOD ")[B", FN_PTR(getBytecode)}, + {CC "getExceptionTableStart", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getExceptionTableStart)}, + {CC "getExceptionTableLength", CC "(" HS_RESOLVED_METHOD ")I", FN_PTR(getExceptionTableLength)}, + {CC "findUniqueConcreteMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD ")" HS_RESOLVED_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC "getImplementor", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_KLASS, FN_PTR(getImplementor)}, + {CC "getStackTraceElement", CC "(" HS_RESOLVED_METHOD "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC "doNotInlineOrCompile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(doNotInlineOrCompile)}, + {CC "canInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(canInlineMethod)}, + {CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)}, + {CC "lookupType", CC "(" STRING CLASS "Z)" HS_RESOLVED_KLASS, FN_PTR(lookupType)}, + {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)}, + {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupSignatureInPool)}, + {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, + {CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, + {CC "resolveConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolveConstantInPool)}, + {CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, + {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "IB[J)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, + {CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)}, + {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, + {CC "getVtableIndexForInterfaceMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD ")I", FN_PTR(getVtableIndexForInterfaceMethod)}, + {CC "getClassInitializer", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, + {CC "hasFinalizableSubclass", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(hasFinalizableSubclass)}, + {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, + {CC "getResolvedJavaMethodAtSlot", CC "(" CLASS "I)" HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethodAtSlot)}, + {CC "getResolvedJavaMethod", CC "(Ljava/lang/Object;J)" HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC "getConstantPool", CC "(Ljava/lang/Object;J)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC "getResolvedJavaType", CC "(Ljava/lang/Object;JZ)" HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, + {CC "initializeConfiguration", CC "(" HS_CONFIG ")J", FN_PTR(initializeConfiguration)}, + {CC "installCode", CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE HS_SPECULATION_LOG ")I", FN_PTR(installCode)}, + {CC "getMetadata", CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA ")I", FN_PTR(getMetadata)}, + {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, + {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, + {CC "executeInstalledCode", CC "([" OBJECT INSTALLED_CODE ")" OBJECT, FN_PTR(executeInstalledCode)}, + {CC "getLineNumberTable", CC "(" HS_RESOLVED_METHOD ")[J", FN_PTR(getLineNumberTable)}, + {CC "getLocalVariableTableStart", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getLocalVariableTableStart)}, + {CC "getLocalVariableTableLength", CC "(" HS_RESOLVED_METHOD ")I", FN_PTR(getLocalVariableTableLength)}, + {CC "reprofile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(reprofile)}, + {CC "invalidateInstalledCode", CC "(" INSTALLED_CODE ")V", FN_PTR(invalidateInstalledCode)}, + {CC "readUncompressedOop", CC "(J)" OBJECT, FN_PTR(readUncompressedOop)}, + {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, + {CC "allocateCompileId", CC "(" HS_RESOLVED_METHOD "I)I", FN_PTR(allocateCompileId)}, + {CC "isMature", CC "(" METASPACE_METHOD_DATA ")Z", FN_PTR(isMature)}, + {CC "hasCompiledCodeForOSR", CC "(" HS_RESOLVED_METHOD "II)Z", FN_PTR(hasCompiledCodeForOSR)}, + {CC "getSymbol", CC "(J)" STRING, FN_PTR(getSymbol)}, + {CC "lookupSymbol", CC "(" STRING ")J", FN_PTR(lookupSymbol)}, + {CC "getNextStackFrame", CC "(" HS_STACK_FRAME_REF "[" RESOLVED_METHOD "I)" HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, + {CC "materializeVirtualObjects", CC "(" HS_STACK_FRAME_REF "Z)V", FN_PTR(materializeVirtualObjects)}, + {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC "writeDebugOutput", CC "([BII)V", FN_PTR(writeDebugOutput)}, + {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, + {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, + {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, }; int CompilerToVM::methods_count() { diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 68d4a05bc7f..eb39c2764c3 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" @@ -436,7 +437,7 @@ JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(D stringStream st(buffer, O_BUFLEN); deps.print_dependency(witness, true, &st); *failure_detail = st.as_string(); - if (env == NULL || counter_changed) { + if (env == NULL || counter_changed || deps.type() == Dependencies::evol_method) { return JVMCIEnv::dependencies_failed; } else { // The dependencies were invalid at the time of installation diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index c398f7442b7..76545ebc7b1 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -34,6 +34,7 @@ #include "jvmci/jvmciEnv.hpp" #include "logging/log.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "prims/jvm.h" diff --git a/hotspot/src/share/vm/logging/log.cpp b/hotspot/src/share/vm/logging/log.cpp index ad86c39d6f9..3d676219d89 100644 --- a/hotspot/src/share/vm/logging/log.cpp +++ b/hotspot/src/share/vm/logging/log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,71 +28,13 @@ #ifndef PRODUCT +#include "gc/shared/gcTraceTime.inline.hpp" #include "logging/log.hpp" #include "logging/logConfiguration.hpp" #include "logging/logOutput.hpp" +#include "logging/logStream.inline.hpp" #include "memory/resourceArea.hpp" -void Test_log_length() { - remove("loglengthoutput.txt"); - - // Write long message to output file - ResourceMark rm; - LogHandle(logging) log; - bool success = LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace", - NULL, NULL, log.error_stream()); - assert(success, "test unable to configure logging"); - log.trace("01:1234567890-" - "02:1234567890-" - "03:1234567890-" - "04:1234567890-" - "05:1234567890-" - "06:1234567890-" - "07:1234567890-" - "08:1234567890-" - "09:1234567890-" - "10:1234567890-" - "11:1234567890-" - "12:1234567890-" - "13:1234567890-" - "14:1234567890-" - "15:1234567890-" - "16:1234567890-" - "17:1234567890-" - "18:1234567890-" - "19:1234567890-" - "20:1234567890-" - "21:1234567890-" - "22:1234567890-" - "23:1234567890-" - "24:1234567890-" - "25:1234567890-" - "26:1234567890-" - "27:1234567890-" - "28:1234567890-" - "29:1234567890-" - "30:1234567890-" - "31:1234567890-" - "32:1234567890-" - "33:1234567890-" - "34:1234567890-" - "35:1234567890-" - "36:1234567890-" - "37:1234567890-"); - LogConfiguration::parse_log_arguments("loglengthoutput.txt", "all=off", - NULL, NULL, log.error_stream()); - - // Look for end of message in output file - FILE* fp = fopen("loglengthoutput.txt", "r"); - assert(fp, "File read error"); - char output[600]; - if (fgets(output, 600, fp) != NULL) { - assert(strstr(output, "37:1234567890-"), "logging print size error"); - } - fclose(fp); - remove("loglengthoutput.txt"); -} - #define assert_str_eq(s1, s2) \ assert(strcmp(s1, s2) == 0, "Expected '%s' to equal '%s'", s1, s2) @@ -102,18 +44,72 @@ void Test_log_length() { #define assert_char_not_in(c, s) \ assert(strchr(s, c) == NULL, "Expected '%s' to *not* contain character '%c'", s, c) -void Test_configure_stdout() { - ResourceMark rm; - LogHandle(logging) log; - LogOutput* stdoutput = LogOutput::Stdout; +class TestLogFile { + private: + char file_name[256]; - // Save current stdout config and clear it - char* saved_config = os::strdup_check_oom(stdoutput->config_string()); - LogConfiguration::parse_log_arguments("stdout", "all=off", NULL, NULL, log.error_stream()); + void set_name(const char* test_name) { + const char* tmpdir = os::get_temp_directory(); + int pos = jio_snprintf(file_name, sizeof(file_name), "%s%svmtest.%s.%d.log", tmpdir, os::file_separator(), test_name, os::current_process_id()); + assert(pos > 0, "too small log file name buffer"); + assert((size_t)pos < sizeof(file_name), "too small log file name buffer"); + } + + public: + TestLogFile(const char* test_name) { + set_name(test_name); + remove(name()); + } + + ~TestLogFile() { + remove(name()); + } + + const char* name() { + return file_name; + } +}; + +class TestLogSavedConfig { + private: + char* _saved_config; + char* _new_output; + Log(logging) _log; + public: + TestLogSavedConfig(const char* apply_output = NULL, const char* apply_setting = NULL) : _new_output(0) { + ResourceMark rm; + _saved_config = os::strdup_check_oom(LogOutput::Stdout->config_string()); + bool success = LogConfiguration::parse_log_arguments("stdout", "all=off", NULL, NULL, _log.error_stream()); + assert(success, "test unable to turn all off"); + + if (apply_output) { + _new_output = os::strdup_check_oom(apply_output); + bool success = LogConfiguration::parse_log_arguments(_new_output, apply_setting, NULL, NULL, _log.error_stream()); + assert(success, "test unable to apply test log configuration"); + } + } + + ~TestLogSavedConfig() { + ResourceMark rm; + if (_new_output) { + bool success = LogConfiguration::parse_log_arguments(_new_output, "all=off", NULL, NULL, _log.error_stream()); + assert(success, "test unable to turn all off"); + os::free(_new_output); + } + + bool success = LogConfiguration::parse_log_arguments("stdout", _saved_config, NULL, NULL, _log.error_stream()); + assert(success, "test unable to restore log configuration"); + os::free(_saved_config); + } +}; + +void Test_configure_stdout() { + LogOutput* stdoutput = LogOutput::Stdout; + TestLogSavedConfig tlsc; // Enable 'logging=info', verifying it has been set LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(logging)); - assert_str_eq("logging=info,", stdoutput->config_string()); + assert_str_eq("logging=info", stdoutput->config_string()); assert(log_is_enabled(Info, logging), "logging was not properly enabled"); // Enable 'gc=debug' (no wildcard), verifying no other tags are enabled @@ -131,9 +127,588 @@ void Test_configure_stdout() { LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(gc)); LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(logging)); assert_str_eq("all=off", stdoutput->config_string()); - - // Restore saved configuration - LogConfiguration::parse_log_arguments("stdout", saved_config, NULL, NULL, log.error_stream()); - os::free(saved_config); } + +static int Test_logconfiguration_subscribe_triggered = 0; + +static void Test_logconfiguration_subscribe_helper() { + Test_logconfiguration_subscribe_triggered++; +} + +void Test_logconfiguration_subscribe() { + ResourceMark rm; + Log(logging) log; + + TestLogSavedConfig log_cfg("stdout", "logging*=trace"); + + LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper); + + LogConfiguration::parse_log_arguments("stdout", "logging=trace", NULL, NULL, log.error_stream()); + assert(Test_logconfiguration_subscribe_triggered == 1, "subscription not triggered (1)"); + + LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc)); + assert(Test_logconfiguration_subscribe_triggered == 2, "subscription not triggered (2)"); + + LogConfiguration::disable_logging(); + assert(Test_logconfiguration_subscribe_triggered == 3, "subscription not triggered (3)"); + + // We need to renable stderr error logging since "disable_logging" disable it all. + // TestLogSavedConfig log_cfg will only renable stdout for us. + LogConfiguration::parse_log_arguments("stderr", "all=warning", NULL, NULL, log.error_stream()); + assert(Test_logconfiguration_subscribe_triggered == 4, "subscription not triggered (3)"); +} + +#define LOG_PREFIX_STR "THE_PREFIX " +#define LOG_LINE_STR "a log line" + +size_t Test_log_prefix_prefixer(char* buf, size_t len) { + int ret = jio_snprintf(buf, len, LOG_PREFIX_STR); + assert(ret > 0, "Failed to print prefix. Log buffer too small?"); + return (size_t) ret; +} + +void Test_log_prefix() { + TestLogFile log_file("log_prefix"); + TestLogSavedConfig log_cfg(log_file.name(), "logging+test=trace"); + + log_trace(logging, test)(LOG_LINE_STR); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + char output[1024]; + if (fgets(output, 1024, fp) != NULL) { + assert(strstr(output, LOG_PREFIX_STR LOG_LINE_STR), "logging prefix error"); + } + fclose(fp); +} + +void Test_log_big() { + char big_msg[4096] = {0}; + char Xchar = '~'; + + TestLogFile log_file("log_big"); + TestLogSavedConfig log_cfg(log_file.name(), "logging+test=trace"); + + memset(big_msg, Xchar, sizeof(big_msg) - 1); + + log_trace(logging, test)("%s", big_msg); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + char output[sizeof(big_msg)+128 /*decorators*/ ]; + if (fgets(output, sizeof(output), fp) != NULL) { + assert(strstr(output, LOG_PREFIX_STR), "logging prefix error"); + size_t count = 0; + for (size_t ps = 0 ; output[ps + count] != '\0'; output[ps + count] == Xchar ? count++ : ps++); + assert(count == (sizeof(big_msg) - 1) , "logging msg error"); + } + fclose(fp); +} + +void Test_logtagset_duplicates() { + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + char ts_name[512]; + ts->label(ts_name, sizeof(ts_name), ","); + + // verify that NO_TAG is never followed by a real tag + for (size_t i = 0; i < LogTag::MaxTags; i++) { + if (ts->tag(i) == LogTag::__NO_TAG) { + for (i++; i < LogTag::MaxTags; i++) { + assert(ts->tag(i) == LogTag::__NO_TAG, + "NO_TAG was followed by a real tag (%s) in tagset %s", + LogTag::name(ts->tag(i)), ts_name); + } + } + } + + // verify that there are no duplicate tagsets (same tags in different order) + for (LogTagSet* other = ts->next(); other != NULL; other = other->next()) { + if (ts->ntags() != other->ntags()) { + continue; + } + bool equal = true; + for (size_t i = 0; i < ts->ntags(); i++) { + LogTagType tag = ts->tag(i); + if (!other->contains(tag)) { + equal = false; + break; + } + } + // Since tagsets are implemented using template arguments, using both of + // the (logically equivalent) tagsets (t1, t2) and (t2, t1) somewhere will + // instantiate two different LogTagSetMappings. This causes multiple + // tagset instances to be created for the same logical set. We want to + // avoid this to save time, memory and prevent any confusion around it. + if (equal) { + char other_name[512]; + other->label(other_name, sizeof(other_name), ","); + assert(false, "duplicate LogTagSets found: '%s' vs '%s' " + "(tags must always be specified in the same order for each tagset)", + ts_name, other_name); + } + } + } +} + +#define Test_logtarget_string_literal "First line" + + +static void Test_logtarget_on() { + TestLogFile log_file("log_target"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug"); + + LogTarget(Debug, gc) log; + + assert(log.is_enabled(), "assert"); + + // Log the line and expect it to be available in the output file. + log.print(Test_logtarget_string_literal); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp != NULL, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, Test_logtarget_string_literal) != NULL, "log line missing"); + + fclose(fp); +} + +static void Test_logtarget_off() { + TestLogFile log_file("log_target"); + TestLogSavedConfig tlsc(log_file.name(), "gc=info"); + + LogTarget(Debug, gc) log; + + if (log.is_enabled()) { + // The log config could have been redirected gc=debug to a file. If gc=debug + // is enabled, we can only test that the LogTarget returns the same value + // as the log_is_enabled function. The rest of the test will be ignored. + assert(log.is_enabled() == log_is_enabled(Debug, gc), "assert"); + log_warning(logging)("This test doesn't support runs with -Xlog"); + return; + } + + // Try to log, but expect this to be filtered out. + log.print(Test_logtarget_string_literal); + + // Log a dummy line so that fgets doesn't return NULL because the file is empty. + log_info(gc)("Dummy line"); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp != NULL, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, Test_logtarget_string_literal) == NULL, "log line not missing"); + + fclose(fp); +} + +void Test_logtarget() { + Test_logtarget_on(); + Test_logtarget_off(); +} + + +static void Test_logstream_helper(outputStream* stream) { + TestLogFile log_file("log_stream"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug"); + + // Try to log, but expect this to be filtered out. + stream->print("%d ", 3); stream->print("workers"); stream->cr(); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp != NULL, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, "3 workers") != NULL, "log line missing"); + + fclose(fp); +} + +static void Test_logstream_log() { + Log(gc) log; + LogStream stream(log.debug()); + + Test_logstream_helper(&stream); +} + +static void Test_logstream_logtarget() { + LogTarget(Debug, gc) log; + LogStream stream(log); + + Test_logstream_helper(&stream); +} + +static void Test_logstream_logstreamhandle() { + LogStreamHandle(Debug, gc) stream; + + Test_logstream_helper(&stream); +} + +static void Test_logstream_no_rm() { + ResourceMark rm; + outputStream* stream = LogTarget(Debug, gc)::stream(); + + Test_logstream_helper(stream); +} + +void Test_logstream() { + Test_logstream_log(); + Test_logstream_logtarget(); + Test_logstream_logstreamhandle(); + Test_logstream_no_rm(); +} + +void Test_loghandle_on() { + TestLogFile log_file("log_handle"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug"); + + Log(gc) log; + LogHandle log_handle(log); + + assert(log_handle.is_debug(), "assert"); + + // Try to log trough a LogHandle. + log_handle.debug("%d workers", 3); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, "3 workers") != NULL, "log line missing"); + + fclose(fp); +} + +void Test_loghandle_off() { + TestLogFile log_file("log_handle"); + TestLogSavedConfig tlsc(log_file.name(), "gc=info"); + + Log(gc) log; + LogHandle log_handle(log); + + if (log_handle.is_debug()) { + // The log config could have been redirected gc=debug to a file. If gc=debug + // is enabled, we can only test that the LogTarget returns the same value + // as the log_is_enabled function. The rest of the test will be ignored. + assert(log_handle.is_debug() == log_is_enabled(Debug, gc), "assert"); + log_warning(logging)("This test doesn't support runs with -Xlog"); + return; + } + + // Try to log trough a LogHandle. Should fail, since only info is turned on. + log_handle.debug("%d workers", 3); + + // Log a dummy line so that fgets doesn't return NULL because the file is empty. + log_info(gc)("Dummy line"); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, "3 workers") == NULL, "log line missing"); + + fclose(fp); +} + +void Test_loghandle() { + Test_loghandle_on(); + Test_loghandle_off(); +} + +static void Test_logtargethandle_on() { + TestLogFile log_file("log_handle"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug"); + + LogTarget(Debug, gc) log; + LogTargetHandle log_handle(log); + + assert(log_handle.is_enabled(), "assert"); + + // Try to log trough a LogHandle. + log_handle.print("%d workers", 3); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, "3 workers") != NULL, "log line missing"); + + fclose(fp); +} + +static void Test_logtargethandle_off() { + TestLogFile log_file("log_handle"); + TestLogSavedConfig tlsc(log_file.name(), "gc=info"); + + LogTarget(Debug, gc) log; + LogTargetHandle log_handle(log); + + if (log_handle.is_enabled()) { + // The log config could have been redirected gc=debug to a file. If gc=debug + // is enabled, we can only test that the LogTarget returns the same value + // as the log_is_enabled function. The rest of the test will be ignored. + assert(log_handle.is_enabled() == log_is_enabled(Debug, gc), "assert"); + log_warning(logging)("This test doesn't support runs with -Xlog"); + return; + } + + // Try to log trough a LogHandle. Should fail, since only info is turned on. + log_handle.print("%d workers", 3); + + // Log a dummy line so that fgets doesn't return NULL because the file is empty. + log_info(gc)("Dummy line"); + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + assert(strstr(output, "3 workers") == NULL, "log line missing"); + + fclose(fp); +} + +void Test_logtargethandle() { + Test_logtargethandle_on(); + Test_logtargethandle_off(); +} + +static void Test_log_gctracetime_full() { + TestLogFile log_file("log_gctracetime"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug"); + + LogTarget(Debug, gc) gc_debug; + LogTarget(Debug, gc, start) gc_start_debug; + + assert(gc_debug.is_enabled(), "assert"); + assert(gc_start_debug.is_enabled(), "assert"); + + { + MutexLocker lock(Heap_lock); // Needed to read heap usage + GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, true); + } + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s) + assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s)") != NULL, "Incorrect log line"); + + res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc ] Test GC (Allocation Failure) 59M->59M(502M) (2.975s, 2.975s) 0.026ms + assert(strstr(output, "[gc ") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) ") != NULL, "Incorrect log line"); + assert(strstr(output, "M) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s, ") != NULL, "Incorrect log line"); + assert(strstr(output, "s) ") != NULL, "Incorrect log line"); + assert(strstr(output, "ms") != NULL, "Incorrect log line"); + + fclose(fp); +} + +static void Test_log_gctracetime_full_multitag() { + TestLogFile log_file("log_gctracetime"); + TestLogSavedConfig tlsc(log_file.name(), "gc+ref=debug,gc+ref+start=debug"); + + LogTarget(Debug, gc, ref) gc_debug; + LogTarget(Debug, gc, ref, start) gc_start_debug; + + assert(gc_debug.is_enabled(), "assert"); + assert(gc_start_debug.is_enabled(), "assert"); + + { + MutexLocker lock(Heap_lock); // Needed to read heap usage + GCTraceTime(Debug, gc, ref) timer("Test GC", NULL, GCCause::_allocation_failure, true); + } + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s) + assert(strstr(output, "[gc,ref,start") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s)") != NULL, "Incorrect log line"); + + res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc ] Test GC (Allocation Failure) 59M->59M(502M) (2.975s, 2.975s) 0.026ms + assert(strstr(output, "[gc,ref ") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) ") != NULL, "Incorrect log line"); + assert(strstr(output, "M) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s, ") != NULL, "Incorrect log line"); + assert(strstr(output, "s) ") != NULL, "Incorrect log line"); + assert(strstr(output, "ms") != NULL, "Incorrect log line"); + + fclose(fp); +} + +static void Test_log_gctracetime_no_heap() { + TestLogFile log_file("log_gctracetime"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug"); + + LogTarget(Debug, gc) gc_debug; + LogTarget(Debug, gc, start) gc_start_debug; + + assert(gc_debug.is_enabled(), "assert"); + assert(gc_start_debug.is_enabled(), "assert"); + + { + GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, false); + } + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s) + assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s)") != NULL, "Incorrect log line"); + + res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc ] Test GC (Allocation Failure) (2.975s, 2.975s) 0.026ms + assert(strstr(output, "[gc ") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line"); + assert(strstr(output, "M) (") == NULL, "Incorrect log line"); + assert(strstr(output, "s, ") != NULL, "Incorrect log line"); + assert(strstr(output, "s) ") != NULL, "Incorrect log line"); + assert(strstr(output, "ms") != NULL, "Incorrect log line"); + + fclose(fp); +} + +static void Test_log_gctracetime_no_cause() { + TestLogFile log_file("log_gctracetime"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug"); + + LogTarget(Debug, gc) gc_debug; + LogTarget(Debug, gc, start) gc_start_debug; + + assert(gc_debug.is_enabled(), "assert"); + assert(gc_start_debug.is_enabled(), "assert"); + + { + MutexLocker lock(Heap_lock); // Needed to read heap usage + GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, true); + } + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc,start] Test GC (2.975s) + assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line"); + assert(strstr(output, "s)") != NULL, "Incorrect log line"); + + res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc ] Test GC 59M->59M(502M) (2.975s, 2.975s) 0.026ms + assert(strstr(output, "[gc ") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC ") != NULL, "Incorrect log line"); + assert(strstr(output, "M) (") != NULL, "Incorrect log line"); + assert(strstr(output, "s, ") != NULL, "Incorrect log line"); + assert(strstr(output, "s) ") != NULL, "Incorrect log line"); + assert(strstr(output, "ms") != NULL, "Incorrect log line"); + + fclose(fp); +} + +static void Test_log_gctracetime_no_heap_no_cause() { + TestLogFile log_file("log_gctracetime"); + TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug"); + + LogTarget(Debug, gc) gc_debug; + LogTarget(Debug, gc, start) gc_start_debug; + + assert(gc_debug.is_enabled(), "assert"); + assert(gc_start_debug.is_enabled(), "assert"); + + { + MutexLocker lock(Heap_lock); // Needed to read heap usage + GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, false); + } + + FILE* fp = fopen(log_file.name(), "r"); + assert(fp, "File read error"); + + char output[256 /* Large enough buffer */]; + + char* res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc,start] Test GC (2.975s) + assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line"); + assert(strstr(output, "s)") != NULL, "Incorrect log line"); + + res = fgets(output, sizeof(output), fp); + assert(res != NULL, "assert"); + + // [2.975s][debug][gc ] Test GC (2.975s, 2.975s) 0.026ms + assert(strstr(output, "[gc ") != NULL, "Incorrect tag set"); + assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line"); + assert(strstr(output, "M) (") == NULL, "Incorrect log line"); + assert(strstr(output, "s, ") != NULL, "Incorrect log line"); + assert(strstr(output, "s) ") != NULL, "Incorrect log line"); + assert(strstr(output, "ms") != NULL, "Incorrect log line"); + + fclose(fp); +} + +void Test_log_gctracetime() { + Test_log_gctracetime_full(); + Test_log_gctracetime_full_multitag(); + Test_log_gctracetime_no_heap(); + Test_log_gctracetime_no_cause(); + Test_log_gctracetime_no_heap_no_cause(); +} + #endif // PRODUCT diff --git a/hotspot/src/share/vm/logging/log.hpp b/hotspot/src/share/vm/logging/log.hpp index d76df7cc52f..64664a52366 100644 --- a/hotspot/src/share/vm/logging/log.hpp +++ b/hotspot/src/share/vm/logging/log.hpp @@ -29,10 +29,8 @@ #include "logging/logTagSet.hpp" #include "logging/logTag.hpp" #include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" -#include "utilities/ostream.hpp" // // Logging macros @@ -44,19 +42,19 @@ // // Note that these macros will not evaluate the arguments unless the logging is enabled. // -#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : Log::write -#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : Log::write -#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write -#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write -#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write +#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : LogImpl::write // Macros for logging that should be excluded in product builds. // Available for levels Info, Debug and Trace. Includes test macro that // evaluates to false in product builds. #ifndef PRODUCT -#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write -#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write -#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write +#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : LogImpl::write +#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : LogImpl::write #define log_develop_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__) #else #define DUMMY_ARGUMENT_CONSUMER(...) @@ -67,7 +65,7 @@ #endif // Convenience macro to test if the logging is enabled on the specified level for given tags. -#define log_is_enabled(level, ...) (Log::is_level(LogLevel::level)) +#define log_is_enabled(level, ...) (LogImpl::is_level(LogLevel::level)) // // Log class for more advanced logging scenarios. @@ -78,18 +76,43 @@ // calls to _stream() functions (trace_stream(), debug_stream(), etc). // // Example usage: -// LogHandle(logging) log; +// Log(logging) log; // if (log.is_debug()) { // ... // log.debug("result = %d", result).trace(" tracing info"); // obj->print_on(log.debug_stream()); // } // -#define LogHandle(...) Log +#define Log(...) LogImpl + +// +// Log class that embeds both log tags and a log level. +// +// The class provides a way to write the tags and log level once, +// so that redundant specification of tags or levels can be avoided. +// +// Example usage: +// LogTarget(Debug, gc) out; +// if (out.is_enabled()) { +// ... +// out.print("Worker: %u", i); +// out.print(" data: %d", x); +// ... +// print_stats(out.stream()); +// } +// +#define LogTarget(level, ...) LogTargetImpl + +// Forward declaration to decouple this file from the outputStream API. +class outputStream; +outputStream* create_log_stream(LogLevelType level, LogTagSet* tagset); + +template +class LogTargetImpl; template -class Log VALUE_OBJ_CLASS_SPEC { +class LogImpl VALUE_OBJ_CLASS_SPEC { private: static const size_t LogBufferSize = 512; public: @@ -100,7 +123,7 @@ class Log VALUE_OBJ_CLASS_SPEC { // Empty constructor to avoid warnings on MSVC about unused variables // when the log instance is only used for static functions. - Log() { + LogImpl() { } static bool is_level(LogLevelType level) { @@ -113,7 +136,7 @@ class Log VALUE_OBJ_CLASS_SPEC { va_start(args, fmt); vwrite(level, fmt, args); va_end(args); - }; + } template ATTRIBUTE_PRINTF(1, 2) @@ -122,40 +145,19 @@ class Log VALUE_OBJ_CLASS_SPEC { va_start(args, fmt); vwrite(Level, fmt, args); va_end(args); - }; + } ATTRIBUTE_PRINTF(2, 0) static void vwrite(LogLevelType level, const char* fmt, va_list args) { - char buf[LogBufferSize]; - va_list saved_args; // For re-format on buf overflow. - va_copy(saved_args, args); - size_t prefix_len = LogPrefix::prefix(buf, sizeof(buf)); - // Check that string fits in buffer; resize buffer if necessary - int ret = os::log_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args); - assert(ret >= 0, "Log message buffer issue"); - if ((size_t)ret >= sizeof(buf)) { - size_t newbuf_len = prefix_len + ret + 1; - char* newbuf = NEW_C_HEAP_ARRAY(char, newbuf_len, mtLogging); - prefix_len = LogPrefix::prefix(newbuf, newbuf_len); - ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args); - assert(ret >= 0, "Log message buffer issue"); - puts(level, newbuf); - FREE_C_HEAP_ARRAY(char, newbuf); - } else { - puts(level, buf); - } - } - - static void puts(LogLevelType level, const char* string) { - LogTagSetMapping::tagset().log(level, string); + LogTagSetMapping::tagset().vwrite(level, fmt, args); } #define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \ - Log& v##name(const char* fmt, va_list args) { \ + LogImpl& v##name(const char* fmt, va_list args) { \ vwrite(LogLevel::level, fmt, args); \ return *this; \ } \ - Log& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \ + LogImpl& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \ va_list args; \ va_start(args, fmt); \ vwrite(LogLevel::level, fmt, args); \ @@ -166,10 +168,39 @@ class Log VALUE_OBJ_CLASS_SPEC { return is_level(LogLevel::level); \ } \ static outputStream* name##_stream() { \ - return new logStream(write); \ + return create_log_stream(LogLevel::level, &LogTagSetMapping::tagset()); \ + } \ + static LogTargetImpl* name() { \ + return (LogTargetImpl*)NULL; \ } LOG_LEVEL_LIST #undef LOG_LEVEL }; +// Combines logging tags and a logging level. +template +class LogTargetImpl { +public: + // Empty constructor to avoid warnings on MSVC about unused variables + // when the log instance is only used for static functions. + LogTargetImpl() { + } + + static bool is_enabled() { + return LogImpl::is_level(level); + } + + static void print(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2) { + va_list args; + va_start(args, fmt); + LogImpl::vwrite(level, fmt, args); + va_end(args); + } + + static outputStream* stream() { + return create_log_stream(level, &LogTagSetMapping::tagset()); + } +}; + #endif // SHARE_VM_LOGGING_LOG_HPP diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index 2bdd8682f93..67b63b782d9 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -40,6 +40,9 @@ LogOutput** LogConfiguration::_outputs = NULL; size_t LogConfiguration::_n_outputs = 0; +LogConfiguration::UpdateListenerFunction* LogConfiguration::_listener_callbacks = NULL; +size_t LogConfiguration::_n_listener_callbacks = 0; + // Stack object to take the lock for configuring the logging. // Should only be held during the critical parts of the configuration // (when calling configure_output or reading/modifying the outputs array). @@ -71,7 +74,7 @@ bool ConfigurationLock::current_thread_has_lock() { void LogConfiguration::post_initialize() { LogDiagnosticCommand::registerCommand(); - LogHandle(logging) log; + Log(logging) log; log.info("Log configuration fully initialized."); log_develop_info(logging)("Develop logging is available."); if (log.is_trace()) { @@ -254,6 +257,7 @@ void LogConfiguration::disable_logging() { for (size_t i = 0; i < _n_outputs; i++) { disable_output(i); } + notify_update_listeners(); } void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, ...) { @@ -282,6 +286,7 @@ void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, .. // Apply configuration to stdout (output #0), with the same decorators as before. ConfigurationLock cl; configure_output(0, expr, LogOutput::Stdout->decorators()); + notify_update_listeners(); } bool LogConfiguration::parse_command_line_arguments(const char* opts) { @@ -373,6 +378,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, } } configure_output(idx, expr, decorators); + notify_update_listeners(); return true; } @@ -471,3 +477,20 @@ void LogConfiguration::rotate_all_outputs() { } } +void LogConfiguration::register_update_listener(UpdateListenerFunction cb) { + assert(cb != NULL, "Should not register NULL as listener"); + ConfigurationLock cl; + size_t idx = _n_listener_callbacks++; + _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction, + _listener_callbacks, + _n_listener_callbacks, + mtLogging); + _listener_callbacks[idx] = cb; +} + +void LogConfiguration::notify_update_listeners() { + assert(ConfigurationLock::current_thread_has_lock(), "notify_update_listeners must be called in ConfigurationLock scope (lock held)"); + for (size_t i = 0; i < _n_listener_callbacks; i++) { + _listener_callbacks[i](); + } +} diff --git a/hotspot/src/share/vm/logging/logConfiguration.hpp b/hotspot/src/share/vm/logging/logConfiguration.hpp index 409c8b05ef5..9b7325b370e 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.hpp +++ b/hotspot/src/share/vm/logging/logConfiguration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,10 +37,26 @@ class LogTagLevelExpression; // kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets // are iterated over and updated accordingly. class LogConfiguration : public AllStatic { + public: + // Function for listeners + typedef void (*UpdateListenerFunction)(void); + + // Register callback for config change. + // The callback is always called with ConfigurationLock held, + // hence doing log reconfiguration from the callback will deadlock. + // The main Java thread may call this callback if there is an early registration + // else the attach listener JavaThread, started via diagnostic command, will be executing thread. + // The main purpose of this callback is to see if a loglevel have been changed. + // There is no way to unregister. + static void register_update_listener(UpdateListenerFunction cb); + private: static LogOutput** _outputs; static size_t _n_outputs; + static UpdateListenerFunction* _listener_callbacks; + static size_t _n_listener_callbacks; + // Create a new output. Returns NULL if failed. static LogOutput* new_output(char* name, const char* options, outputStream* errstream); @@ -60,6 +76,9 @@ class LogConfiguration : public AllStatic { // Configure output (add or update existing configuration) to log on tag-level combination using specified decorators. static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators); + // This should be called after any configuration change while still holding ConfigurationLock + static void notify_update_listeners(); + public: // Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively. static void initialize(jlong vm_start_time); diff --git a/hotspot/src/share/vm/logging/logFileOutput.cpp b/hotspot/src/share/vm/logging/logFileOutput.cpp index 730a90190bd..4084d5d2ce1 100644 --- a/hotspot/src/share/vm/logging/logFileOutput.cpp +++ b/hotspot/src/share/vm/logging/logFileOutput.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ LogFileOutput::~LogFileOutput() { } if (fclose(_stream) != 0) { jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n", - _file_name, strerror(errno)); + _file_name, os::strerror(errno)); } } os::free(_archive_name); @@ -139,7 +139,7 @@ bool LogFileOutput::initialize(const char* options) { } _stream = fopen(_file_name, FileOpenMode); if (_stream == NULL) { - log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno)); + log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, os::strerror(errno)); return false; } return true; @@ -176,7 +176,7 @@ void LogFileOutput::archive() { // Rename the file from ex hotspot.log to hotspot.log.2 if (rename(_file_name, _archive_name) == -1) { jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n", - _file_name, _archive_name, strerror(errno)); + _file_name, _archive_name, os::strerror(errno)); } } @@ -194,7 +194,7 @@ void LogFileOutput::rotate() { if (fclose(_stream)) { jio_fprintf(defaultStream::error_stream(), "Error closing file '%s' during log rotation (%s).\n", - _file_name, strerror(errno)); + _file_name, os::strerror(errno)); } // Archive the current log file @@ -204,7 +204,7 @@ void LogFileOutput::rotate() { _stream = fopen(_file_name, FileOpenMode); if (_stream == NULL) { jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n", - _file_name, strerror(errno)); + _file_name, os::strerror(errno)); return; } diff --git a/hotspot/src/share/vm/logging/logHandle.hpp b/hotspot/src/share/vm/logging/logHandle.hpp new file mode 100644 index 00000000000..1f62d96e6f9 --- /dev/null +++ b/hotspot/src/share/vm/logging/logHandle.hpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGHANDLE_HPP +#define SHARE_VM_LOGGING_LOGHANDLE_HPP + +#include "logging/log.hpp" + +// Wraps a Log instance and throws away the template information. +// +// This can be used to pass a Log instance as a parameter without +// polluting the surrounding API with template functions. +class LogHandle { +private: + LogTagSet* _tagset; + +public: + template + LogHandle(const LogImpl& type_carrier) : + _tagset(&LogTagSetMapping::tagset()) {} + + bool is_level(LogLevelType level) { + return _tagset->is_level(level); + } + +#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \ + LogHandle& v##name(const char* fmt, va_list args) { \ + _tagset->vwrite(LogLevel::level, fmt, args); \ + return *this; \ + } \ + LogHandle& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \ + va_list args; \ + va_start(args, fmt); \ + _tagset->vwrite(LogLevel::level, fmt, args); \ + va_end(args); \ + return *this; \ + } \ + bool is_##name() { \ + return _tagset->is_level(LogLevel::level); \ + } + LOG_LEVEL_LIST +#undef LOG_LEVEL +}; + +// Wraps a LogTarget instance and throws away the template information. +// +// This can be used to pass a Log instance as a parameter without +// polluting the surrounding API with template functions. +class LogTargetHandle { + friend class LogStream; + +private: + const LogLevelType _level; + LogTagSet* _tagset; + +public: + template + LogTargetHandle(const LogTargetImpl& type_carrier) : + _level(level), + _tagset(&LogTagSetMapping::tagset()) {} + + template + static LogTargetHandle create() { + return LogTargetHandle(LogTargetImpl()); + } + + void print(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { + va_list args; + va_start(args, fmt); + _tagset->vwrite(_level, fmt, args); + va_end(args); + } + + bool is_enabled() const { + return _tagset->is_level(_level); + } + + // Creates a log stream from the information stored in this instance. + // Callers need a ResourceMark on the stack. + outputStream* stream() { + return create_log_stream(_level, _tagset);; + } +}; + +#endif // SHARE_VM_LOGGING_LOGHANDLE_HPP diff --git a/hotspot/src/share/vm/logging/logOutput.cpp b/hotspot/src/share/vm/logging/logOutput.cpp index ba0ce383fa8..0254b7616b5 100644 --- a/hotspot/src/share/vm/logging/logOutput.cpp +++ b/hotspot/src/share/vm/logging/logOutput.cpp @@ -56,6 +56,11 @@ void LogOutput::add_to_config_string(const LogTagSet* ts, LogLevelType level) { } size_t offset = strlen(_config_string); + if (offset > 0) { + // Add commas in-between tag and level combinations in the config string + _config_string[offset++] = ','; + } + for (;;) { int ret = ts->label(_config_string + offset, _config_string_buffer_size - offset, "+"); if (ret == -1) { @@ -69,7 +74,7 @@ void LogOutput::add_to_config_string(const LogTagSet* ts, LogLevelType level) { offset = strlen(_config_string); for (;;) { - int ret = jio_snprintf(_config_string + offset, _config_string_buffer_size - offset, "=%s,", LogLevel::name(level)); + int ret = jio_snprintf(_config_string + offset, _config_string_buffer_size - offset, "=%s", LogLevel::name(level)); if (ret == -1) { _config_string_buffer_size *= 2; _config_string = REALLOC_C_HEAP_ARRAY(char, _config_string, _config_string_buffer_size, mtLogging); diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 213fa7c2806..48d342d1ba8 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,23 +38,30 @@ // List of prefixes for specific tags and/or tagsets. // Syntax: LOG_PREFIX(, LOG_TAGS()) // Where the prefixer function matches the following signature: size_t (*)(char*, size_t) + +// Prefix function for internal vm test +DEBUG_ONLY(size_t Test_log_prefix_prefixer(char* buf, size_t len);) + #define LOG_PREFIX_LIST \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, age)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, alloc)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, alloc, region)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, barrier)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, classhisto)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction)) \ - LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, cpu)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, cset)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, heap)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, ihop)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, heap)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, heap, region)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, freelist)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, humongous)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ihop)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, liveness)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, marking)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ @@ -70,7 +77,9 @@ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, stats)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, time)) \ - LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, tlab)) + DEBUG_ONLY(LOG_PREFIX(Test_log_prefix_prefixer, LOG_TAGS(logging, test))) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, tlab)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, workgang)) // The empty prefix, used when there's no prefix defined. diff --git a/hotspot/src/share/vm/runtime/logTimer.hpp b/hotspot/src/share/vm/logging/logStream.cpp similarity index 69% rename from hotspot/src/share/vm/runtime/logTimer.hpp rename to hotspot/src/share/vm/logging/logStream.cpp index 81bbd085eb3..b68dca7f056 100644 --- a/hotspot/src/share/vm/runtime/logTimer.hpp +++ b/hotspot/src/share/vm/logging/logStream.cpp @@ -22,22 +22,13 @@ * */ -#ifndef SHARE_VM_RUNTIME_LOG_TIMER_HPP -#define SHARE_VM_RUNTIME_LOG_TIMER_HPP - +#include "precompiled.hpp" #include "logging/log.hpp" -#include "runtime/timer.hpp" +#include "logging/logStream.hpp" -// TraceStartupTime is used for tracing the execution time of a block with logging -// Usage: -// { TraceStartupTime t("block time") -// some_code(); -// } -// +// Create a log stream without an embedded ResourceMark. +// The function is placed here to be called out-of-line in log.hpp. +outputStream* create_log_stream(LogLevelType level, LogTagSet* tagset) { + return new LogStreamNoResourceMark(level, tagset); +} -class TraceStartupTime : public TraceTime { - public: - TraceStartupTime(const char* s) : TraceTime(s, log_is_enabled(Info, startuptime), LogTag::_startuptime) {} -}; - -#endif // SHARE_VM_RUNTIME_LOG_TIMER_HPP diff --git a/hotspot/src/share/vm/gc/shared/liveRange.hpp b/hotspot/src/share/vm/logging/logStream.hpp similarity index 50% rename from hotspot/src/share/vm/gc/shared/liveRange.hpp rename to hotspot/src/share/vm/logging/logStream.hpp index 51c7ccc19cc..38ba83ab3ee 100644 --- a/hotspot/src/share/vm/gc/shared/liveRange.hpp +++ b/hotspot/src/share/vm/logging/logStream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,34 +22,27 @@ * */ -#ifndef SHARE_VM_GC_SHARED_LIVERANGE_HPP -#define SHARE_VM_GC_SHARED_LIVERANGE_HPP +#ifndef SHARE_VM_LOGGING_LOGSTREAM_HPP +#define SHARE_VM_LOGGING_LOGSTREAM_HPP -#include "memory/memRegion.hpp" -#include "utilities/copy.hpp" +#include "logging/log.hpp" +#include "utilities/ostream.hpp" -// This is a shared helper class used during phase 3 and 4 to move all the objects -// Dead regions in a Space are linked together to keep track of the live regions -// so that the live data can be traversed quickly without having to look at each -// object. +// An output stream that logs to the logging framework. +// Requires a ResourceMark on the stack. +class LogStreamNoResourceMark : public outputStream { +private: + stringStream _current_line; + LogLevelType _level; + LogTagSet* _tagset; -class LiveRange: public MemRegion { public: - LiveRange(HeapWord* bottom, HeapWord* top): MemRegion(bottom, top) {} - - void set_end(HeapWord* e) { - assert(e >= start(), "should be a non-zero range"); - MemRegion::set_end(e); - } - void set_word_size(size_t ws) { - MemRegion::set_word_size(ws); + LogStreamNoResourceMark(LogLevelType level, LogTagSet* tagset) : _level(level), _tagset(tagset) {} + ~LogStreamNoResourceMark() { + guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?"); } - LiveRange * next() { return (LiveRange *) end(); } - - void move_to(HeapWord* destination) { - Copy::aligned_conjoint_words(start(), destination, word_size()); - } + void write(const char* s, size_t len); }; -#endif // SHARE_VM_GC_SHARED_LIVERANGE_HPP +#endif // SHARE_VM_LOGGING_LOGSTREAM_HPP diff --git a/hotspot/src/share/vm/logging/logStream.inline.hpp b/hotspot/src/share/vm/logging/logStream.inline.hpp new file mode 100644 index 00000000000..b1bff8b53bd --- /dev/null +++ b/hotspot/src/share/vm/logging/logStream.inline.hpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGSTREAM_INLINE_HPP +#define SHARE_VM_LOGGING_LOGSTREAM_INLINE_HPP + +#include "logging/log.hpp" +#include "logging/logHandle.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" +#include "utilities/ostream.hpp" + +inline void LogStreamNoResourceMark::write(const char* s, size_t len) { + if (len > 0 && s[len - 1] == '\n') { + _current_line.write(s, len - 1); + _tagset->write(_level, "%s", _current_line.as_string()); + _current_line.reset(); + } else { + _current_line.write(s, len); + } + update_position(s, len); +} + +// An output stream that logs to the logging framework, and embeds a ResourceMark. +// +// The class is intended to be stack allocated. +// Care needs to be taken when nested ResourceMarks are used. +class LogStream : public outputStream { +private: + ResourceMark _embedded_resource_mark; + LogStreamNoResourceMark _stream; + +public: + // Constructor to support creation from a LogTarget instance. + // + // LogTarget(Debug, gc) log; + // LogStream(log) stream; + template + LogStream(const LogTargetImpl& type_carrier) : + _embedded_resource_mark(), + _stream(level, &LogTagSetMapping::tagset()) {} + + // Constructor to support creation from typed (likely NULL) pointer. Mostly used by the logging framework. + // + // LogStream stream(log.debug()); + // LogStream stream((LogTargetImpl*)NULL); + template + LogStream(const LogTargetImpl* type_carrier) : + _embedded_resource_mark(), + _stream(level, &LogTagSetMapping::tagset()) {} + + // Constructor to support creation from a LogTargetHandle. + // + // LogTarget(Debug, gc) log; + // LogTargetHandle(log) handle; + // LogStream stream(handle); + LogStream(LogTargetHandle handle) : + _embedded_resource_mark(), + _stream(handle._level, handle._tagset) {} + + // Override of outputStream::write. + void write(const char* s, size_t len) { _stream.write(s, len); } +}; + +// Support creation of a LogStream without having to provide a LogTarget pointer. +#define LogStreamHandle(level, ...) LogStreamTemplate + +template +class LogStreamTemplate : public LogStream { +public: + LogStreamTemplate() : LogStream((LogTargetImpl*)NULL) {} +}; + +#endif // SHARE_VM_LOGGING_LOGSTREAM_INLINE_HPP diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index c7fb0a08325..78cb944c345 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_VM_LOGGING_LOGTAG_HPP #define SHARE_VM_LOGGING_LOGTAG_HPP +#include "logging/logTag_ext.hpp" #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" @@ -33,6 +34,7 @@ #define LOG_TAG_LIST \ LOG_TAG(alloc) \ LOG_TAG(age) \ + LOG_TAG(arguments) \ LOG_TAG(barrier) \ LOG_TAG(biasedlocking) \ LOG_TAG(bot) \ @@ -45,6 +47,7 @@ LOG_TAG(classunload) /* Trace unloading of classes */ \ LOG_TAG(classpath) \ LOG_TAG(compaction) \ + LOG_TAG(constraints) \ LOG_TAG(cpu) \ LOG_TAG(cset) \ LOG_TAG(defaultmethods) \ @@ -64,32 +67,41 @@ LOG_TAG(metaspace) \ LOG_TAG(modules) \ LOG_TAG(monitorinflation) \ + LOG_TAG(monitormismatch) \ LOG_TAG(os) \ LOG_TAG(phases) \ LOG_TAG(plab) \ LOG_TAG(promotion) \ + LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \ LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \ LOG_TAG(ref) \ LOG_TAG(refine) \ LOG_TAG(region) \ LOG_TAG(remset) \ LOG_TAG(safepoint) \ + LOG_TAG(safepointcleanup) \ LOG_TAG(scavenge) \ LOG_TAG(scrub) \ + LOG_TAG(stacktrace) \ LOG_TAG(start) \ LOG_TAG(startuptime) \ LOG_TAG(state) \ LOG_TAG(stats) \ LOG_TAG(stringdedup) \ + LOG_TAG(stringtable) \ LOG_TAG(survivor) \ LOG_TAG(sweep) \ LOG_TAG(task) \ + DEBUG_ONLY(LOG_TAG(test)) \ LOG_TAG(thread) \ LOG_TAG(tlab) \ LOG_TAG(time) \ + LOG_TAG(verification) \ LOG_TAG(verify) \ LOG_TAG(vmoperation) \ - LOG_TAG(vtables) + LOG_TAG(vtables) \ + LOG_TAG(workgang) \ + LOG_TAG_LIST_EXT #define PREFIX_LOG_TAG(T) (LogTag::_##T) diff --git a/hotspot/src/share/vm/logging/logTagSet.cpp b/hotspot/src/share/vm/logging/logTagSet.cpp index 7d22c480e32..db675a26854 100644 --- a/hotspot/src/share/vm/logging/logTagSet.cpp +++ b/hotspot/src/share/vm/logging/logTagSet.cpp @@ -27,14 +27,15 @@ #include "logging/logOutput.hpp" #include "logging/logTag.hpp" #include "logging/logTagSet.hpp" +#include "memory/allocation.inline.hpp" LogTagSet* LogTagSet::_list = NULL; size_t LogTagSet::_ntagsets = 0; // This constructor is called only during static initialization. // See the declaration in logTagSet.hpp for more information. -LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4) - : _next(_list) { +LogTagSet::LogTagSet(PrefixWriter prefix_writer, LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4) + : _next(_list), _write_prefix(prefix_writer) { _tag[0] = t0; _tag[1] = t1; _tag[2] = t2; @@ -49,10 +50,6 @@ LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, _output_list.set_output_level(LogOutput::Stderr, LogLevel::Default); } -bool LogTagSet::is_level(LogLevelType level) const { - return _output_list.is_level(level); -} - void LogTagSet::update_decorators(const LogDecorators& decorator) { LogDecorators new_decorators = decorator; for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { @@ -90,3 +87,34 @@ int LogTagSet::label(char* buf, size_t len, const char* separator) const { } return tot_written; } + +void LogTagSet::write(LogLevelType level, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(level, fmt, args); + va_end(args); +} + +const size_t vwrite_buffer_size = 512; + +void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { + char buf[vwrite_buffer_size]; + va_list saved_args; // For re-format on buf overflow. + va_copy(saved_args, args); + size_t prefix_len = _write_prefix(buf, sizeof(buf)); + // Check that string fits in buffer; resize buffer if necessary + int ret = os::log_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args); + assert(ret >= 0, "Log message buffer issue"); + if ((size_t)ret >= sizeof(buf)) { + size_t newbuf_len = prefix_len + ret + 1; + char* newbuf = NEW_C_HEAP_ARRAY(char, newbuf_len, mtLogging); + memcpy(newbuf, buf, prefix_len); + ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args); + assert(ret >= 0, "Log message buffer issue"); + log(level, newbuf); + FREE_C_HEAP_ARRAY(char, newbuf); + } else { + log(level, buf); + } + va_end(saved_args); +} diff --git a/hotspot/src/share/vm/logging/logTagSet.hpp b/hotspot/src/share/vm/logging/logTagSet.hpp index 3259e49eadb..7b193fc9751 100644 --- a/hotspot/src/share/vm/logging/logTagSet.hpp +++ b/hotspot/src/share/vm/logging/logTagSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "logging/logDecorators.hpp" #include "logging/logLevel.hpp" #include "logging/logOutputList.hpp" +#include "logging/logPrefix.hpp" #include "logging/logTag.hpp" #include "utilities/globalDefinitions.hpp" @@ -45,14 +46,17 @@ class LogTagSet VALUE_OBJ_CLASS_SPEC { LogOutputList _output_list; LogDecorators _decorators; + typedef size_t (*PrefixWriter)(char* buf, size_t size); + PrefixWriter _write_prefix; + // Keep constructor private to prevent incorrect instantiations of this class. // Only LogTagSetMappings can create/contain instances of this class. // The constructor links all tagsets together in a global list of tagsets. // This list is used during configuration to be able to update all tagsets // and their configurations to reflect the new global log configuration. - LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4); + LogTagSet(PrefixWriter prefix_writer, LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4); - template + template friend class LogTagSetMapping; public: @@ -68,6 +72,10 @@ class LogTagSet VALUE_OBJ_CLASS_SPEC { return _ntags; } + LogTagType tag(size_t idx) const { + return _tag[idx]; + } + bool contains(LogTagType tag) const { for (size_t i = 0; _tag[i] != LogTag::__NO_TAG; i++) { if (tag == _tag[i]) { @@ -91,14 +99,37 @@ class LogTagSet VALUE_OBJ_CLASS_SPEC { int label(char *buf, size_t len, const char* separator = ",") const; bool has_output(const LogOutput* output); - bool is_level(LogLevelType level) const; + + // The implementation of this function is put here to ensure + // that it is inline:able by the log_is_enabled(level, ...) macro. + bool is_level(LogLevelType level) const { + return _output_list.is_level(level); + } void log(LogLevelType level, const char* msg); + + ATTRIBUTE_PRINTF(3, 4) + void write(LogLevelType level, const char* fmt, ...); + + template + ATTRIBUTE_PRINTF(2, 3) + void write(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(Level, fmt, args); + va_end(args); + } + + ATTRIBUTE_PRINTF(3, 0) + void vwrite(LogLevelType level, const char* fmt, va_list args); }; template + LogTagType T3 = LogTag::__NO_TAG, LogTagType T4 = LogTag::__NO_TAG, + LogTagType GuardTag = LogTag::__NO_TAG> class LogTagSetMapping : public AllStatic { private: + // Verify number of logging tags does not exceed maximum supported. + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); static LogTagSet _tagset; public: @@ -112,7 +143,7 @@ public: // Each combination of tags used as template arguments to the Log class somewhere (via macro or not) // will instantiate the LogTagSetMapping template, which in turn creates the static field for that // tagset. This _tagset contains the configuration for those tags. -template -LogTagSet LogTagSetMapping::_tagset(T0, T1, T2, T3, T4); +template +LogTagSet LogTagSetMapping::_tagset(&LogPrefix::prefix, T0, T1, T2, T3, T4); #endif // SHARE_VM_LOGGING_LOGTAGSET_HPP diff --git a/hotspot/src/share/vm/logging/logTag_ext.hpp b/hotspot/src/share/vm/logging/logTag_ext.hpp new file mode 100644 index 00000000000..0300d311a2e --- /dev/null +++ b/hotspot/src/share/vm/logging/logTag_ext.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAG_EXT_HPP +#define SHARE_VM_LOGGING_LOGTAG_EXT_HPP + +#define LOG_TAG_LIST_EXT + +#endif // SHARE_VM_LOGGING_LOGTAG_EXT_HPP diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index c86eb5174ab..5a3ae92cb60 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -242,7 +242,7 @@ class ChunkPool: public CHeapObj { ChunkPool(size_t size) : _size(size) { _first = NULL; _num_chunks = _num_used = 0; } // Allocate a new chunk from the pool (might expand the pool) - _NOINLINE_ void* allocate(size_t bytes, AllocFailType alloc_failmode) { + NOINLINE void* allocate(size_t bytes, AllocFailType alloc_failmode) { assert(bytes == _size, "bad size"); void* p = NULL; // No VM lock can be taken inside ThreadCritical lock, so os::malloc diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index e7cb81947af..2705c6d8994 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -41,18 +41,6 @@ #define ARENA_ALIGN_MASK (~((size_t)ARENA_ALIGN_M1)) #define ARENA_ALIGN(x) ((((size_t)(x)) + ARENA_ALIGN_M1) & ARENA_ALIGN_MASK) - -// noinline attribute -#ifdef _WINDOWS - #define _NOINLINE_ __declspec(noinline) -#else - #if __GNUC__ < 3 // gcc 2.x does not support noinline attribute - #define _NOINLINE_ - #else - #define _NOINLINE_ __attribute__ ((noinline)) - #endif -#endif - class AllocFailStrategy { public: enum AllocFailEnum { EXIT_OOM, RETURN_NULL }; @@ -178,17 +166,17 @@ class NativeCallStack; template class CHeapObj ALLOCATION_SUPER_CLASS_SPEC { public: - _NOINLINE_ void* operator new(size_t size, const NativeCallStack& stack) throw(); - _NOINLINE_ void* operator new(size_t size) throw(); - _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant, + NOINLINE void* operator new(size_t size, const NativeCallStack& stack) throw(); + NOINLINE void* operator new(size_t size) throw(); + NOINLINE void* operator new (size_t size, const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw(); - _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant) + NOINLINE void* operator new (size_t size, const std::nothrow_t& nothrow_constant) throw(); - _NOINLINE_ void* operator new [](size_t size, const NativeCallStack& stack) throw(); - _NOINLINE_ void* operator new [](size_t size) throw(); - _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant, + NOINLINE void* operator new [](size_t size, const NativeCallStack& stack) throw(); + NOINLINE void* operator new [](size_t size) throw(); + NOINLINE void* operator new [](size_t size, const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw(); - _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant) + NOINLINE void* operator new [](size_t size, const std::nothrow_t& nothrow_constant) throw(); void operator delete(void* p); void operator delete [] (void* p); @@ -724,30 +712,42 @@ public: // is set so that we always use malloc except for Solaris where we set the // limit to get mapped memory. template -class ArrayAllocator VALUE_OBJ_CLASS_SPEC { - char* _addr; - bool _use_malloc; - size_t _size; - bool _free_in_destructor; +class ArrayAllocator : public AllStatic { + private: + static bool should_use_malloc(size_t length); - static bool should_use_malloc(size_t size) { - return size < ArrayAllocatorMallocLimit; - } + static E* allocate_malloc(size_t length); + static E* allocate_mmap(size_t length); + + static void free_malloc(E* addr, size_t length); + static void free_mmap(E* addr, size_t length); - static char* allocate_inner(size_t& size, bool& use_malloc); public: - ArrayAllocator(bool free_in_destructor = true) : - _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { } + static E* allocate(size_t length); + static E* reallocate(E* old_addr, size_t old_length, size_t new_length); + static void free(E* addr, size_t length); +}; - ~ArrayAllocator() { - if (_free_in_destructor) { - free(); - } - } +// Uses mmaped memory for all allocations. All allocations are initially +// zero-filled. No pre-touching. +template +class MmapArrayAllocator : public AllStatic { + private: + static size_t size_for(size_t length); - E* allocate(size_t length); - E* reallocate(size_t new_length); - void free(); + public: + static E* allocate(size_t length); + static void free(E* addr, size_t length); +}; + +// Uses malloc:ed memory for all allocations. +template +class MallocArrayAllocator : public AllStatic { + public: + static size_t size_for(size_t length); + + static E* allocate(size_t length); + static void free(E* addr, size_t length); }; #endif // SHARE_VM_MEMORY_ALLOCATION_HPP diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index 961f510b14e..27c9c786fbc 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -151,66 +151,107 @@ template void CHeapObj::operator delete [](void* p){ } template -char* ArrayAllocator::allocate_inner(size_t &size, bool &use_malloc) { - char* addr = NULL; - - if (use_malloc) { - addr = AllocateHeap(size, F); - if (addr == NULL && size >= (size_t)os::vm_allocation_granularity()) { - // malloc failed let's try with mmap instead - use_malloc = false; - } else { - return addr; - } - } - +size_t MmapArrayAllocator::size_for(size_t length) { + size_t size = length * sizeof(E); int alignment = os::vm_allocation_granularity(); - size = align_size_up(size, alignment); + return align_size_up(size, alignment); +} - addr = os::reserve_memory(size, NULL, alignment, F); +template +E* MmapArrayAllocator::allocate(size_t length) { + size_t size = size_for(length); + int alignment = os::vm_allocation_granularity(); + + char* addr = os::reserve_memory(size, NULL, alignment, F); if (addr == NULL) { vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); } os::commit_memory_or_exit(addr, size, !ExecMem, "Allocator (commit)"); - return addr; + + return (E*)addr; +} + +template +void MmapArrayAllocator::free(E* addr, size_t length) { + bool result = os::release_memory((char*)addr, size_for(length)); + assert(result, "Failed to release memory"); +} + +template +size_t MallocArrayAllocator::size_for(size_t length) { + return length * sizeof(E); +} + +template +E* MallocArrayAllocator::allocate(size_t length) { + return (E*)AllocateHeap(size_for(length), F); +} + +template +void MallocArrayAllocator::free(E* addr, size_t /*length*/) { + FreeHeap(addr); +} + +template +bool ArrayAllocator::should_use_malloc(size_t length) { + return MallocArrayAllocator::size_for(length) < ArrayAllocatorMallocLimit; +} + +template +E* ArrayAllocator::allocate_malloc(size_t length) { + return MallocArrayAllocator::allocate(length); +} + +template +E* ArrayAllocator::allocate_mmap(size_t length) { + return MmapArrayAllocator::allocate(length); } template E* ArrayAllocator::allocate(size_t length) { - assert(_addr == NULL, "Already in use"); + if (should_use_malloc(length)) { + return allocate_malloc(length); + } - _size = sizeof(E) * length; - _use_malloc = should_use_malloc(_size); - _addr = allocate_inner(_size, _use_malloc); - - return (E*)_addr; + return allocate_mmap(length); } template -E* ArrayAllocator::reallocate(size_t new_length) { - size_t new_size = sizeof(E) * new_length; - bool use_malloc = should_use_malloc(new_size); - char* new_addr = allocate_inner(new_size, use_malloc); +E* ArrayAllocator::reallocate(E* old_addr, size_t old_length, size_t new_length) { + E* new_addr = (new_length > 0) + ? allocate(new_length) + : NULL; - memcpy(new_addr, _addr, MIN2(new_size, _size)); + if (new_addr != NULL && old_addr != NULL) { + memcpy(new_addr, old_addr, MIN2(old_length, new_length) * sizeof(E)); + } - free(); - _size = new_size; - _use_malloc = use_malloc; - _addr = new_addr; - return (E*)new_addr; + if (old_addr != NULL) { + free(old_addr, old_length); + } + + return new_addr; } template -void ArrayAllocator::free() { - if (_addr != NULL) { - if (_use_malloc) { - FreeHeap(_addr); +void ArrayAllocator::free_malloc(E* addr, size_t length) { + MallocArrayAllocator::free(addr, length); +} + +template +void ArrayAllocator::free_mmap(E* addr, size_t length) { + MmapArrayAllocator::free(addr, length); +} + +template +void ArrayAllocator::free(E* addr, size_t length) { + if (addr != NULL) { + if (should_use_malloc(length)) { + free_malloc(addr, length); } else { - os::release_memory(_addr, _size); + free_mmap(addr, length); } - _addr = NULL; } } diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp index c96fd6a32f1..d15262d8472 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/cms/allocationStats.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/logStream.inline.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/freeList.hpp" @@ -1190,10 +1191,10 @@ void BinaryTreeDictionary::end_sweep_dict_census(double spl // Does walking the tree 3 times hurt? set_tree_surplus(splitSurplusPercent); set_tree_hints(); - LogHandle(gc, freelist, stats) log; - if (log.is_trace()) { - ResourceMark rm; - report_statistics(log.trace_stream()); + LogTarget(Trace, gc, freelist, stats) log; + if (log.is_enabled()) { + LogStream out(log); + report_statistics(&out); } clear_tree_census(); } @@ -1232,27 +1233,26 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure* fl) { - LogHandle(gc, freelist, census) log; - outputStream* out = log.debug_stream(); + LogStreamHandle(Debug, gc, freelist, census) out; + if (++_print_line >= 40) { - ResourceMark rm; - FreeList_t::print_labels_on(out, "size"); + FreeList_t::print_labels_on(&out, "size"); _print_line = 0; } - fl->print_on(out); + fl->print_on(&out); _total_free += fl->count() * fl->size(); total()->set_count(total()->count() + fl->count()); } #if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { - LogHandle(gc, freelist, census) log; - outputStream* out = log.debug_stream(); + LogStreamHandle(Debug, gc, freelist, census) out; + if (++_print_line >= 40) { - FreeList_t::print_labels_on(out, "size"); + FreeList_t::print_labels_on(&out, "size"); _print_line = 0; } - fl->print_on(out); + fl->print_on(&out); _total_free += fl->count() * fl->size() ; total()->set_count( total()->count() + fl->count() ); total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() ); diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 0f6415e49e3..606b7bd6960 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -372,7 +372,7 @@ bool FileMapInfo::open_for_read() { fail_continue("Specified shared archive not found."); } else { fail_continue("Failed to open shared archive file (%s).", - strerror(errno)); + os::strerror(errno)); } return false; } @@ -402,7 +402,7 @@ void FileMapInfo::open_for_write() { int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); if (fd < 0) { fail_stop("Unable to create shared archive file %s: (%s).", _full_path, - strerror(errno)); + os::strerror(errno)); } _fd = fd; _file_offset = 0; diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index 3293571ec71..6d7d9d4fece 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -213,6 +213,16 @@ class BoolObjectClosure : public Closure { virtual bool do_object_b(oop obj) = 0; }; +class AlwaysTrueClosure: public BoolObjectClosure { + public: + bool do_object_b(oop p) { return true; } +}; + +class AlwaysFalseClosure : public BoolObjectClosure { + public: + bool do_object_b(oop p) { return false; } +}; + // Applies an oop closure to all ref fields in objects iterated over in an // object iteration. class ObjectToOopClosure: public ObjectClosure { diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 352fc09ea17..aa04201ad2e 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -759,7 +759,6 @@ class SpaceManager : public CHeapObj { void verify(); void verify_chunk_size(Metachunk* chunk); - NOT_PRODUCT(void mangle_freed_chunks();) #ifdef ASSERT void verify_allocated_blocks_words(); #endif @@ -889,7 +888,7 @@ Metachunk* VirtualSpaceNode::take_from_committed(size_t chunk_word_size) { "The committed memory doesn't match the expanded memory."); if (!is_available(chunk_word_size)) { - LogHandle(gc, metaspace, freelist) log; + Log(gc, metaspace, freelist) log; log.debug("VirtualSpaceNode::take_from_committed() not available " SIZE_FORMAT " words ", chunk_word_size); // Dump some information about the virtual space that is nearly full ResourceMark rm; @@ -1230,7 +1229,7 @@ void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry) { new_entry->mangle(); #endif if (log_is_enabled(Trace, gc, metaspace)) { - LogHandle(gc, metaspace) log; + Log(gc, metaspace) log; VirtualSpaceNode* vsl = current_virtual_space(); ResourceMark rm; vsl->print_on(log.trace_stream()); @@ -1569,7 +1568,7 @@ void MetaspaceGC::compute_new_size() { } else { _shrink_factor = MIN2(current_shrink_factor * 4, (uint) 100); } - log_trace(gc, metaspace)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", + log_trace(gc, metaspace)(" shrinking: initThreshold: %.1fK maximum_desired_capacity: %.1fK", MetaspaceSize / (double) K, maximum_desired_capacity / (double) K); log_trace(gc, metaspace)(" shrink_bytes: %.1fK current_shrink_factor: %d new shrink factor: %d MinMetaspaceExpansion: %.1fK", shrink_bytes / (double) K, current_shrink_factor, _shrink_factor, MinMetaspaceExpansion / (double) K); @@ -1792,7 +1791,7 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { assert((word_size <= chunk->word_size()) || list_index(chunk->word_size() == HumongousIndex), "Non-humongous variable sized chunk"); - LogHandle(gc, metaspace, freelist) log; + Log(gc, metaspace, freelist) log; if (log.is_debug()) { size_t list_count; if (list_index(word_size) < HumongousIndex) { @@ -1991,7 +1990,7 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { "Size calculation is wrong, word_size " SIZE_FORMAT " chunk_word_size " SIZE_FORMAT, word_size, chunk_word_size); - LogHandle(gc, metaspace, alloc) log; + Log(gc, metaspace, alloc) log; if (log.is_debug() && SpaceManager::is_humongous(word_size)) { log.debug("Metadata humongous allocation:"); log.debug(" word_size " PTR_FORMAT, word_size); @@ -2160,7 +2159,7 @@ SpaceManager::~SpaceManager() { dec_total_from_size_metrics(); - LogHandle(gc, metaspace, freelist) log; + Log(gc, metaspace, freelist) log; if (log.is_trace()) { log.trace("~SpaceManager(): " PTR_FORMAT, p2i(this)); ResourceMark rm; @@ -2300,7 +2299,7 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { inc_size_metrics(new_chunk->word_size()); assert(new_chunk->is_empty(), "Not ready for reuse"); - LogHandle(gc, metaspace, freelist) log; + Log(gc, metaspace, freelist) log; if (log.is_trace()) { log.trace("SpaceManager::add_chunk: " SIZE_FORMAT ") ", sum_count_in_chunks_in_use()); ResourceMark rm; @@ -2331,7 +2330,7 @@ Metachunk* SpaceManager::get_new_chunk(size_t word_size, medium_chunk_bunch()); } - LogHandle(gc, metaspace, alloc) log; + Log(gc, metaspace, alloc) log; if (log.is_debug() && next != NULL && SpaceManager::is_humongous(next->word_size())) { log.debug(" new humongous chunk word size " PTR_FORMAT, next->word_size()); @@ -2512,20 +2511,6 @@ void SpaceManager::dump(outputStream* const out) const { " waste " SIZE_FORMAT, curr_total, used, free, capacity, waste); } -#ifndef PRODUCT -void SpaceManager::mangle_freed_chunks() { - for (ChunkIndex index = ZeroIndex; - index < NumberOfInUseLists; - index = next_chunk_index(index)) { - for (Metachunk* curr = chunks_in_use(index); - curr != NULL; - curr = curr->next()) { - curr->mangle(uninitMetaWordVal); - } - } -} -#endif // PRODUCT - // MetaspaceAux @@ -3045,7 +3030,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a initialize_class_space(metaspace_rs); if (log_is_enabled(Trace, gc, metaspace)) { - LogHandle(gc, metaspace) log; + Log(gc, metaspace) log; ResourceMark rm; print_compressed_class_space(log.trace_stream(), requested_addr); } @@ -3520,7 +3505,7 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s tracer()->report_metadata_oom(loader_data, word_size, type, mdtype); // If result is still null, we are out of memory. - LogHandle(gc, metaspace, freelist) log; + Log(gc, metaspace, freelist) log; if (log.is_trace()) { log.trace("Metaspace allocation failed for size " SIZE_FORMAT, word_size); ResourceMark rm; diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index dc4fc082967..36efacfc4ab 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -38,9 +38,10 @@ #include "memory/filemap.hpp" #include "memory/metaspace.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/os.hpp" #include "runtime/signature.hpp" #include "runtime/vmThread.hpp" @@ -775,7 +776,7 @@ void MetaspaceShared::prepare_for_dumping() { // Preload classes from a list, populate the shared spaces and dump to a // file. void MetaspaceShared::preload_and_dump(TRAPS) { - { TraceStartupTime timer("Dump Shared Spaces"); + { TraceTime timer("Dump Shared Spaces", TRACETIME_LOG(Info, startuptime)); ResourceMark rm; char class_list_path_str[JVM_MAXPATHLEN]; @@ -882,7 +883,7 @@ int MetaspaceShared::preload_and_dump(const char* class_list_path, InstanceKlass* ik = InstanceKlass::cast(klass); - // Should be class load order as per -XX:+TraceClassLoadingPreorder + // Should be class load order as per -Xlog:classload+preorder class_promote_order->append(ik); // Link the class to cause the bytecodes to be rewritten and the diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 60a60e2feed..f33afa87ea2 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -44,6 +44,7 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "memory/universe.inline.hpp" #include "oops/constantPool.hpp" @@ -64,11 +65,10 @@ #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" -#include "runtime/logTimer.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/timer.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vm_operations.hpp" #include "services/memoryService.hpp" #include "utilities/copy.hpp" @@ -377,8 +377,7 @@ void Universe::genesis(TRAPS) { // We can allocate directly in the permanent generation, so we do. int size; if (UseConcMarkSweepGC) { - warning("Using +FullGCALot with concurrent mark sweep gc " - "will not force all objects to relocate"); + log_warning(gc)("Using +FullGCALot with concurrent mark sweep gc will not force all objects to relocate"); size = FullGCALotDummies; } else { size = FullGCALotDummies * 2; @@ -629,7 +628,7 @@ jint universe_init() { guarantee(sizeof(oop) % sizeof(HeapWord) == 0, "oop size is not not a multiple of HeapWord size"); - TraceStartupTime timer("Genesis"); + TraceTime timer("Genesis", TRACETIME_LOG(Info, startuptime)); JavaClasses::compute_hard_coded_offsets(); @@ -880,6 +879,57 @@ Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() { return UnscaledNarrowOop; } +void initialize_known_method(LatestMethodCache* method_cache, + InstanceKlass* ik, + const char* method, + Symbol* signature, + bool is_static, TRAPS) +{ + TempNewSymbol name = SymbolTable::new_symbol(method, CHECK); + Method* m = NULL; + // The klass must be linked before looking up the method. + if (!ik->link_class_or_fail(THREAD) || + ((m = ik->find_method(name, signature)) == NULL) || + is_static != m->is_static()) { + ResourceMark rm(THREAD); + // NoSuchMethodException doesn't actually work because it tries to run the + // function before java_lang_Class is linked. Print error and exit. + vm_exit_during_initialization(err_msg("Unable to link/verify %s.%s method", + ik->name()->as_C_string(), method)); + } + method_cache->init(ik, m); +} + +void Universe::initialize_known_methods(TRAPS) { + // Set up static method for registering finalizers + initialize_known_method(_finalizer_register_cache, + SystemDictionary::Finalizer_klass(), + "register", + vmSymbols::object_void_signature(), true, CHECK); + + initialize_known_method(_throw_illegal_access_error_cache, + SystemDictionary::internal_Unsafe_klass(), + "throwIllegalAccessError", + vmSymbols::void_method_signature(), true, CHECK); + + // Set up method for registering loaded classes in class loader vector + initialize_known_method(_loader_addClass_cache, + SystemDictionary::ClassLoader_klass(), + "addClass", + vmSymbols::class_void_signature(), false, CHECK); + + // Set up method for checking protection domain + initialize_known_method(_pd_implies_cache, + SystemDictionary::ProtectionDomain_klass(), + "impliesCreateAccessControlContext", + vmSymbols::void_boolean_signature(), false, CHECK); + + // Set up method for stack walking + initialize_known_method(_do_stack_walk_cache, + SystemDictionary::AbstractStackWalker_klass(), + "doStackWalk", + vmSymbols::doStackWalk_signature(), false, CHECK); +} void universe2_init() { EXCEPTION_MARK; @@ -908,46 +958,46 @@ bool universe_post_init() { HandleMark hm(THREAD); Klass* k; instanceKlassHandle k_h; - // Setup preallocated empty java.lang.Class array - Universe::_the_empty_class_klass_array = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_false); + // Setup preallocated empty java.lang.Class array + Universe::_the_empty_class_klass_array = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_false); - // Setup preallocated OutOfMemoryError errors - k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false); - k_h = instanceKlassHandle(THREAD, k); - Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false); - Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false); - Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false); - Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false); - Universe::_out_of_memory_error_gc_overhead_limit = - k_h->allocate_instance(CHECK_false); - Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false); + // Setup preallocated OutOfMemoryError errors + k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false); + k_h = instanceKlassHandle(THREAD, k); + Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_gc_overhead_limit = + k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false); - // Setup preallocated cause message for delayed StackOverflowError - if (StackReservedPages > 0) { - Universe::_delayed_stack_overflow_error_message = - java_lang_String::create_oop_from_str("Delayed StackOverflowError due to ReservedStackAccess annotated method", CHECK_false); - } + // Setup preallocated cause message for delayed StackOverflowError + if (StackReservedPages > 0) { + Universe::_delayed_stack_overflow_error_message = + java_lang_String::create_oop_from_str("Delayed StackOverflowError due to ReservedStackAccess annotated method", CHECK_false); + } - // Setup preallocated NullPointerException - // (this is currently used for a cheap & dirty solution in compiler exception handling) - k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false); - Universe::_null_ptr_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false); - // Setup preallocated ArithmeticException - // (this is currently used for a cheap & dirty solution in compiler exception handling) - k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ArithmeticException(), true, CHECK_false); - Universe::_arithmetic_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false); - // Virtual Machine Error for when we get into a situation we can't resolve - k = SystemDictionary::resolve_or_fail( - vmSymbols::java_lang_VirtualMachineError(), true, CHECK_false); - bool linked = InstanceKlass::cast(k)->link_class_or_fail(CHECK_false); - if (!linked) { - tty->print_cr("Unable to link/verify VirtualMachineError class"); - return false; // initialization failed - } - Universe::_virtual_machine_error_instance = - InstanceKlass::cast(k)->allocate_instance(CHECK_false); + // Setup preallocated NullPointerException + // (this is currently used for a cheap & dirty solution in compiler exception handling) + k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false); + Universe::_null_ptr_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false); + // Setup preallocated ArithmeticException + // (this is currently used for a cheap & dirty solution in compiler exception handling) + k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ArithmeticException(), true, CHECK_false); + Universe::_arithmetic_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false); + // Virtual Machine Error for when we get into a situation we can't resolve + k = SystemDictionary::resolve_or_fail( + vmSymbols::java_lang_VirtualMachineError(), true, CHECK_false); + bool linked = InstanceKlass::cast(k)->link_class_or_fail(CHECK_false); + if (!linked) { + tty->print_cr("Unable to link/verify VirtualMachineError class"); + return false; // initialization failed + } + Universe::_virtual_machine_error_instance = + InstanceKlass::cast(k)->allocate_instance(CHECK_false); - Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false); + Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false); if (!DumpSharedSpaces) { // These are the only Java fields that are currently set during shared space dumping. @@ -988,71 +1038,7 @@ bool universe_post_init() { Universe::_preallocated_out_of_memory_error_avail_count = (jint)len; } - - // Setup static method for registering finalizers - // The finalizer klass must be linked before looking up the method, in - // case it needs to get rewritten. - SystemDictionary::Finalizer_klass()->link_class(CHECK_false); - Method* m = SystemDictionary::Finalizer_klass()->find_method( - vmSymbols::register_method_name(), - vmSymbols::register_method_signature()); - if (m == NULL || !m->is_static()) { - tty->print_cr("Unable to link/verify Finalizer.register method"); - return false; // initialization failed (cannot throw exception yet) - } - Universe::_finalizer_register_cache->init( - SystemDictionary::Finalizer_klass(), m); - - SystemDictionary::internal_Unsafe_klass()->link_class(CHECK_false); - m = SystemDictionary::internal_Unsafe_klass()->find_method( - vmSymbols::throwIllegalAccessError_name(), - vmSymbols::void_method_signature()); - if (m != NULL && !m->is_static()) { - // Note null is okay; this method is used in itables, and if it is null, - // then AbstractMethodError is thrown instead. - tty->print_cr("Unable to link/verify Unsafe.throwIllegalAccessError method"); - return false; // initialization failed (cannot throw exception yet) - } - Universe::_throw_illegal_access_error_cache->init( - SystemDictionary::internal_Unsafe_klass(), m); - - // Setup method for registering loaded classes in class loader vector - SystemDictionary::ClassLoader_klass()->link_class(CHECK_false); - m = SystemDictionary::ClassLoader_klass()->find_method(vmSymbols::addClass_name(), vmSymbols::class_void_signature()); - if (m == NULL || m->is_static()) { - tty->print_cr("Unable to link/verify ClassLoader.addClass method"); - return false; // initialization failed (cannot throw exception yet) - } - Universe::_loader_addClass_cache->init( - SystemDictionary::ClassLoader_klass(), m); - - // Setup method for checking protection domain - SystemDictionary::ProtectionDomain_klass()->link_class(CHECK_false); - m = SystemDictionary::ProtectionDomain_klass()-> - find_method(vmSymbols::impliesCreateAccessControlContext_name(), - vmSymbols::void_boolean_signature()); - // Allow NULL which should only happen with bootstrapping. - if (m != NULL) { - if (m->is_static()) { - // NoSuchMethodException doesn't actually work because it tries to run the - // function before java_lang_Class is linked. Print error and exit. - tty->print_cr("ProtectionDomain.impliesCreateAccessControlContext() has the wrong linkage"); - return false; // initialization failed - } - Universe::_pd_implies_cache->init( - SystemDictionary::ProtectionDomain_klass(), m); - } - - // Setup method for stack walking - InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->link_class(CHECK_false); - m = InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())-> - find_method(vmSymbols::doStackWalk_name(), - vmSymbols::doStackWalk_signature()); - // Allow NULL which should only happen with bootstrapping. - if (m != NULL) { - Universe::_do_stack_walk_cache->init( - SystemDictionary::AbstractStackWalker_klass(), m); - } + Universe::initialize_known_methods(CHECK_false); // This needs to be done before the first scavenge/gc, since // it's an input to soft ref clearing policy. @@ -1097,20 +1083,20 @@ void Universe::print_heap_at_SIGBREAK() { } void Universe::print_heap_before_gc() { - LogHandle(gc, heap) log; - if (log.is_trace()) { - log.trace("Heap before GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); + Log(gc, heap) log; + if (log.is_debug()) { + log.debug("Heap before GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); ResourceMark rm; - heap()->print_on(log.trace_stream()); + heap()->print_on(log.debug_stream()); } } void Universe::print_heap_after_gc() { - LogHandle(gc, heap) log; - if (log.is_trace()) { - log.trace("Heap after GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); + Log(gc, heap) log; + if (log.is_debug()) { + log.debug("Heap after GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); ResourceMark rm; - heap()->print_on(log.trace_stream()); + heap()->print_on(log.debug_stream()); } } diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 340e87fb706..924809b5704 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -323,6 +323,9 @@ class Universe: AllStatic { static Method* do_stack_walk_method() { return _do_stack_walk_cache->get_method(); } + // Function to initialize these + static void initialize_known_methods(TRAPS); + static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; } diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index 50d5e041d84..98088b6a1f1 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -29,6 +29,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcLocker.hpp" #include "jvmtifiles/jvmti.h" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index 3a5d5a7fb73..5ffc8e03e81 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.cpp @@ -27,6 +27,7 @@ #include "interpreter/interpreter.hpp" #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/constMethod.hpp" #include "oops/method.hpp" diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 6d7b72c3f07..75a2bf970da 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -33,6 +33,7 @@ #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/constantPool.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" @@ -208,11 +209,11 @@ void ConstantPool::trace_class_resolution(const constantPoolHandle& this_cp, Kla if (k() != this_cp->pool_holder()) { // only print something if the classes are different if (source_file != NULL) { - log_info(classresolve)("%s %s %s:%d", + log_debug(classresolve)("%s %s %s:%d", this_cp->pool_holder()->external_name(), k->external_name(), source_file, line_number); } else { - log_info(classresolve)("%s %s", + log_debug(classresolve)("%s %s", this_cp->pool_holder()->external_name(), k->external_name()); } @@ -281,15 +282,10 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data(); this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM - if (log_is_enabled(Info, classresolve) && !k->is_array_klass()) { - // skip resolving the constant pool so that this code gets - // called the next time some bytecodes refer to this class. - trace_class_resolution(this_cp, k); - return k(); - } else { - this_cp->klass_at_put(which, k()); - } + // logging for classresolve tag. + trace_class_resolution(this_cp, k); + this_cp->klass_at_put(which, k()); entry = this_cp->resolved_klass_at(which); assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); return entry.get_klass(); diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 1e9b0b649e9..491688ccc6f 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/rewriter.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/cpCache.hpp" #include "oops/objArrayOop.inline.hpp" diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index 53ec05ef6ea..60738d741a5 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,16 @@ #include "precompiled.hpp" #include "interpreter/bytecodeStream.hpp" +#include "logging/log.hpp" #include "oops/generateOopMap.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/relocator.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/ostream.hpp" #include "prims/methodHandles.hpp" // @@ -786,7 +789,7 @@ void GenerateOopMap::merge_state_into_bb(BasicBlock *bb) { bb->set_changed(true); } } else { - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("monitor stack height merge conflict"); } // When the monitor stacks are not matched, we set _monitor_top to @@ -855,7 +858,7 @@ CellTypeState GenerateOopMap::monitor_pop() { _monitor_safe = false; _monitor_top = bad_monitors; - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("monitor stack underflow"); } return CellTypeState::ref; // just to keep the analysis going. @@ -871,7 +874,7 @@ void GenerateOopMap::monitor_push(CellTypeState cts) { _monitor_safe = false; _monitor_top = bad_monitors; - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("monitor stack overflow"); } return; @@ -1244,7 +1247,7 @@ void GenerateOopMap::do_exception_edge(BytecodeStream* itr) { // We don't set _monitor_top to bad_monitors because there are no successors // to this exceptional exit. - if (TraceMonitorMismatch && _monitor_safe) { + if (log_is_enabled(Info, monitormismatch) && _monitor_safe) { // We check _monitor_safe so that we only report the first mismatched // exceptional exit. report_monitor_mismatch("non-empty monitor stack at exceptional exit"); @@ -1254,11 +1257,11 @@ void GenerateOopMap::do_exception_edge(BytecodeStream* itr) { } void GenerateOopMap::report_monitor_mismatch(const char *msg) { -#ifndef PRODUCT - tty->print(" Monitor mismatch in method "); - method()->print_short_name(tty); - tty->print_cr(": %s", msg); -#endif + ResourceMark rm; + outputStream* out = Log(monitormismatch)::info_stream(); + out->print("Monitor mismatch in method "); + method()->print_short_name(out); + out->print_cr(": %s", msg); } void GenerateOopMap::print_states(outputStream *os, @@ -1781,7 +1784,7 @@ void GenerateOopMap::do_monitorenter(int bci) { _monitor_top = bad_monitors; _monitor_safe = false; - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("nested redundant lock -- bailout..."); } return; @@ -1819,7 +1822,7 @@ void GenerateOopMap::do_monitorexit(int bci) { bb->set_changed(true); bb->_monitor_top = bad_monitors; - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("improper monitor pair"); } } else { @@ -1845,7 +1848,7 @@ void GenerateOopMap::do_return_monitor_check() { // Since there are no successors to the *return bytecode, it // isn't necessary to set _monitor_top to bad_monitors. - if (TraceMonitorMismatch) { + if (log_is_enabled(Info, monitormismatch)) { report_monitor_mismatch("non-empty monitor stack at return"); } } diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 5eb39b8fa70..f97f826444b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -41,6 +41,7 @@ #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceKlass.inline.hpp" @@ -1089,7 +1090,7 @@ void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_k, TRAP assert(!this_k->is_initialized(), "we cannot initialize twice"); if (log_is_enabled(Info, classinit)) { ResourceMark rm; - outputStream* log = LogHandle(classinit)::info_stream(); + outputStream* log = Log(classinit)::info_stream(); log->print("%d Initializing ", call_class_initializer_impl_counter++); this_k->name()->print_value_on(log); log->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this_k())); @@ -3010,11 +3011,11 @@ void InstanceKlass::print_loading_log(LogLevel::type type, assert(type == LogLevel::Info || type == LogLevel::Debug, "sanity"); if (type == LogLevel::Info) { - log = LogHandle(classload)::info_stream(); + log = Log(classload)::info_stream(); } else { assert(type == LogLevel::Debug, "print_loading_log supports only Debug and Info levels"); - log = LogHandle(classload)::debug_stream(); + log = Log(classload)::debug_stream(); } // Name and class hierarchy info diff --git a/hotspot/src/share/vm/oops/instanceKlass.inline.hpp b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp index bff6f19bb2c..3fe04808df4 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.inline.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,16 +36,9 @@ // The iteration over the oops in objects is a hot path in the GC code. // By force inlining the following functions, we get similar GC performance // as the previous macro based implementation. -#ifdef TARGET_COMPILER_visCPP -#define INLINE __forceinline -#elif defined(TARGET_COMPILER_sparcWorks) -#define INLINE __attribute__((always_inline)) -#else -#define INLINE inline -#endif template -INLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) { T* p = (T*)obj->obj_field_addr(map->offset()); T* const end = p + map->count(); @@ -56,7 +49,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, Oo #if INCLUDE_ALL_GCS template -INLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) { T* const start = (T*)obj->obj_field_addr(map->offset()); T* p = start + map->count(); @@ -68,7 +61,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop #endif template -INLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) { T* p = (T*)obj->obj_field_addr(map->offset()); T* end = p + map->count(); @@ -91,7 +84,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop } template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) { OopMapBlock* map = start_of_nonstatic_oop_maps(); OopMapBlock* const end_map = map + nonstatic_oop_map_count(); @@ -102,7 +95,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClos #if INCLUDE_ALL_GCS template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) { OopMapBlock* const start_map = start_of_nonstatic_oop_maps(); OopMapBlock* map = start_map + nonstatic_oop_map_count(); @@ -114,7 +107,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, #endif template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) { OopMapBlock* map = start_of_nonstatic_oop_maps(); OopMapBlock* const end_map = map + nonstatic_oop_map_count(); @@ -124,7 +117,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, } template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) { if (UseCompressedOops) { oop_oop_iterate_oop_maps_specialized(obj, closure); } else { @@ -134,7 +127,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* clo #if INCLUDE_ALL_GCS template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) { if (UseCompressedOops) { oop_oop_iterate_oop_maps_specialized_reverse(obj, closure); } else { @@ -144,7 +137,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureT #endif template -INLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) { +ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) { if (UseCompressedOops) { oop_oop_iterate_oop_maps_specialized_bounded(obj, closure, mr); } else { @@ -153,7 +146,7 @@ INLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureT } template -INLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { +ALWAYSINLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { if (Devirtualizer::do_metadata(closure)) { Devirtualizer::do_klass(closure, this); } @@ -165,7 +158,7 @@ INLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { #if INCLUDE_ALL_GCS template -INLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { +ALWAYSINLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { assert(!Devirtualizer::do_metadata(closure), "Code to handle metadata is not implemented"); @@ -176,7 +169,7 @@ INLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closu #endif template -INLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { +ALWAYSINLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { if (Devirtualizer::do_metadata(closure)) { if (mr.contains(obj)) { Devirtualizer::do_klass(closure, this); @@ -188,8 +181,6 @@ INLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closu return size_helper(); } -#undef INLINE - #define ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ OOP_OOP_ITERATE_DEFN( InstanceKlass, OopClosureType, nv_suffix) \ OOP_OOP_ITERATE_DEFN_BOUNDED( InstanceKlass, OopClosureType, nv_suffix) \ diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index 8dc309dbee2..f396838ef9a 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,8 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/specialized_oop_closures.hpp" #include "oops/instanceRefKlass.inline.hpp" #include "oops/oop.inline.hpp" -#include "utilities/macros.hpp" -#include "utilities/preserveException.hpp" void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent @@ -87,48 +82,3 @@ void InstanceRefKlass::oop_verify_on(oop obj, outputStream* st) { guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed"); } } - -bool InstanceRefKlass::owns_pending_list_lock(JavaThread* thread) { - if (java_lang_ref_Reference::pending_list_lock() == NULL) return false; - Handle h_lock(thread, java_lang_ref_Reference::pending_list_lock()); - return ObjectSynchronizer::current_thread_holds_lock(thread, h_lock); -} - -void InstanceRefKlass::acquire_pending_list_lock(BasicLock *pending_list_basic_lock) { - // we may enter this with pending exception set - PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument - - // Create a HandleMark in case we retry a GC multiple times. - // Each time we attempt the GC, we allocate the handle below - // to hold the pending list lock. We want to free this handle. - HandleMark hm; - - Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock()); - ObjectSynchronizer::fast_enter(h_lock, pending_list_basic_lock, false, THREAD); - assert(ObjectSynchronizer::current_thread_holds_lock( - JavaThread::current(), h_lock), - "Locking should have succeeded"); - if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION; -} - -void InstanceRefKlass::release_and_notify_pending_list_lock( - BasicLock *pending_list_basic_lock) { - // we may enter this with pending exception set - PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument - - // Create a HandleMark in case we retry a GC multiple times. - // Each time we attempt the GC, we allocate the handle below - // to hold the pending list lock. We want to free this handle. - HandleMark hm; - - Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock()); - assert(ObjectSynchronizer::current_thread_holds_lock( - JavaThread::current(), h_lock), - "Lock should be held"); - // Notify waiters on pending lists lock if there is any reference. - if (java_lang_ref_Reference::pending_list() != NULL) { - ObjectSynchronizer::notifyall(h_lock, THREAD); - } - ObjectSynchronizer::fast_exit(h_lock(), pending_list_basic_lock, THREAD); - if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION; -} diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.hpp b/hotspot/src/share/vm/oops/instanceRefKlass.hpp index 4de86a4c7ff..2d072c24dcf 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp @@ -118,10 +118,6 @@ private: ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS) #endif // INCLUDE_ALL_GCS - static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock); - static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock); - static bool owns_pending_list_lock(JavaThread* thread); - // Update non-static oop maps so 'referent', 'nextPending' and // 'discovered' will look like non-oops static void update_nonstatic_oop_maps(Klass* k); diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 13e6fbadfa9..af4bde9b751 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -274,7 +274,7 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) { if (log_develop_is_enabled(Trace, vtables)) { ResourceMark rm(THREAD); - outputStream* logst = LogHandle(vtables)::trace_stream(); + outputStream* logst = Log(vtables)::trace_stream(); char* sig = target_method()->name_and_sig_as_C_string(); logst->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", supersuperklass->internal_name(), @@ -305,7 +305,7 @@ static void log_vtables(int i, bool overrides, methodHandle target_method, #ifndef PRODUCT if (log_develop_is_enabled(Trace, vtables)) { ResourceMark rm(thread); - outputStream* logst = LogHandle(vtables)::trace_stream(); + outputStream* logst = Log(vtables)::trace_stream(); char* sig = target_method()->name_and_sig_as_C_string(); if (overrides) { logst->print("overriding with %s::%s index %d, original flags: ", @@ -493,7 +493,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar void klassVtable::put_method_at(Method* m, int index) { if (log_develop_is_enabled(Trace, vtables)) { ResourceMark rm; - outputStream* logst = LogHandle(vtables)::trace_stream(); + outputStream* logst = Log(vtables)::trace_stream(); const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : ""; logst->print("adding %s at index %d, flags: ", sig, index); if (m != NULL) { @@ -821,7 +821,7 @@ int klassVtable::fill_in_mirandas(int initialized) { if (log_develop_is_enabled(Trace, vtables)) { Method* meth = mirandas.at(i); ResourceMark rm(Thread::current()); - outputStream* logst = LogHandle(vtables)::trace_stream(); + outputStream* logst = Log(vtables)::trace_stream(); if (meth != NULL) { char* sig = meth->name_and_sig_as_C_string(); logst->print("fill in mirandas with %s index %d, flags: ", @@ -1045,7 +1045,7 @@ int klassItable::assign_itable_indices_for_interface(Klass* klass) { // If m is already assigned a vtable index, do not disturb it. if (log_develop_is_enabled(Trace, itables)) { ResourceMark rm; - outputStream* logst = LogHandle(itables)::trace_stream(); + outputStream* logst = Log(itables)::trace_stream(); assert(m != NULL, "methods can never be null"); const char* sig = m->name_and_sig_as_C_string(); if (m->has_vtable_index()) { @@ -1161,7 +1161,7 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass if (log_develop_is_enabled(Trace, itables)) { ResourceMark rm(THREAD); if (target() != NULL) { - outputStream* logst = LogHandle(itables)::trace_stream(); + outputStream* logst = Log(itables)::trace_stream(); char* sig = target()->name_and_sig_as_C_string(); logst->print("interface: %s, ime_num: %d, target: %s, method_holder: %s ", interf_h()->internal_name(), ime_num, sig, diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 0b41252b558..efaaaa5009a 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -30,6 +30,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/generation.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeTracer.hpp" #include "interpreter/bytecodes.hpp" @@ -38,6 +39,7 @@ #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/constMethod.hpp" #include "oops/method.hpp" #include "oops/methodData.hpp" @@ -374,7 +376,7 @@ void Method::build_interpreter_method_data(const methodHandle& method, TRAPS) { // Do not profile method if current thread holds the pending list lock, // which avoids deadlock for acquiring the MethodData_lock. - if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { + if (ReferencePendingListLocker::is_locked_by_self()) { return; } diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 8fc7b133a16..732de6cdba3 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -264,6 +264,7 @@ class Method : public Metadata { int highest_osr_comp_level() const; void set_highest_osr_comp_level(int level); +#if defined(COMPILER2) || INCLUDE_JVMCI // Count of times method was exited via exception while interpreting void interpreter_throwout_increment(TRAPS) { MethodCounters* mcs = get_method_counters(CHECK); @@ -271,6 +272,7 @@ class Method : public Metadata { mcs->interpreter_throwout_increment(); } } +#endif int interpreter_throwout_count() const { MethodCounters* mcs = method_counters(); @@ -407,11 +409,13 @@ class Method : public Metadata { return (mcs == NULL) ? 0 : mcs->interpreter_invocation_count(); } } +#if defined(COMPILER2) || INCLUDE_JVMCI int increment_interpreter_invocation_count(TRAPS) { if (TieredCompilation) ShouldNotReachHere(); MethodCounters* mcs = get_method_counters(CHECK_0); return (mcs == NULL) ? 0 : mcs->increment_interpreter_invocation_count(); } +#endif #ifndef PRODUCT int compiled_invocation_count() const { return _compiled_invocation_count; } diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp index b52bff3104a..a0b96b6ba8b 100644 --- a/hotspot/src/share/vm/oops/methodCounters.hpp +++ b/hotspot/src/share/vm/oops/methodCounters.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,10 @@ class MethodCounters: public MetaspaceObj { friend class VMStructs; friend class JVMCIVMStructs; private: +#if defined(COMPILER2) || INCLUDE_JVMCI int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting +#endif u2 _number_of_breakpoints; // fullspeed debugging support InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequencey-based optimizations @@ -60,9 +62,7 @@ class MethodCounters: public MetaspaceObj { u1 _highest_osr_comp_level; // Same for OSR level #endif - MethodCounters(methodHandle mh) : _interpreter_invocation_count(0), - _interpreter_throwout_count(0), - _number_of_breakpoints(0), + MethodCounters(methodHandle mh) : _number_of_breakpoints(0), _nmethod_age(INT_MAX) #ifdef TIERED , _rate(0), @@ -71,6 +71,8 @@ class MethodCounters: public MetaspaceObj { _highest_osr_comp_level(0) #endif { + set_interpreter_invocation_count(0); + set_interpreter_throwout_count(0); invocation_counter()->init(); backedge_counter()->init(); @@ -109,6 +111,8 @@ class MethodCounters: public MetaspaceObj { void clear_counters(); +#if defined(COMPILER2) || INCLUDE_JVMCI + int interpreter_invocation_count() { return _interpreter_invocation_count; } @@ -131,6 +135,24 @@ class MethodCounters: public MetaspaceObj { _interpreter_throwout_count = count; } +#else // defined(COMPILER2) || INCLUDE_JVMCI + + int interpreter_invocation_count() { + return 0; + } + void set_interpreter_invocation_count(int count) { + assert(count == 0, "count must be 0"); + } + + int interpreter_throwout_count() const { + return 0; + } + void set_interpreter_throwout_count(int count) { + assert(count == 0, "count must be 0"); + } + +#endif // defined(COMPILER2) || INCLUDE_JVMCI + u2 number_of_breakpoints() const { return _number_of_breakpoints; } void incr_number_of_breakpoints() { ++_number_of_breakpoints; } void decr_number_of_breakpoints() { --_number_of_breakpoints; } @@ -170,10 +192,25 @@ class MethodCounters: public MetaspaceObj { return byte_offset_of(MethodCounters, _nmethod_age); } +#if defined(COMPILER2) || INCLUDE_JVMCI + static ByteSize interpreter_invocation_counter_offset() { return byte_offset_of(MethodCounters, _interpreter_invocation_count); } + static int interpreter_invocation_counter_offset_in_bytes() { + return offset_of(MethodCounters, _interpreter_invocation_count); + } + +#else // defined(COMPILER2) || INCLUDE_JVMCI + + static ByteSize interpreter_invocation_counter_offset() { + ShouldNotReachHere(); + return in_ByteSize(0); + } + +#endif // defined(COMPILER2) || INCLUDE_JVMCI + static ByteSize invocation_counter_offset() { return byte_offset_of(MethodCounters, _invocation_counter); } @@ -182,10 +219,6 @@ class MethodCounters: public MetaspaceObj { return byte_offset_of(MethodCounters, _backedge_counter); } - static int interpreter_invocation_counter_offset_in_bytes() { - return offset_of(MethodCounters, _interpreter_invocation_count); - } - static ByteSize interpreter_invocation_limit_offset() { return byte_offset_of(MethodCounters, _interpreter_invocation_limit); } diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 319787a189a..d5f5d6ad454 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -29,6 +29,7 @@ #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" #include "memory/heapInspection.hpp" +#include "memory/resourceArea.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/arguments.hpp" diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 8750ac73736..7f090471741 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -461,8 +461,6 @@ void ObjArrayKlass::oop_print_on(oop obj, outputStream* st) { #endif //PRODUCT -static int max_objArray_print_length = 4; - void ObjArrayKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_objArray(), "must be objArray"); st->print("a "); @@ -470,16 +468,6 @@ void ObjArrayKlass::oop_print_value_on(oop obj, outputStream* st) { int len = objArrayOop(obj)->length(); st->print("[%d] ", len); obj->print_address_on(st); - if (NOT_PRODUCT(PrintOopAddress ||) PrintMiscellaneous && (WizardMode || Verbose)) { - st->print("{"); - for (int i = 0; i < len; i++) { - if (i > max_objArray_print_length) { - st->print("..."); break; - } - st->print(" " INTPTR_FORMAT, (intptr_t)(void*)objArrayOop(obj)->obj_at(i)); - } - st->print(" }"); - } } const char* ObjArrayKlass::internal_name() const { diff --git a/hotspot/src/share/vm/oops/oop.cpp b/hotspot/src/share/vm/oops/oop.cpp index 18d1f227b48..48e7c337abe 100644 --- a/hotspot/src/share/vm/oops/oop.cpp +++ b/hotspot/src/share/vm/oops/oop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" #include "classfile/javaClasses.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "runtime/handles.inline.hpp" @@ -44,9 +45,8 @@ void oopDesc::print_on(outputStream* st) const { } void oopDesc::print_address_on(outputStream* st) const { - if (PrintOopAddress) { - st->print("{" INTPTR_FORMAT "}", p2i(this)); - } + st->print("{" INTPTR_FORMAT "}", p2i(this)); + } void oopDesc::print() { print_on(tty); } @@ -76,7 +76,7 @@ void oopDesc::print_value_on(outputStream* st) const { st->print("NULL"); } else if (java_lang_String::is_instance(obj)) { java_lang_String::print(obj, st); - if (PrintOopAddress) print_address_on(st); + print_address_on(st); } else { klass()->oop_print_value_on(obj, st); } diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index e33af9f4f31..2dbd3e4b894 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "compiler/compilerDirectives.hpp" #include "opto/block.hpp" #include "opto/cfgnode.hpp" diff --git a/hotspot/src/share/vm/opto/buildOopMap.cpp b/hotspot/src/share/vm/opto/buildOopMap.cpp index 6c8981b2fe8..2a90980a812 100644 --- a/hotspot/src/share/vm/opto/buildOopMap.cpp +++ b/hotspot/src/share/vm/opto/buildOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/compile.hpp" diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 9507ca64dc8..ca02fd2cc8e 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -194,6 +194,9 @@ "Map number of unrolls for main loop via " \ "Superword Level Parallelism analysis") \ \ + product_pd(bool, PostLoopMultiversioning, \ + "Multi versioned post loops to eliminate range checks") \ + \ notproduct(bool, TraceSuperWordLoopUnrollAnalysis, false, \ "Trace what Superword Level Parallelism analysis applies") \ \ @@ -229,21 +232,12 @@ develop(bool, TraceLoopOpts, false, \ "Trace executed loop optimizations") \ \ - diagnostic(bool, LoopLimitCheck, true, \ - "Generate a loop limits check for overflow") \ - \ develop(bool, TraceLoopLimitCheck, false, \ "Trace generation of loop limits checks") \ \ - diagnostic(bool, RangeLimitCheck, true, \ - "Additional overflow checks during range check elimination") \ - \ develop(bool, TraceRangeLimitCheck, false, \ "Trace additional overflow checks in RCE") \ \ - diagnostic(bool, UnrollLimitCheck, true, \ - "Additional overflow checks during loop unroll") \ - \ /* OptimizeFill not yet supported on PowerPC. */ \ product(bool, OptimizeFill, true PPC64_ONLY(&& false), \ "convert fill/copy loops into intrinsic") \ @@ -595,26 +589,26 @@ product(bool, BlockLayoutRotateLoops, true, \ "Allow back branches to be fall throughs in the block layour") \ \ - diagnostic(bool, InlineReflectionGetCallerClass, true, \ + develop(bool, InlineReflectionGetCallerClass, true, \ "inline sun.reflect.Reflection.getCallerClass(), known to be " \ "part of base library DLL") \ \ - diagnostic(bool, InlineObjectCopy, true, \ + develop(bool, InlineObjectCopy, true, \ "inline Object.clone and Arrays.copyOf[Range] intrinsics") \ \ - diagnostic(bool, SpecialStringCompareTo, true, \ + develop(bool, SpecialStringCompareTo, true, \ "special version of string compareTo") \ \ - diagnostic(bool, SpecialStringIndexOf, true, \ + develop(bool, SpecialStringIndexOf, true, \ "special version of string indexOf") \ \ - diagnostic(bool, SpecialStringEquals, true, \ + develop(bool, SpecialStringEquals, true, \ "special version of string equals") \ \ - diagnostic(bool, SpecialArraysEquals, true, \ + develop(bool, SpecialArraysEquals, true, \ "special version of Arrays.equals(char[],char[])") \ \ - diagnostic(bool, SpecialEncodeISOArray, true, \ + product(bool, SpecialEncodeISOArray, true, \ "special version of ISO_8859_1$Encoder.encodeISOArray") \ \ develop(bool, BailoutToInterpreterForThrows, false, \ @@ -716,22 +710,22 @@ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ \ - diagnostic(bool, UseMathExactIntrinsics, true, \ + product(bool, UseMathExactIntrinsics, true, \ "Enables intrinsification of various java.lang.Math functions") \ \ - diagnostic(bool, UseMultiplyToLenIntrinsic, false, \ + product(bool, UseMultiplyToLenIntrinsic, false, \ "Enables intrinsification of BigInteger.multiplyToLen()") \ \ - diagnostic(bool, UseSquareToLenIntrinsic, false, \ + product(bool, UseSquareToLenIntrinsic, false, \ "Enables intrinsification of BigInteger.squareToLen()") \ \ - diagnostic(bool, UseMulAddIntrinsic, false, \ + product(bool, UseMulAddIntrinsic, false, \ "Enables intrinsification of BigInteger.mulAdd()") \ \ - diagnostic(bool, UseMontgomeryMultiplyIntrinsic, false, \ + product(bool, UseMontgomeryMultiplyIntrinsic, false, \ "Enables intrinsification of BigInteger.montgomeryMultiply()") \ \ - diagnostic(bool, UseMontgomerySquareIntrinsic, false, \ + product(bool, UseMontgomerySquareIntrinsic, false, \ "Enables intrinsification of BigInteger.montgomerySquare()") \ \ product(bool, UseTypeSpeculation, true, \ diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index c0bad767d0c..25e34e57738 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 3a9e0c03a6e..f50d4d42a8a 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "compiler/compileLog.hpp" #include "compiler/oopMap.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index ec737694e53..cd212ea015c 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "compiler/compileLog.hpp" #include "compiler/disassembler.hpp" #include "compiler/oopMap.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/c2compiler.hpp" diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 343574e68f3..7076f4a68ef 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -39,6 +39,7 @@ #include "opto/phase.hpp" #include "opto/regmask.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vmThread.hpp" #include "trace/tracing.hpp" #include "utilities/ticks.hpp" diff --git a/hotspot/src/share/vm/opto/domgraph.cpp b/hotspot/src/share/vm/opto/domgraph.cpp index c285738ac6b..7af4d07264f 100644 --- a/hotspot/src/share/vm/opto/domgraph.cpp +++ b/hotspot/src/share/vm/opto/domgraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "opto/block.hpp" #include "opto/machnode.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index d2641d2acca..15ece3072b0 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "compiler/compileLog.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "opto/c2compiler.hpp" #include "opto/arraycopynode.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 48376b2f57a..8df50abb23d 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/block.hpp" #include "opto/c2compiler.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index 48166b491fc..c8b045d75f0 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 73f7c3e1254..a9f1cd10f29 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTableModRefBS.hpp" #include "gc/shared/collectedHeap.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" #include "opto/convertnode.hpp" @@ -1190,11 +1191,6 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, bool speculative) { assert(!assert_null || null_control == NULL, "not both at once"); if (stopped()) return top(); - if (!GenerateCompilerNullChecks && !assert_null && null_control == NULL) { - // For some performance testing, we may wish to suppress null checking. - value = cast_not_null(value); // Make it appear to be non-null (4962416). - return value; - } NOT_PRODUCT(explicit_null_checks_inserted++); // Construct NULL check @@ -1686,6 +1682,9 @@ Node* GraphKit::load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAr const Type* elemtype = arytype->elem(); BasicType elembt = elemtype->array_element_basic_type(); Node* adr = array_element_address(ary, idx, elembt, arytype->size()); + if (elembt == T_NARROWOOP) { + elembt = T_OBJECT; // To satisfy switch in LoadNode::make() + } Node* ld = make_load(ctl, adr, elemtype, elembt, arytype, MemNode::unordered); return ld; } @@ -3770,9 +3769,7 @@ void GraphKit::add_predicate(int nargs) { add_predicate_impl(Deoptimization::Reason_predicate, nargs); } // loop's limit check predicate should be near the loop. - if (LoopLimitCheck) { - add_predicate_impl(Deoptimization::Reason_loop_limit_check, nargs); - } + add_predicate_impl(Deoptimization::Reason_loop_limit_check, nargs); } //----------------------------- store barriers ---------------------------- diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 730b3a85733..0d5fbdda39c 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/resourceArea.hpp" #include "opto/chaitin.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index b8b823e9d57..96d81ad6ce9 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "compiler/oopMap.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index 9e315739008..169146a607e 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "ci/ciTypeFlow.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index a31760c8ea9..13d153ce70d 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -28,6 +28,7 @@ #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" @@ -6272,7 +6273,20 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { +#ifdef PPC64 + // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. + // Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. + // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. + // The ppc64 stubs of encryption and decryption use the same round keys (sessionK[0]). + Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I", /*is_exact*/ false); + assert (objSessionK != NULL, "wrong version of com.sun.crypto.provider.AESCrypt"); + if (objSessionK == NULL) { + return (Node *) NULL; + } + Node* objAESCryptKey = load_array_element(control(), objSessionK, intcon(0), TypeAryPtr::OOPS); +#else Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false); +#endif // PPC64 assert (objAESCryptKey != NULL, "wrong version of com.sun.crypto.provider.AESCrypt"); if (objAESCryptKey == NULL) return (Node *) NULL; diff --git a/hotspot/src/share/vm/opto/live.cpp b/hotspot/src/share/vm/opto/live.cpp index 633a00ca82c..e730a117d0b 100644 --- a/hotspot/src/share/vm/opto/live.cpp +++ b/hotspot/src/share/vm/opto/live.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/callnode.hpp" #include "opto/chaitin.hpp" #include "opto/live.hpp" diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 56d21451ef8..7f10a7d980a 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -313,11 +313,9 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, // Search original predicates Node* entry = old_entry; ProjNode* limit_check_proj = NULL; - if (LoopLimitCheck) { - limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); - if (limit_check_proj != NULL) { - entry = entry->in(0)->in(0); - } + limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); + if (limit_check_proj != NULL) { + entry = entry->in(0)->in(0); } if (UseLoopPredicate) { ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); @@ -353,11 +351,9 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, // Skip related predicates. Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) { Node* predicate = NULL; - if (LoopLimitCheck) { - predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); - if (predicate != NULL) { - entry = entry->in(0)->in(0); - } + predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); + if (predicate != NULL) { + entry = entry->in(0)->in(0); } if (UseLoopPredicate) { predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); @@ -393,11 +389,9 @@ ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimi // Find a predicate Node* PhaseIdealLoop::find_predicate(Node* entry) { Node* predicate = NULL; - if (LoopLimitCheck) { - predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); - if (predicate != NULL) { // right pattern that can be used by loop predication - return entry; - } + predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); + if (predicate != NULL) { // right pattern that can be used by loop predication + return entry; } if (UseLoopPredicate) { predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); @@ -646,19 +640,13 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl, Node* max_idx_expr = init; int stride_con = stride->get_int(); if ((stride_con > 0) == (scale > 0) == upper) { - if (LoopLimitCheck) { - // With LoopLimitCheck limit is not exact. - // Calculate exact limit here. - // Note, counted loop's test is '<' or '>'. - limit = exact_limit(loop); - max_idx_expr = new SubINode(limit, stride); - register_new_node(max_idx_expr, ctrl); - if (TraceLoopPredicate) predString->print("(limit - stride) "); - } else { - max_idx_expr = new SubINode(limit, stride); - register_new_node(max_idx_expr, ctrl); - if (TraceLoopPredicate) predString->print("(limit - stride) "); - } + // Limit is not exact. + // Calculate exact limit here. + // Note, counted loop's test is '<' or '>'. + limit = exact_limit(loop); + max_idx_expr = new SubINode(limit, stride); + register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) predString->print("(limit - stride) "); } else { if (TraceLoopPredicate) predString->print("init "); } @@ -721,12 +709,9 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { Node* entry = head->in(LoopNode::EntryControl); ProjNode *predicate_proj = NULL; // Loop limit check predicate should be near the loop. - if (LoopLimitCheck) { - predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); - if (predicate_proj != NULL) - entry = predicate_proj->in(0)->in(0); - } - + predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); + if (predicate_proj != NULL) + entry = predicate_proj->in(0)->in(0); predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); if (!predicate_proj) { #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index d819e69059e..f2bf2eff8da 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -1027,82 +1027,9 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ _igvn.replace_input_of(bol, 1, cmp); } - //------------------------------ - // Step A: Create Post-Loop. - Node* main_exit = main_end->proj_out(false); - assert( main_exit->Opcode() == Op_IfFalse, "" ); - int dd_main_exit = dom_depth(main_exit); - - // Step A1: Clone the loop body. The clone becomes the post-loop. The main - // loop pre-header illegally has 2 control users (old & new loops). - clone_loop( loop, old_new, dd_main_exit ); - assert( old_new[main_end ->_idx]->Opcode() == Op_CountedLoopEnd, "" ); - CountedLoopNode *post_head = old_new[main_head->_idx]->as_CountedLoop(); - post_head->set_post_loop(main_head); - - // Reduce the post-loop trip count. - CountedLoopEndNode* post_end = old_new[main_end ->_idx]->as_CountedLoopEnd(); - post_end->_prob = PROB_FAIR; - - // Build the main-loop normal exit. - IfFalseNode *new_main_exit = new IfFalseNode(main_end); - _igvn.register_new_node_with_optimizer( new_main_exit ); - set_idom(new_main_exit, main_end, dd_main_exit ); - set_loop(new_main_exit, loop->_parent); - - // Step A2: Build a zero-trip guard for the post-loop. After leaving the - // main-loop, the post-loop may not execute at all. We 'opaque' the incr - // (the main-loop trip-counter exit value) because we will be changing - // the exit value (via unrolling) so we cannot constant-fold away the zero - // trip guard until all unrolling is done. - Node *zer_opaq = new Opaque1Node(C, incr); - Node *zer_cmp = new CmpINode( zer_opaq, limit ); - Node *zer_bol = new BoolNode( zer_cmp, b_test ); - register_new_node( zer_opaq, new_main_exit ); - register_new_node( zer_cmp , new_main_exit ); - register_new_node( zer_bol , new_main_exit ); - - // Build the IfNode - IfNode *zer_iff = new IfNode( new_main_exit, zer_bol, PROB_FAIR, COUNT_UNKNOWN ); - _igvn.register_new_node_with_optimizer( zer_iff ); - set_idom(zer_iff, new_main_exit, dd_main_exit); - set_loop(zer_iff, loop->_parent); - - // Plug in the false-path, taken if we need to skip post-loop - _igvn.replace_input_of(main_exit, 0, zer_iff); - set_idom(main_exit, zer_iff, dd_main_exit); - set_idom(main_exit->unique_out(), zer_iff, dd_main_exit); - // Make the true-path, must enter the post loop - Node *zer_taken = new IfTrueNode( zer_iff ); - _igvn.register_new_node_with_optimizer( zer_taken ); - set_idom(zer_taken, zer_iff, dd_main_exit); - set_loop(zer_taken, loop->_parent); - // Plug in the true path - _igvn.hash_delete( post_head ); - post_head->set_req(LoopNode::EntryControl, zer_taken); - set_idom(post_head, zer_taken, dd_main_exit); - - Arena *a = Thread::current()->resource_area(); - VectorSet visited(a); - Node_Stack clones(a, main_head->back_control()->outcnt()); - // Step A3: Make the fall-in values to the post-loop come from the - // fall-out values of the main-loop. - for (DUIterator_Fast imax, i = main_head->fast_outs(imax); i < imax; i++) { - Node* main_phi = main_head->fast_out(i); - if( main_phi->is_Phi() && main_phi->in(0) == main_head && main_phi->outcnt() >0 ) { - Node *post_phi = old_new[main_phi->_idx]; - Node *fallmain = clone_up_backedge_goo(main_head->back_control(), - post_head->init_control(), - main_phi->in(LoopNode::LoopBackControl), - visited, clones); - _igvn.hash_delete(post_phi); - post_phi->set_req( LoopNode::EntryControl, fallmain ); - } - } - - // Update local caches for next stanza - main_exit = new_main_exit; - + // Add the post loop + CountedLoopNode *post_head = NULL; + Node *main_exit = insert_post_loop(loop, old_new, main_head, main_end, incr, limit, post_head); //------------------------------ // Step B: Create Pre-Loop. @@ -1158,8 +1085,9 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ main_head->set_req(LoopNode::EntryControl, min_taken); set_idom(main_head, min_taken, dd_main_head); - visited.Clear(); - clones.clear(); + Arena *a = Thread::current()->resource_area(); + VectorSet visited(a); + Node_Stack clones(a, main_head->back_control()->outcnt()); // Step B3: Make the fall-in values to the main-loop come from the // fall-out values of the pre-loop. for (DUIterator_Fast i2max, i2 = main_head->fast_outs(i2max); i2 < i2max; i2++) { @@ -1185,12 +1113,8 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ // variable value and the induction variable Phi to preserve correct // dependencies. - // CastII for the post loop: - bool inserted = cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head); - assert(inserted, "no castII inserted"); - // CastII for the main loop: - inserted = cast_incr_before_loop(pre_incr, min_taken, main_head); + bool inserted = cast_incr_before_loop( pre_incr, min_taken, main_head ); assert(inserted, "no castII inserted"); // Step B4: Shorten the pre-loop to run only 1 iteration (for now). @@ -1298,19 +1222,82 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old guarantee(main_end != NULL, "no loop exit node"); // diagnostic to show loop end is not properly formed assert(main_end->outcnt() == 2, "1 true, 1 false path only"); - uint dd_main_head = dom_depth(main_head); - uint max = main_head->outcnt(); // mark this loop as processed main_head->mark_has_atomic_post_loop(); - Node *pre_header = main_head->in(LoopNode::EntryControl); - Node *init = main_head->init_trip(); Node *incr = main_end->incr(); Node *limit = main_end->limit(); - Node *stride = main_end->stride(); - Node *cmp = main_end->cmp_node(); - BoolTest::mask b_test = main_end->test_trip(); + + // In this case we throw away the result as we are not using it to connect anything else. + CountedLoopNode *post_head = NULL; + insert_post_loop(loop, old_new, main_head, main_end, incr, limit, post_head); + + // It's difficult to be precise about the trip-counts + // for post loops. They are usually very short, + // so guess that unit vector trips is a reasonable value. + post_head->set_profile_trip_cnt(cur_unroll); + + // Now force out all loop-invariant dominating tests. The optimizer + // finds some, but we _know_ they are all useless. + peeled_dom_test_elim(loop, old_new); + loop->record_for_igvn(); +} + + +//-------------------------insert_scalar_rced_post_loop------------------------ +// Insert a copy of the rce'd main loop as a post loop, +// We have not unrolled the main loop, so this is the right time to inject this. +// Later we will examine the partner of this post loop pair which still has range checks +// to see inject code which tests at runtime if the range checks are applicable. +void PhaseIdealLoop::insert_scalar_rced_post_loop(IdealLoopTree *loop, Node_List &old_new) { + if (!loop->_head->is_CountedLoop()) return; + + CountedLoopNode *cl = loop->_head->as_CountedLoop(); + + // only process RCE'd main loops + if (!cl->is_main_loop() || cl->range_checks_present()) return; + +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("PostScalarRce "); + loop->dump_head(); + } +#endif + C->set_major_progress(); + + // Find common pieces of the loop being guarded with pre & post loops + CountedLoopNode *main_head = loop->_head->as_CountedLoop(); + CountedLoopEndNode *main_end = main_head->loopexit(); + guarantee(main_end != NULL, "no loop exit node"); + // diagnostic to show loop end is not properly formed + assert(main_end->outcnt() == 2, "1 true, 1 false path only"); + + Node *incr = main_end->incr(); + Node *limit = main_end->limit(); + + // In this case we throw away the result as we are not using it to connect anything else. + CountedLoopNode *post_head = NULL; + insert_post_loop(loop, old_new, main_head, main_end, incr, limit, post_head); + + // It's difficult to be precise about the trip-counts + // for post loops. They are usually very short, + // so guess that unit vector trips is a reasonable value. + post_head->set_profile_trip_cnt(4.0); + post_head->set_is_rce_post_loop(); + + // Now force out all loop-invariant dominating tests. The optimizer + // finds some, but we _know_ they are all useless. + peeled_dom_test_elim(loop, old_new); + loop->record_for_igvn(); +} + + +//------------------------------insert_post_loop------------------------------- +// Insert post loops. Add a post loop to the given loop passed. +Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree *loop, Node_List &old_new, + CountedLoopNode *main_head, CountedLoopEndNode *main_end, + Node *incr, Node *limit, CountedLoopNode *&post_head) { //------------------------------ // Step A: Create a new post-Loop. @@ -1322,7 +1309,7 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old // The main loop pre-header illegally has 2 control users (old & new loops). clone_loop(loop, old_new, dd_main_exit); assert(old_new[main_end->_idx]->Opcode() == Op_CountedLoopEnd, ""); - CountedLoopNode *post_head = old_new[main_head->_idx]->as_CountedLoop(); + post_head = old_new[main_head->_idx]->as_CountedLoop(); post_head->set_normal_loop(); post_head->set_post_loop(main_head); @@ -1336,14 +1323,14 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old set_idom(new_main_exit, main_end, dd_main_exit); set_loop(new_main_exit, loop->_parent); - // Step A2: Build a zero-trip guard for the vector post-loop. After leaving the - // main-loop, the vector post-loop may not execute at all. We 'opaque' the incr - // (the vectorized main-loop trip-counter exit value) because we will be changing + // Step A2: Build a zero-trip guard for the post-loop. After leaving the + // main-loop, the post-loop may not execute at all. We 'opaque' the incr + // (the previous loop trip-counter exit value) because we will be changing // the exit value (via additional unrolling) so we cannot constant-fold away the zero // trip guard until all unrolling is done. Node *zer_opaq = new Opaque1Node(C, incr); Node *zer_cmp = new CmpINode(zer_opaq, limit); - Node *zer_bol = new BoolNode(zer_cmp, b_test); + Node *zer_bol = new BoolNode(zer_cmp, main_end->test_trip()); register_new_node(zer_opaq, new_main_exit); register_new_node(zer_cmp, new_main_exit); register_new_node(zer_bol, new_main_exit); @@ -1354,11 +1341,11 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old set_idom(zer_iff, new_main_exit, dd_main_exit); set_loop(zer_iff, loop->_parent); - // Plug in the false-path, taken if we need to skip vector post-loop + // Plug in the false-path, taken if we need to skip this post-loop _igvn.replace_input_of(main_exit, 0, zer_iff); set_idom(main_exit, zer_iff, dd_main_exit); set_idom(main_exit->unique_out(), zer_iff, dd_main_exit); - // Make the true-path, must enter the vector post loop + // Make the true-path, must enter this post loop Node *zer_taken = new IfTrueNode(zer_iff); _igvn.register_new_node_with_optimizer(zer_taken); set_idom(zer_taken, zer_iff, dd_main_exit); @@ -1371,7 +1358,7 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old Arena *a = Thread::current()->resource_area(); VectorSet visited(a); Node_Stack clones(a, main_head->back_control()->outcnt()); - // Step A3: Make the fall-in values to the vector post-loop come from the + // Step A3: Make the fall-in values to the post-loop come from the // fall-out values of the main-loop. for (DUIterator_Fast imax, i = main_head->fast_outs(imax); i < imax; i++) { Node* main_phi = main_head->fast_out(i); @@ -1390,15 +1377,7 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old bool inserted = cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head); assert(inserted, "no castII inserted"); - // It's difficult to be precise about the trip-counts - // for post loops. They are usually very short, - // so guess that unit vector trips is a reasonable value. - post_head->set_profile_trip_cnt((float)slp_max_unroll_factor); - - // Now force out all loop-invariant dominating tests. The optimizer - // finds some, but we _know_ they are all useless. - peeled_dom_test_elim(loop, old_new); - loop->record_for_igvn(); + return new_main_exit; } //------------------------------is_invariant----------------------------- @@ -1457,7 +1436,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad // Check the shape of the graph at the loop entry. If an inappropriate // graph shape is encountered, the compiler bails out loop unrolling; // compilation of the method will still succeed. - if (!is_canonical_main_loop_entry(loop_head)) { + if (!is_canonical_loop_entry(loop_head)) { return; } opaq = ctrl->in(0)->in(1)->in(1)->in(2); @@ -1468,209 +1447,156 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad C->set_major_progress(); Node* new_limit = NULL; - if (UnrollLimitCheck) { - int stride_con = stride->get_int(); - int stride_p = (stride_con > 0) ? stride_con : -stride_con; - uint old_trip_count = loop_head->trip_count(); - // Verify that unroll policy result is still valid. - assert(old_trip_count > 1 && - (!adjust_min_trip || stride_p <= (1<<3)*loop_head->unrolled_count()), "sanity"); + int stride_con = stride->get_int(); + int stride_p = (stride_con > 0) ? stride_con : -stride_con; + uint old_trip_count = loop_head->trip_count(); + // Verify that unroll policy result is still valid. + assert(old_trip_count > 1 && + (!adjust_min_trip || stride_p <= (1<<3)*loop_head->unrolled_count()), "sanity"); - // Adjust loop limit to keep valid iterations number after unroll. - // Use (limit - stride) instead of (((limit - init)/stride) & (-2))*stride - // which may overflow. - if (!adjust_min_trip) { - assert(old_trip_count > 1 && (old_trip_count & 1) == 0, - "odd trip count for maximally unroll"); - // Don't need to adjust limit for maximally unroll since trip count is even. - } else if (loop_head->has_exact_trip_count() && init->is_Con()) { - // Loop's limit is constant. Loop's init could be constant when pre-loop - // become peeled iteration. - jlong init_con = init->get_int(); - // We can keep old loop limit if iterations count stays the same: - // old_trip_count == new_trip_count * 2 - // Note: since old_trip_count >= 2 then new_trip_count >= 1 - // so we also don't need to adjust zero trip test. - jlong limit_con = limit->get_int(); - // (stride_con*2) not overflow since stride_con <= 8. - int new_stride_con = stride_con * 2; - int stride_m = new_stride_con - (stride_con > 0 ? 1 : -1); - jlong trip_count = (limit_con - init_con + stride_m)/new_stride_con; - // New trip count should satisfy next conditions. - assert(trip_count > 0 && (julong)trip_count < (julong)max_juint/2, "sanity"); - uint new_trip_count = (uint)trip_count; - adjust_min_trip = (old_trip_count != new_trip_count*2); - } + // Adjust loop limit to keep valid iterations number after unroll. + // Use (limit - stride) instead of (((limit - init)/stride) & (-2))*stride + // which may overflow. + if (!adjust_min_trip) { + assert(old_trip_count > 1 && (old_trip_count & 1) == 0, + "odd trip count for maximally unroll"); + // Don't need to adjust limit for maximally unroll since trip count is even. + } else if (loop_head->has_exact_trip_count() && init->is_Con()) { + // Loop's limit is constant. Loop's init could be constant when pre-loop + // become peeled iteration. + jlong init_con = init->get_int(); + // We can keep old loop limit if iterations count stays the same: + // old_trip_count == new_trip_count * 2 + // Note: since old_trip_count >= 2 then new_trip_count >= 1 + // so we also don't need to adjust zero trip test. + jlong limit_con = limit->get_int(); + // (stride_con*2) not overflow since stride_con <= 8. + int new_stride_con = stride_con * 2; + int stride_m = new_stride_con - (stride_con > 0 ? 1 : -1); + jlong trip_count = (limit_con - init_con + stride_m)/new_stride_con; + // New trip count should satisfy next conditions. + assert(trip_count > 0 && (julong)trip_count < (julong)max_juint/2, "sanity"); + uint new_trip_count = (uint)trip_count; + adjust_min_trip = (old_trip_count != new_trip_count*2); + } - if (adjust_min_trip) { - // Step 2: Adjust the trip limit if it is called for. - // The adjustment amount is -stride. Need to make sure if the - // adjustment underflows or overflows, then the main loop is skipped. - Node* cmp = loop_end->cmp_node(); - assert(cmp->in(2) == limit, "sanity"); - assert(opaq != NULL && opaq->in(1) == limit, "sanity"); + if (adjust_min_trip) { + // Step 2: Adjust the trip limit if it is called for. + // The adjustment amount is -stride. Need to make sure if the + // adjustment underflows or overflows, then the main loop is skipped. + Node* cmp = loop_end->cmp_node(); + assert(cmp->in(2) == limit, "sanity"); + assert(opaq != NULL && opaq->in(1) == limit, "sanity"); - // Verify that policy_unroll result is still valid. - const TypeInt* limit_type = _igvn.type(limit)->is_int(); - assert(stride_con > 0 && ((limit_type->_hi - stride_con) < limit_type->_hi) || - stride_con < 0 && ((limit_type->_lo - stride_con) > limit_type->_lo), "sanity"); + // Verify that policy_unroll result is still valid. + const TypeInt* limit_type = _igvn.type(limit)->is_int(); + assert(stride_con > 0 && ((limit_type->_hi - stride_con) < limit_type->_hi) || + stride_con < 0 && ((limit_type->_lo - stride_con) > limit_type->_lo), "sanity"); - if (limit->is_Con()) { - // The check in policy_unroll and the assert above guarantee - // no underflow if limit is constant. - new_limit = _igvn.intcon(limit->get_int() - stride_con); - set_ctrl(new_limit, C->root()); + if (limit->is_Con()) { + // The check in policy_unroll and the assert above guarantee + // no underflow if limit is constant. + new_limit = _igvn.intcon(limit->get_int() - stride_con); + set_ctrl(new_limit, C->root()); + } else { + // Limit is not constant. + if (loop_head->unrolled_count() == 1) { // only for first unroll + // Separate limit by Opaque node in case it is an incremented + // variable from previous loop to avoid using pre-incremented + // value which could increase register pressure. + // Otherwise reorg_offsets() optimization will create a separate + // Opaque node for each use of trip-counter and as result + // zero trip guard limit will be different from loop limit. + assert(has_ctrl(opaq), "should have it"); + Node* opaq_ctrl = get_ctrl(opaq); + limit = new Opaque2Node( C, limit ); + register_new_node( limit, opaq_ctrl ); + } + if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) || + stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) { + // No underflow. + new_limit = new SubINode(limit, stride); } else { - // Limit is not constant. - if (loop_head->unrolled_count() == 1) { // only for first unroll - // Separate limit by Opaque node in case it is an incremented - // variable from previous loop to avoid using pre-incremented - // value which could increase register pressure. - // Otherwise reorg_offsets() optimization will create a separate - // Opaque node for each use of trip-counter and as result - // zero trip guard limit will be different from loop limit. - assert(has_ctrl(opaq), "should have it"); - Node* opaq_ctrl = get_ctrl(opaq); - limit = new Opaque2Node( C, limit ); - register_new_node( limit, opaq_ctrl ); - } - if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) || - stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) { - // No underflow. - new_limit = new SubINode(limit, stride); + // (limit - stride) may underflow. + // Clamp the adjustment value with MININT or MAXINT: + // + // new_limit = limit-stride + // if (stride > 0) + // new_limit = (limit < new_limit) ? MININT : new_limit; + // else + // new_limit = (limit > new_limit) ? MAXINT : new_limit; + // + BoolTest::mask bt = loop_end->test_trip(); + assert(bt == BoolTest::lt || bt == BoolTest::gt, "canonical test is expected"); + Node* adj_max = _igvn.intcon((stride_con > 0) ? min_jint : max_jint); + set_ctrl(adj_max, C->root()); + Node* old_limit = NULL; + Node* adj_limit = NULL; + Node* bol = limit->is_CMove() ? limit->in(CMoveNode::Condition) : NULL; + if (loop_head->unrolled_count() > 1 && + limit->is_CMove() && limit->Opcode() == Op_CMoveI && + limit->in(CMoveNode::IfTrue) == adj_max && + bol->as_Bool()->_test._test == bt && + bol->in(1)->Opcode() == Op_CmpI && + bol->in(1)->in(2) == limit->in(CMoveNode::IfFalse)) { + // Loop was unrolled before. + // Optimize the limit to avoid nested CMove: + // use original limit as old limit. + old_limit = bol->in(1)->in(1); + // Adjust previous adjusted limit. + adj_limit = limit->in(CMoveNode::IfFalse); + adj_limit = new SubINode(adj_limit, stride); } else { - // (limit - stride) may underflow. - // Clamp the adjustment value with MININT or MAXINT: - // - // new_limit = limit-stride - // if (stride > 0) - // new_limit = (limit < new_limit) ? MININT : new_limit; - // else - // new_limit = (limit > new_limit) ? MAXINT : new_limit; - // - BoolTest::mask bt = loop_end->test_trip(); - assert(bt == BoolTest::lt || bt == BoolTest::gt, "canonical test is expected"); - Node* adj_max = _igvn.intcon((stride_con > 0) ? min_jint : max_jint); - set_ctrl(adj_max, C->root()); - Node* old_limit = NULL; - Node* adj_limit = NULL; - Node* bol = limit->is_CMove() ? limit->in(CMoveNode::Condition) : NULL; - if (loop_head->unrolled_count() > 1 && - limit->is_CMove() && limit->Opcode() == Op_CMoveI && - limit->in(CMoveNode::IfTrue) == adj_max && - bol->as_Bool()->_test._test == bt && - bol->in(1)->Opcode() == Op_CmpI && - bol->in(1)->in(2) == limit->in(CMoveNode::IfFalse)) { - // Loop was unrolled before. - // Optimize the limit to avoid nested CMove: - // use original limit as old limit. - old_limit = bol->in(1)->in(1); - // Adjust previous adjusted limit. - adj_limit = limit->in(CMoveNode::IfFalse); - adj_limit = new SubINode(adj_limit, stride); - } else { - old_limit = limit; - adj_limit = new SubINode(limit, stride); - } - assert(old_limit != NULL && adj_limit != NULL, ""); - register_new_node( adj_limit, ctrl ); // adjust amount - Node* adj_cmp = new CmpINode(old_limit, adj_limit); - register_new_node( adj_cmp, ctrl ); - Node* adj_bool = new BoolNode(adj_cmp, bt); - register_new_node( adj_bool, ctrl ); - new_limit = new CMoveINode(adj_bool, adj_limit, adj_max, TypeInt::INT); + old_limit = limit; + adj_limit = new SubINode(limit, stride); } - register_new_node(new_limit, ctrl); + assert(old_limit != NULL && adj_limit != NULL, ""); + register_new_node( adj_limit, ctrl ); // adjust amount + Node* adj_cmp = new CmpINode(old_limit, adj_limit); + register_new_node( adj_cmp, ctrl ); + Node* adj_bool = new BoolNode(adj_cmp, bt); + register_new_node( adj_bool, ctrl ); + new_limit = new CMoveINode(adj_bool, adj_limit, adj_max, TypeInt::INT); } - assert(new_limit != NULL, ""); - // Replace in loop test. - assert(loop_end->in(1)->in(1) == cmp, "sanity"); - if (cmp->outcnt() == 1 && loop_end->in(1)->outcnt() == 1) { - // Don't need to create new test since only one user. - _igvn.hash_delete(cmp); - cmp->set_req(2, new_limit); - } else { - // Create new test since it is shared. - Node* ctrl2 = loop_end->in(0); - Node* cmp2 = cmp->clone(); - cmp2->set_req(2, new_limit); - register_new_node(cmp2, ctrl2); - Node* bol2 = loop_end->in(1)->clone(); - bol2->set_req(1, cmp2); - register_new_node(bol2, ctrl2); - _igvn.replace_input_of(loop_end, 1, bol2); - } - // Step 3: Find the min-trip test guaranteed before a 'main' loop. - // Make it a 1-trip test (means at least 2 trips). - - // Guard test uses an 'opaque' node which is not shared. Hence I - // can edit it's inputs directly. Hammer in the new limit for the - // minimum-trip guard. - assert(opaq->outcnt() == 1, ""); - _igvn.replace_input_of(opaq, 1, new_limit); + register_new_node(new_limit, ctrl); + } + assert(new_limit != NULL, ""); + // Replace in loop test. + assert(loop_end->in(1)->in(1) == cmp, "sanity"); + if (cmp->outcnt() == 1 && loop_end->in(1)->outcnt() == 1) { + // Don't need to create new test since only one user. + _igvn.hash_delete(cmp); + cmp->set_req(2, new_limit); + } else { + // Create new test since it is shared. + Node* ctrl2 = loop_end->in(0); + Node* cmp2 = cmp->clone(); + cmp2->set_req(2, new_limit); + register_new_node(cmp2, ctrl2); + Node* bol2 = loop_end->in(1)->clone(); + bol2->set_req(1, cmp2); + register_new_node(bol2, ctrl2); + _igvn.replace_input_of(loop_end, 1, bol2); } - - // Adjust max trip count. The trip count is intentionally rounded - // down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll, - // the main, unrolled, part of the loop will never execute as it is protected - // by the min-trip test. See bug 4834191 for a case where we over-unrolled - // and later determined that part of the unrolled loop was dead. - loop_head->set_trip_count(old_trip_count / 2); - - // Double the count of original iterations in the unrolled loop body. - loop_head->double_unrolled_count(); - - } else { // LoopLimitCheck - - // Adjust max trip count. The trip count is intentionally rounded - // down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll, - // the main, unrolled, part of the loop will never execute as it is protected - // by the min-trip test. See bug 4834191 for a case where we over-unrolled - // and later determined that part of the unrolled loop was dead. - loop_head->set_trip_count(loop_head->trip_count() / 2); - - // Double the count of original iterations in the unrolled loop body. - loop_head->double_unrolled_count(); - - // ----------- - // Step 2: Cut back the trip counter for an unroll amount of 2. - // Loop will normally trip (limit - init)/stride_con. Since it's a - // CountedLoop this is exact (stride divides limit-init exactly). - // We are going to double the loop body, so we want to knock off any - // odd iteration: (trip_cnt & ~1). Then back compute a new limit. - Node *span = new SubINode( limit, init ); - register_new_node( span, ctrl ); - Node *trip = new DivINode( 0, span, stride ); - register_new_node( trip, ctrl ); - Node *mtwo = _igvn.intcon(-2); - set_ctrl(mtwo, C->root()); - Node *rond = new AndINode( trip, mtwo ); - register_new_node( rond, ctrl ); - Node *spn2 = new MulINode( rond, stride ); - register_new_node( spn2, ctrl ); - new_limit = new AddINode( spn2, init ); - register_new_node( new_limit, ctrl ); - - // Hammer in the new limit - Node *ctrl2 = loop_end->in(0); - Node *cmp2 = new CmpINode( loop_head->incr(), new_limit ); - register_new_node( cmp2, ctrl2 ); - Node *bol2 = new BoolNode( cmp2, loop_end->test_trip() ); - register_new_node( bol2, ctrl2 ); - _igvn.replace_input_of(loop_end, CountedLoopEndNode::TestValue, bol2); - // Step 3: Find the min-trip test guaranteed before a 'main' loop. // Make it a 1-trip test (means at least 2 trips). - if( adjust_min_trip ) { - assert( new_limit != NULL, "" ); - // Guard test uses an 'opaque' node which is not shared. Hence I - // can edit it's inputs directly. Hammer in the new limit for the - // minimum-trip guard. - assert( opaq->outcnt() == 1, "" ); - _igvn.hash_delete(opaq); - opaq->set_req(1, new_limit); - } - } // LoopLimitCheck + + // Guard test uses an 'opaque' node which is not shared. Hence I + // can edit it's inputs directly. Hammer in the new limit for the + // minimum-trip guard. + assert(opaq->outcnt() == 1, ""); + _igvn.replace_input_of(opaq, 1, new_limit); + } + + // Adjust max trip count. The trip count is intentionally rounded + // down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll, + // the main, unrolled, part of the loop will never execute as it is protected + // by the min-trip test. See bug 4834191 for a case where we over-unrolled + // and later determined that part of the unrolled loop was dead. + loop_head->set_trip_count(old_trip_count / 2); + + // Double the count of original iterations in the unrolled loop body. + loop_head->double_unrolled_count(); // --------- // Step 4: Clone the loop body. Move it inside the loop. This loop body @@ -1904,7 +1830,6 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset // ) if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; // We need this guard when scale*pre_limit+offset >= limit // due to underflow. So we need execute pre-loop until // scale*I+offset >= min_int. But (min_int-offset) will @@ -1956,7 +1881,6 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl); if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; // We need this guard when scale*main_limit+offset >= limit // due to underflow. So we need execute main-loop while // scale*I+offset+1 > min_int. But (min_int-offset-1) will @@ -2091,7 +2015,7 @@ bool PhaseIdealLoop::is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, //------------------------------do_range_check--------------------------------- // Eliminate range-checks and other trip-counter vs loop-invariant tests. -void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { +int PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { #ifndef PRODUCT if (PrintOpto && VerifyLoopOptimizations) { tty->print("Range Check Elimination "); @@ -2103,10 +2027,12 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { #endif assert(RangeCheckElimination, ""); CountedLoopNode *cl = loop->_head->as_CountedLoop(); + // If we fail before trying to eliminate range checks, set multiversion state + int closed_range_checks = 1; // protect against stride not being a constant if (!cl->stride_is_con()) - return; + return closed_range_checks; // Find the trip counter; we are iteration splitting based on it Node *trip_counter = cl->phi(); @@ -2117,8 +2043,8 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // Check graph shape. Cannot optimize a loop if zero-trip // Opaque1 node is optimized away and then another round // of loop opts attempted. - if (!is_canonical_main_loop_entry(cl)) { - return; + if (!is_canonical_loop_entry(cl)) { + return closed_range_checks; } // Need to find the main-loop zero-trip guard @@ -2132,7 +2058,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { Node *p_f = iffm->in(0); // pre loop may have been optimized out if (p_f->Opcode() != Op_IfFalse) { - return; + return closed_range_checks; } CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); assert(pre_end->loopnode()->is_pre_loop(), ""); @@ -2141,7 +2067,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // optimized away and then another round of loop opts attempted. // We can not optimize this particular loop in that case. if (pre_opaq1->Opcode() != Op_Opaque1) - return; + return closed_range_checks; Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1; Node *pre_limit = pre_opaq->in(1); @@ -2152,7 +2078,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // pre-loop Opaque1 node. Node *orig_limit = pre_opaq->original_loop_limit(); if (orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP) - return; + return closed_range_checks; // Must know if its a count-up or count-down loop @@ -2173,6 +2099,10 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // executed. bool conditional_rc = false; + // Count number of range checks and reduce by load range limits, if zero, + // the loop is in canonical form to multiversion. + closed_range_checks = 0; + // Check loop body for tests of trip-counter plus loop-invariant vs // loop-invariant. for( uint i = 0; i < loop->_body.size(); i++ ) { @@ -2181,6 +2111,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { iff->Opcode() == Op_RangeCheck) { // Test? // Test is an IfNode, has 2 projections. If BOTH are in the loop // we need loop unswitching instead of iteration splitting. + closed_range_checks++; Node *exit = loop->is_loop_exit(iff); if( !exit ) continue; int flip = (exit->Opcode() == Op_IfTrue) ? 1 : 0; @@ -2258,7 +2189,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit ); if (!conditional_rc) { // (0-offset)/scale could be outside of loop iterations range. - conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; + conditional_rc = !loop->dominates_backedge(iff); } } else { if (PrintOpto) { @@ -2275,7 +2206,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { scale_con = -scale_con; offset = new SubINode( zero, offset ); register_new_node( offset, pre_ctrl ); - limit = new SubINode( zero, limit ); + limit = new SubINode( zero, limit ); register_new_node( limit, pre_ctrl ); // Fall into LE case case BoolTest::le: @@ -2294,7 +2225,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // ((MIN_INT+1)-offset)/scale could be outside of loop iterations range. // Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could // still be outside of loop range. - conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; + conditional_rc = !loop->dominates_backedge(iff); } break; default: @@ -2324,6 +2255,9 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { --imax; } } + if (limit->Opcode() == Op_LoadRange) { + closed_range_checks--; + } } // End of is IF @@ -2340,26 +2274,6 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // Note:: we are making the main loop limit no longer precise; // need to round up based on stride. cl->set_nonexact_trip_count(); - if (!LoopLimitCheck && stride_con != 1 && stride_con != -1) { // Cutout for common case - // "Standard" round-up logic: ([main_limit-init+(y-1)]/y)*y+init - // Hopefully, compiler will optimize for powers of 2. - Node *ctrl = get_ctrl(main_limit); - Node *stride = cl->stride(); - Node *init = cl->init_trip()->uncast(); - Node *span = new SubINode(main_limit,init); - register_new_node(span,ctrl); - Node *rndup = _igvn.intcon(stride_con + ((stride_con>0)?-1:1)); - Node *add = new AddINode(span,rndup); - register_new_node(add,ctrl); - Node *div = new DivINode(0,add,stride); - register_new_node(div,ctrl); - Node *mul = new MulINode(div,stride); - register_new_node(mul,ctrl); - Node *newlim = new AddINode(mul,init); - register_new_node(newlim,ctrl); - main_limit = newlim; - } - Node *main_cle = cl->loopexit(); Node *main_bol = main_cle->in(1); // Hacking loop bounds; need private copies of exit test @@ -2379,6 +2293,169 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // The OpaqueNode is unshared by design assert( opqzm->outcnt() == 1, "cannot hack shared node" ); _igvn.replace_input_of(opqzm, 1, main_limit); + + return closed_range_checks; +} + +//------------------------------has_range_checks------------------------------- +// Check to see if RCE cleaned the current loop of range-checks. +void PhaseIdealLoop::has_range_checks(IdealLoopTree *loop) { + assert(RangeCheckElimination, ""); + + // skip if not a counted loop + if (!loop->is_counted()) return; + + CountedLoopNode *cl = loop->_head->as_CountedLoop(); + + // skip this loop if it is already checked + if (cl->has_been_range_checked()) return; + + // Now check for existance of range checks + for (uint i = 0; i < loop->_body.size(); i++) { + Node *iff = loop->_body[i]; + int iff_opc = iff->Opcode(); + if (iff_opc == Op_If || iff_opc == Op_RangeCheck) { + cl->mark_has_range_checks(); + break; + } + } + cl->set_has_been_range_checked(); +} + +//-------------------------multi_version_post_loops---------------------------- +// Check the range checks that remain, if simple, use the bounds to guard +// which version to a post loop we execute, one with range checks or one without +bool PhaseIdealLoop::multi_version_post_loops(IdealLoopTree *rce_loop, IdealLoopTree *legacy_loop) { + bool multi_version_succeeded = false; + assert(RangeCheckElimination, ""); + CountedLoopNode *legacy_cl = legacy_loop->_head->as_CountedLoop(); + assert(legacy_cl->is_post_loop(), ""); + + // Check for existance of range checks using the unique instance to make a guard with + Unique_Node_List worklist; + for (uint i = 0; i < legacy_loop->_body.size(); i++) { + Node *iff = legacy_loop->_body[i]; + int iff_opc = iff->Opcode(); + if (iff_opc == Op_If || iff_opc == Op_RangeCheck) { + worklist.push(iff); + } + } + + // Find RCE'd post loop so that we can stage its guard. + if (!is_canonical_loop_entry(legacy_cl)) return multi_version_succeeded; + Node* ctrl = legacy_cl->in(LoopNode::EntryControl); + Node* iffm = ctrl->in(0); + + // Now we test that both the post loops are connected + Node* post_loop_region = iffm->in(0); + if (post_loop_region == NULL) return multi_version_succeeded; + if (!post_loop_region->is_Region()) return multi_version_succeeded; + Node* covering_region = post_loop_region->in(RegionNode::Control+1); + if (covering_region == NULL) return multi_version_succeeded; + if (!covering_region->is_Region()) return multi_version_succeeded; + Node* p_f = covering_region->in(RegionNode::Control); + if (p_f == NULL) return multi_version_succeeded; + if (!p_f->is_IfFalse()) return multi_version_succeeded; + if (!p_f->in(0)->is_CountedLoopEnd()) return multi_version_succeeded; + CountedLoopEndNode* rce_loop_end = p_f->in(0)->as_CountedLoopEnd(); + if (rce_loop_end == NULL) return multi_version_succeeded; + CountedLoopNode* rce_cl = rce_loop_end->loopnode(); + if (rce_cl == NULL || !rce_cl->is_post_loop()) return multi_version_succeeded; + CountedLoopNode *known_rce_cl = rce_loop->_head->as_CountedLoop(); + if (rce_cl != known_rce_cl) return multi_version_succeeded; + + // Then we fetch the cover entry test + ctrl = rce_cl->in(LoopNode::EntryControl); + if (!ctrl->is_IfTrue() && !ctrl->is_IfFalse()) return multi_version_succeeded; + +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("PostMultiVersion\n"); + rce_loop->dump_head(); + legacy_loop->dump_head(); + } +#endif + + // Now fetch the limit we want to compare against + Node *limit = rce_cl->limit(); + bool first_time = true; + + // If we got this far, we identified the post loop which has been RCE'd and + // we have a work list. Now we will try to transform the if guard to cause + // the loop pair to be multi version executed with the determination left to runtime + // or the optimizer if full information is known about the given arrays at compile time. + Node *last_min = NULL; + multi_version_succeeded = true; + while (worklist.size()) { + Node* rc_iffm = worklist.pop(); + if (rc_iffm->is_If()) { + Node *rc_bolzm = rc_iffm->in(1); + if (rc_bolzm->is_Bool()) { + Node *rc_cmpzm = rc_bolzm->in(1); + if (rc_cmpzm->is_Cmp()) { + Node *rc_left = rc_cmpzm->in(2); + if (rc_left->Opcode() != Op_LoadRange) { + multi_version_succeeded = false; + break; + } + if (first_time) { + last_min = rc_left; + first_time = false; + } else { + Node *cur_min = new MinINode(last_min, rc_left); + last_min = cur_min; + _igvn.register_new_node_with_optimizer(last_min); + } + } + } + } + } + + // All we have to do is update the limit of the rce loop + // with the min of our expression and the current limit. + // We will use this expression to replace the current limit. + if (last_min && multi_version_succeeded) { + Node *cur_min = new MinINode(last_min, limit); + _igvn.register_new_node_with_optimizer(cur_min); + Node *cmp_node = rce_loop_end->cmp_node(); + _igvn.replace_input_of(cmp_node, 2, cur_min); + set_idom(cmp_node, cur_min, dom_depth(ctrl)); + set_ctrl(cur_min, ctrl); + set_loop(cur_min, rce_loop->_parent); + + legacy_cl->mark_is_multiversioned(); + rce_cl->mark_is_multiversioned(); + multi_version_succeeded = true; + + C->set_major_progress(); + } + + return multi_version_succeeded; +} + +//-------------------------poison_rce_post_loop-------------------------------- +// Causes the rce'd post loop to be optimized away if multiverioning fails +void PhaseIdealLoop::poison_rce_post_loop(IdealLoopTree *rce_loop) { + CountedLoopNode *rce_cl = rce_loop->_head->as_CountedLoop(); + Node* ctrl = rce_cl->in(LoopNode::EntryControl); + if (ctrl->is_IfTrue() || ctrl->is_IfFalse()) { + Node* iffm = ctrl->in(0); + if (iffm->is_If()) { + Node* cur_bool = iffm->in(1); + if (cur_bool->is_Bool()) { + Node* cur_cmp = cur_bool->in(1); + if (cur_cmp->is_Cmp()) { + BoolTest::mask new_test = BoolTest::gt; + BoolNode *new_bool = new BoolNode(cur_cmp, new_test); + _igvn.replace_node(cur_bool, new_bool); + _igvn._worklist.push(new_bool); + Node* left_op = cur_cmp->in(1); + _igvn.replace_input_of(cur_cmp, 2, left_op); + C->set_major_progress(); + } + } + } + } } //------------------------------DCE_loop_body---------------------------------- @@ -2738,8 +2815,20 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_ // Adjust the pre- and main-loop limits to let the pre and post loops run // with full checks, but the main-loop with no checks. Remove said // checks from the main body. - if (should_rce) - phase->do_range_check(this,old_new); + if (should_rce) { + if (phase->do_range_check(this, old_new) != 0) { + cl->mark_has_range_checks(); + } + } else { + phase->has_range_checks(this); + } + + if (should_unroll && !should_peel && PostLoopMultiversioning) { + // Try to setup multiversioning on main loops before they are unrolled + if (cl->is_main_loop() && (cl->unrolled_count() == 1)) { + phase->insert_scalar_rced_post_loop(this, old_new); + } + } // Double loop body for unrolling. Adjust the minimum-trip test (will do // twice as many iterations as before) and the main body limit (only do diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index 991d339d58c..697ff0c9f95 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -138,7 +138,7 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { Node* uniqc = proj_true->unique_ctrl_out(); Node* entry = head->in(LoopNode::EntryControl); Node* predicate = find_predicate(entry); - if (predicate != NULL && LoopLimitCheck && UseLoopPredicate) { + if (predicate != NULL && UseLoopPredicate) { // We may have two predicates, find first. entry = find_predicate(entry->in(0)->in(0)); if (entry != NULL) predicate = entry; diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 59ca3261c20..33f5de7f10a 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "compiler/compileLog.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" @@ -463,8 +464,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { Node *hook = new Node(6); - if (LoopLimitCheck) { - // =================================================== // Generate loop limit check to avoid integer overflow // in cases like next (cyclic loops): @@ -593,103 +592,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { } set_subtree_ctrl( limit ); - } else { // LoopLimitCheck - - // If compare points to incr, we are ok. Otherwise the compare - // can directly point to the phi; in this case adjust the compare so that - // it points to the incr by adjusting the limit. - if (cmp->in(1) == phi || cmp->in(2) == phi) - limit = gvn->transform(new AddINode(limit,stride)); - - // trip-count for +-tive stride should be: (limit - init_trip + stride - 1)/stride. - // Final value for iterator should be: trip_count * stride + init_trip. - Node *one_p = gvn->intcon( 1); - Node *one_m = gvn->intcon(-1); - - Node *trip_count = NULL; - switch( bt ) { - case BoolTest::eq: - ShouldNotReachHere(); - case BoolTest::ne: // Ahh, the case we desire - if (stride_con == 1) - trip_count = gvn->transform(new SubINode(limit,init_trip)); - else if (stride_con == -1) - trip_count = gvn->transform(new SubINode(init_trip,limit)); - else - ShouldNotReachHere(); - set_subtree_ctrl(trip_count); - //_loop.map(trip_count->_idx,loop(limit)); - break; - case BoolTest::le: // Maybe convert to '<' case - limit = gvn->transform(new AddINode(limit,one_p)); - set_subtree_ctrl( limit ); - hook->init_req(4, limit); - - bt = BoolTest::lt; - // Make the new limit be in the same loop nest as the old limit - //_loop.map(limit->_idx,limit_loop); - // Fall into next case - case BoolTest::lt: { // Maybe convert to '!=' case - if (stride_con < 0) // Count down loop rolls through MAXINT - ShouldNotReachHere(); - Node *range = gvn->transform(new SubINode(limit,init_trip)); - set_subtree_ctrl( range ); - hook->init_req(0, range); - - Node *bias = gvn->transform(new AddINode(range,stride)); - set_subtree_ctrl( bias ); - hook->init_req(1, bias); - - Node *bias1 = gvn->transform(new AddINode(bias,one_m)); - set_subtree_ctrl( bias1 ); - hook->init_req(2, bias1); - - trip_count = gvn->transform(new DivINode(0,bias1,stride)); - set_subtree_ctrl( trip_count ); - hook->init_req(3, trip_count); - break; - } - - case BoolTest::ge: // Maybe convert to '>' case - limit = gvn->transform(new AddINode(limit,one_m)); - set_subtree_ctrl( limit ); - hook->init_req(4 ,limit); - - bt = BoolTest::gt; - // Make the new limit be in the same loop nest as the old limit - //_loop.map(limit->_idx,limit_loop); - // Fall into next case - case BoolTest::gt: { // Maybe convert to '!=' case - if (stride_con > 0) // count up loop rolls through MININT - ShouldNotReachHere(); - Node *range = gvn->transform(new SubINode(limit,init_trip)); - set_subtree_ctrl( range ); - hook->init_req(0, range); - - Node *bias = gvn->transform(new AddINode(range,stride)); - set_subtree_ctrl( bias ); - hook->init_req(1, bias); - - Node *bias1 = gvn->transform(new AddINode(bias,one_p)); - set_subtree_ctrl( bias1 ); - hook->init_req(2, bias1); - - trip_count = gvn->transform(new DivINode(0,bias1,stride)); - set_subtree_ctrl( trip_count ); - hook->init_req(3, trip_count); - break; - } - } // switch( bt ) - - Node *span = gvn->transform(new MulINode(trip_count,stride)); - set_subtree_ctrl( span ); - hook->init_req(5, span); - - limit = gvn->transform(new AddINode(span,init_trip)); - set_subtree_ctrl( limit ); - - } // LoopLimitCheck - if (!UseCountedLoopSafepoints) { // Check for SafePoint on backedge and remove Node *sfpt = x->in(LoopNode::LoopBackControl); @@ -829,7 +731,7 @@ Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) { CountedLoopNode *cl = loop->_head->as_CountedLoop(); assert(cl->is_valid_counted_loop(), ""); - if (!LoopLimitCheck || ABS(cl->stride_con()) == 1 || + if (ABS(cl->stride_con()) == 1 || cl->limit()->Opcode() == Op_LoopLimit) { // Old code has exact limit (it could be incorrect in case of int overflow). // Loop limit is exact with stride == 1. And loop may already have exact limit. @@ -1897,12 +1799,10 @@ void IdealLoopTree::dump_head( ) const { tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx); if (_irreducible) tty->print(" IRREDUCIBLE"); Node* entry = _head->in(LoopNode::EntryControl); - if (LoopLimitCheck) { - Node* predicate = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); - if (predicate != NULL ) { - tty->print(" limit_check"); - entry = entry->in(0)->in(0); - } + Node* predicate = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); + if (predicate != NULL ) { + tty->print(" limit_check"); + entry = entry->in(0)->in(0); } if (UseLoopPredicate) { entry = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); @@ -1933,6 +1833,9 @@ void IdealLoopTree::dump_head( ) const { if (cl->is_pre_loop ()) tty->print(" pre" ); if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); + if (cl->is_vectorized_loop()) tty->print(" vector"); + if (cl->range_checks_present()) tty->print(" rc "); + if (cl->is_multiversioned()) tty->print(" multi "); } if (_has_call) tty->print(" has_call"); if (_has_sfpt) tty->print(" has_sfpt"); @@ -2322,7 +2225,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts) // Some parser-inserted loop predicates could never be used by loop // predication or they were moved away from loop during some optimizations. // For example, peeling. Eliminate them before next loop optimizations. - if (UseLoopPredicate || LoopLimitCheck) { + if (UseLoopPredicate) { eliminate_useless_predicates(); } @@ -2451,7 +2354,30 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts) for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { IdealLoopTree* lpt = iter.current(); if (lpt->is_counted()) { - sw.transform_loop(lpt, true); + CountedLoopNode *cl = lpt->_head->as_CountedLoop(); + + if (PostLoopMultiversioning && cl->is_rce_post_loop() && !cl->is_vectorized_loop()) { + // Check that the rce'd post loop is encountered first, multiversion after all + // major main loop optimization are concluded + if (!C->major_progress()) { + IdealLoopTree *lpt_next = lpt->_next; + if (lpt_next && lpt_next->is_counted()) { + CountedLoopNode *cl = lpt_next->_head->as_CountedLoop(); + has_range_checks(lpt_next); + if (cl->is_post_loop() && cl->range_checks_present()) { + if (!cl->is_multiversioned()) { + if (multi_version_post_loops(lpt, lpt_next) == false) { + // Cause the rce loop to be optimized away if we fail + cl->mark_is_multiversioned(); + poison_rce_post_loop(lpt); + } + } + } + } + } + } else if (cl->is_main_loop()) { + sw.transform_loop(lpt, true); + } } } } @@ -3285,8 +3211,10 @@ Node* PhaseIdealLoop::compute_lca_of_uses(Node* n, Node* early, bool verify) { // loop unswitching, and IGVN, or a combination of them) can freely change // the graph's shape. As a result, the graph shape outlined below cannot // be guaranteed anymore. -bool PhaseIdealLoop::is_canonical_main_loop_entry(CountedLoopNode* cl) { - assert(cl->is_main_loop(), "check should be applied to main loops"); +bool PhaseIdealLoop::is_canonical_loop_entry(CountedLoopNode* cl) { + if (!cl->is_main_loop() && !cl->is_post_loop()) { + return false; + } Node* ctrl = cl->in(LoopNode::EntryControl); if (ctrl == NULL || (!ctrl->is_IfTrue() && !ctrl->is_IfFalse())) { return false; @@ -3303,8 +3231,16 @@ bool PhaseIdealLoop::is_canonical_main_loop_entry(CountedLoopNode* cl) { if (cmpzm == NULL || !cmpzm->is_Cmp()) { return false; } - Node* opqzm = cmpzm->in(2); - if (opqzm == NULL || opqzm->Opcode() != Op_Opaque1) { + // compares can get conditionally flipped + bool found_opaque = false; + for (uint i = 1; i < cmpzm->req(); i++) { + Node* opnd = cmpzm->in(i); + if (opnd && opnd->Opcode() == Op_Opaque1) { + found_opaque = true; + break; + } + } + if (!found_opaque) { return false; } return true; diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 09512cdafb5..ba83e503178 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -69,9 +69,13 @@ protected: PassedSlpAnalysis=512, DoUnrollOnly=1024, VectorizedLoop=2048, - HasAtomicPostLoop=4096 }; + HasAtomicPostLoop=4096, + HasRangeChecks=8192, + IsMultiversioned=16384}; char _unswitch_count; enum { _unswitch_max=3 }; + char _postloop_flags; + enum { LoopNotRCEChecked = 0, LoopRCEChecked = 1, RCEPostLoop = 2 }; public: // Names for edge indices @@ -80,9 +84,13 @@ public: int is_inner_loop() const { return _loop_flags & InnerLoop; } void set_inner_loop() { _loop_flags |= InnerLoop; } + int range_checks_present() const { return _loop_flags & HasRangeChecks; } + int is_multiversioned() const { return _loop_flags & IsMultiversioned; } + int is_vectorized_loop() const { return _loop_flags & VectorizedLoop; } int is_partial_peel_loop() const { return _loop_flags & PartialPeelLoop; } void set_partial_peel_loop() { _loop_flags |= PartialPeelLoop; } int partial_peel_has_failed() const { return _loop_flags & PartialPeelFailed; } + void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; } void mark_has_reductions() { _loop_flags |= HasReductions; } void mark_was_slp() { _loop_flags |= WasSlpAnalyzed; } @@ -90,15 +98,23 @@ public: void mark_do_unroll_only() { _loop_flags |= DoUnrollOnly; } void mark_loop_vectorized() { _loop_flags |= VectorizedLoop; } void mark_has_atomic_post_loop() { _loop_flags |= HasAtomicPostLoop; } + void mark_has_range_checks() { _loop_flags |= HasRangeChecks; } + void mark_is_multiversioned() { _loop_flags |= IsMultiversioned; } int unswitch_max() { return _unswitch_max; } int unswitch_count() { return _unswitch_count; } + + int has_been_range_checked() const { return _postloop_flags & LoopRCEChecked; } + void set_has_been_range_checked() { _postloop_flags |= LoopRCEChecked; } + int is_rce_post_loop() const { return _postloop_flags & RCEPostLoop; } + void set_is_rce_post_loop() { _postloop_flags |= RCEPostLoop; } + void set_unswitch_count(int val) { assert (val <= unswitch_max(), "too many unswitches"); _unswitch_count = val; } - LoopNode( Node *entry, Node *backedge ) : RegionNode(3), _loop_flags(0), _unswitch_count(0) { + LoopNode(Node *entry, Node *backedge) : RegionNode(3), _loop_flags(0), _unswitch_count(0), _postloop_flags(0) { init_class_id(Class_Loop); init_req(EntryControl, entry); init_req(LoopBackControl, backedge); @@ -225,7 +241,6 @@ public: int has_passed_slp () const { return (_loop_flags&PassedSlpAnalysis) == PassedSlpAnalysis; } int do_unroll_only () const { return (_loop_flags&DoUnrollOnly) == DoUnrollOnly; } int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; } - int is_vectorized_loop () const { return (_loop_flags & VectorizedLoop) == VectorizedLoop; } int has_atomic_post_loop () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; } void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; } @@ -657,7 +672,7 @@ class PhaseIdealLoop : public PhaseTransform { public: - static bool is_canonical_main_loop_entry(CountedLoopNode* cl); + static bool is_canonical_loop_entry(CountedLoopNode* cl); bool has_node( Node* n ) const { guarantee(n != NULL, "No Node."); @@ -911,6 +926,15 @@ public: // Add pre and post loops around the given loop. These loops are used // during RCE, unrolling and aligning loops. void insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ); + + // Add post loop after the given loop. + Node *insert_post_loop(IdealLoopTree *loop, Node_List &old_new, + CountedLoopNode *main_head, CountedLoopEndNode *main_end, + Node *incr, Node *limit, CountedLoopNode *&post_head); + + // Add an RCE'd post loop which we will multi-version adapt for run time test path usage + void insert_scalar_rced_post_loop( IdealLoopTree *loop, Node_List &old_new ); + // Add a vector post loop between a vector main loop and the current post loop void insert_vector_post_loop(IdealLoopTree *loop, Node_List &old_new); // If Node n lives in the back_ctrl block, we clone a private version of n @@ -983,7 +1007,17 @@ public: } // Eliminate range-checks and other trip-counter vs loop-invariant tests. - void do_range_check( IdealLoopTree *loop, Node_List &old_new ); + int do_range_check( IdealLoopTree *loop, Node_List &old_new ); + + // Check to see if do_range_check(...) cleaned the main loop of range-checks + void has_range_checks(IdealLoopTree *loop); + + // Process post loops which have range checks and try to build a multi-version + // guard to safely determine if we can execute the post loop which was RCE'd. + bool multi_version_post_loops(IdealLoopTree *rce_loop, IdealLoopTree *legacy_loop); + + // Cause the rce'd post loop to optimized away, this happens if we cannot complete multiverioning + void poison_rce_post_loop(IdealLoopTree *rce_loop); // Create a slow version of the loop by cloning the loop // and inserting an if to select fast-slow versions. diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index 0f7641dfebe..bd00791aee0 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" #include "opto/connode.hpp" diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 1df9f7ca1c0..2d91f411174 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/ad.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index e79abac0c19..d6b3c9394ad 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "compiler/compileLog.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 78dcacc550b..2973183f91f 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 503f3c7f400..833f0a66add 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "compiler/compileLog.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "opto/addnode.hpp" #include "opto/c2compiler.hpp" @@ -661,8 +662,7 @@ void Parse::do_all_blocks() { // (Note that dead locals do not get phis built, ever.) ensure_phis_everywhere(); - if (block->is_SEL_head() && - (UseLoopPredicate || LoopLimitCheck)) { + if (block->is_SEL_head() && UseLoopPredicate) { // Add predicate to single entry (not irreducible) loop head. assert(!block->has_merged_backedge(), "only entry paths should be merged for now"); // Need correct bci for predicate. diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 8004ef246e5..6c0c2bec44f 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "classfile/vmSymbols.hpp" #include "compiler/compileLog.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" #include "opto/addnode.hpp" diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index f925cd5ef27..0934a0fd7df 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/block.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" diff --git a/hotspot/src/share/vm/opto/postaloc.cpp b/hotspot/src/share/vm/opto/postaloc.cpp index 2aba90329f2..d572ac9fe2e 100644 --- a/hotspot/src/share/vm/opto/postaloc.cpp +++ b/hotspot/src/share/vm/opto/postaloc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/chaitin.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index 781a53cc00b..81ac6d25fd8 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/c2compiler.hpp" #include "opto/callnode.hpp" diff --git a/hotspot/src/share/vm/opto/replacednodes.cpp b/hotspot/src/share/vm/opto/replacednodes.cpp index d4cb3b1e260..e3f3c113572 100644 --- a/hotspot/src/share/vm/opto/replacednodes.cpp +++ b/hotspot/src/share/vm/opto/replacednodes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/resourceArea.hpp" #include "opto/cfgnode.hpp" #include "opto/phaseX.hpp" #include "opto/replacednodes.hpp" diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index dff0da6161b..37e33ef76ba 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ #include "interpreter/linkResolver.hpp" #include "logging/log.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" @@ -1288,7 +1289,7 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - trace_exception(LogHandle(exceptions)::info_stream(), exception(), pc, ""); + trace_exception(Log(exceptions)::info_stream(), exception(), pc, ""); } // for AbortVMOnException flag diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 74c7de0cc14..00862021ae0 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "compiler/compileLog.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" @@ -3076,7 +3077,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) { CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode* cl) { // The loop cannot be optimized if the graph shape at // the loop entry is inappropriate. - if (!PhaseIdealLoop::is_canonical_main_loop_entry(cl)) { + if (!PhaseIdealLoop::is_canonical_loop_entry(cl)) { return NULL; } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 5f08fcd2c1f..80dc866f136 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -39,6 +39,7 @@ #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceOop.hpp" @@ -349,7 +350,7 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR &st, CHECK_NULL); - if (log_is_enabled(Info, classresolve) && k != NULL) { + if (log_is_enabled(Debug, classresolve) && k != NULL) { trace_class_resolution(k); } @@ -419,7 +420,7 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, thread); - if (log_is_enabled(Info, classresolve) && result != NULL) { + if (log_is_enabled(Debug, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } @@ -3271,7 +3272,7 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) { TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL); jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); - if (log_is_enabled(Info, classresolve) && result != NULL) { + if (log_is_enabled(Debug, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } return result; diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 093efe3bab1..6c77385568c 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -38,6 +38,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/bytecode.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceKlass.hpp" @@ -210,9 +211,9 @@ static void trace_class_resolution_impl(Klass* to_class, TRAPS) { const char * to = to_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - log_info(classresolve)("%s %s %s:%d (%s)", from, to, source_file, line_number, trace); + log_debug(classresolve)("%s %s %s:%d (%s)", from, to, source_file, line_number, trace); } else { - log_info(classresolve)("%s %s (%s)", from, to, trace); + log_debug(classresolve)("%s %s (%s)", from, to, trace); } } } @@ -518,19 +519,13 @@ JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) JVM_END -JVM_ENTRY(jint, JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable)) - JVMWrapper("JVM_GetStackTraceDepth"); - oop exception = JNIHandles::resolve(throwable); - return java_lang_Throwable::get_stack_trace_depth(exception, THREAD); -JVM_END - - -JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index)) - JVMWrapper("JVM_GetStackTraceElement"); - JvmtiVMObjectAllocEventCollector oam; // This ctor (throughout this module) may trigger a safepoint/GC - oop exception = JNIHandles::resolve(throwable); - oop element = java_lang_Throwable::get_stack_trace_element(exception, index, CHECK_NULL); - return JNIHandles::make_local(env, element); +JVM_ENTRY(void, JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray stackTrace)) + JVMWrapper("JVM_GetStackTraceElements"); + Handle exception(THREAD, JNIHandles::resolve(throwable)); + objArrayOop st = objArrayOop(JNIHandles::resolve(stackTrace)); + objArrayHandle stack_trace(THREAD, st); + // Fill in the allocated stack trace + java_lang_Throwable::get_stack_trace_elements(exception, stack_trace, CHECK); JVM_END @@ -839,7 +834,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, return NULL; } - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { trace_class_resolution(k); } return (jclass) JNIHandles::make_local(env, k->java_mirror()); @@ -876,7 +871,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name, jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, false, THREAD); - if (log_is_enabled(Info, classresolve) && result != NULL) { + if (log_is_enabled(Debug, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } return result; @@ -906,7 +901,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, true, thread); - if (log_is_enabled(Info, classresolve) && result != NULL) { + if (log_is_enabled(Debug, classresolve) && result != NULL) { // this function is generally only used for class loading during verification. ResourceMark rm; oop from_mirror = JNIHandles::resolve_non_null(from); @@ -916,7 +911,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, oop mirror = JNIHandles::resolve_non_null(result); Klass* to_class = java_lang_Class::as_Klass(mirror); const char * to = to_class->external_name(); - log_info(classresolve)("%s %s (verification)", from_name, to); + log_debug(classresolve)("%s %s (verification)", from_name, to); } return result; @@ -984,7 +979,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, &st, CHECK_NULL); - if (log_is_enabled(Info, classresolve) && k != NULL) { + if (log_is_enabled(Debug, classresolve) && k != NULL) { trace_class_resolution(k); } @@ -1988,8 +1983,8 @@ JVM_ENTRY(jobject, JVM_GetClassConstantPool(JNIEnv *env, jclass cls)) Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); if (k->is_instance_klass()) { instanceKlassHandle k_h(THREAD, k); - Handle jcp = sun_reflect_ConstantPool::create(CHECK_NULL); - sun_reflect_ConstantPool::set_cp(jcp(), k_h->constants()); + Handle jcp = reflect_ConstantPool::create(CHECK_NULL); + reflect_ConstantPool::set_cp(jcp(), k_h->constants()); return JNIHandles::make_local(jcp()); } } @@ -2001,7 +1996,7 @@ JVM_END JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused)) { JVMWrapper("JVM_ConstantPoolGetSize"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); return cp->length(); } JVM_END @@ -2010,7 +2005,7 @@ JVM_END JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetClassAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_klass() && !tag.is_unresolved_klass()) { @@ -2024,7 +2019,7 @@ JVM_END JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetClassAtIfLoaded"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_klass() && !tag.is_unresolved_klass()) { @@ -2069,7 +2064,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject { JVMWrapper("JVM_ConstantPoolGetMethodAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); jobject res = get_method_at_helper(cp, index, true, CHECK_NULL); return res; @@ -2080,7 +2075,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAtIfLoaded(JNIEnv *env, jobject obj, { JVMWrapper("JVM_ConstantPoolGetMethodAtIfLoaded"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); jobject res = get_method_at_helper(cp, index, false, CHECK_NULL); return res; @@ -2116,7 +2111,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jobject { JVMWrapper("JVM_ConstantPoolGetFieldAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); jobject res = get_field_at_helper(cp, index, true, CHECK_NULL); return res; @@ -2127,7 +2122,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, { JVMWrapper("JVM_ConstantPoolGetFieldAtIfLoaded"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); jobject res = get_field_at_helper(cp, index, false, CHECK_NULL); return res; @@ -2138,7 +2133,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject { JVMWrapper("JVM_ConstantPoolGetMemberRefInfoAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_field_or_method()) { @@ -2164,7 +2159,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, job { JVMWrapper("JVM_ConstantPoolGetClassRefIndexAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); constantTag tag = cp->tag_at(index); if (!tag.is_field_or_method()) { @@ -2178,7 +2173,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject ob { JVMWrapper("JVM_ConstantPoolGetNameAndTypeRefIndexAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); constantTag tag = cp->tag_at(index); if (!tag.is_invoke_dynamic() && !tag.is_field_or_method()) { @@ -2192,7 +2187,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, job { JVMWrapper("JVM_ConstantPoolGetNameAndTypeRefInfoAt"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_name_and_type()) { @@ -2213,7 +2208,7 @@ JVM_END JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetIntAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); constantTag tag = cp->tag_at(index); if (!tag.is_int()) { @@ -2226,7 +2221,7 @@ JVM_END JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetLongAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0L)); constantTag tag = cp->tag_at(index); if (!tag.is_long()) { @@ -2239,7 +2234,7 @@ JVM_END JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetFloatAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0f)); constantTag tag = cp->tag_at(index); if (!tag.is_float()) { @@ -2252,7 +2247,7 @@ JVM_END JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetDoubleAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0)); constantTag tag = cp->tag_at(index); if (!tag.is_double()) { @@ -2265,7 +2260,7 @@ JVM_END JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetStringAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_string()) { @@ -2280,7 +2275,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject u { JVMWrapper("JVM_ConstantPoolGetUTF8At"); JvmtiVMObjectAllocEventCollector oam; - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_symbol()) { @@ -2295,7 +2290,7 @@ JVM_END JVM_ENTRY(jbyte, JVM_ConstantPoolGetTagAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetTagAt"); - constantPoolHandle cp = constantPoolHandle(THREAD, sun_reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); + constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); constantTag tag = cp->tag_at(index); jbyte result = tag.value(); diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 31ff94c5743..dafc3955101 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,11 +201,8 @@ JVM_GetVmArguments(JNIEnv *env); JNIEXPORT void JNICALL JVM_FillInStackTrace(JNIEnv *env, jobject throwable); -JNIEXPORT jint JNICALL -JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); - -JNIEXPORT jobject JNICALL -JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); +JNIEXPORT void JNICALL +JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements); /* * java.lang.StackWalker diff --git a/hotspot/src/share/vm/prims/jvmtiEnter.xsl b/hotspot/src/share/vm/prims/jvmtiEnter.xsl index 15fd952aee4..2d012a82129 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl +++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl @@ -37,6 +37,7 @@ # include "precompiled.hpp" +# include "memory/resourceArea.hpp" # include "utilities/macros.hpp" #if INCLUDE_JVMTI # include "oops/oop.inline.hpp" diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index ca2d50b9a09..6dffe9876a1 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp @@ -59,6 +59,7 @@ #include "runtime/reflectionUtils.hpp" #include "runtime/signature.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.hpp" #include "runtime/vmThread.hpp" #include "services/threadService.hpp" @@ -475,7 +476,7 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) { // terminating the VM so we check one more time. // create the zip entry - ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); + ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, true); if (zip_entry == NULL) { return JVMTI_ERROR_ILLEGAL_ARGUMENT; } @@ -519,7 +520,7 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) { // create the zip entry (which will open the zip file and hence // check that the segment is indeed a zip file). - ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); + ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, false); if (zip_entry == NULL) { return JVMTI_ERROR_ILLEGAL_ARGUMENT; } diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index 6c92b9cf426..96ee3a19adb 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 9b7b0386b48..20de3f979cb 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -2315,6 +2315,8 @@ void JvmtiExport::transition_pending_onload_raw_monitors() { } //////////////////////////////////////////////////////////////////////////////////////////////// +#if INCLUDE_SERVICES +// Attach is disabled if SERVICES is not included // type for the Agent_OnAttach entry point extern "C" { @@ -2416,6 +2418,7 @@ jint JvmtiExport::load_agent_library(const char *agent, const char *absParam, return result; } +#endif // INCLUDE_SERVICES //////////////////////////////////////////////////////////////////////////////////////////////// // Setup current current thread for event collection. diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp index 4e9def53f94..6b11139cb20 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.hpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp @@ -377,9 +377,11 @@ class JvmtiExport : public AllStatic { static void transition_pending_onload_raw_monitors() NOT_JVMTI_RETURN; +#if INCLUDE_SERVICES // attach support static jint load_agent_library(const char *agent, const char *absParam, const char *options, outputStream* out) NOT_JVMTI_RETURN_(JNI_ERR); static jint load_agent_library(AttachOperation* op, outputStream* out) NOT_JVMTI_RETURN_(JNI_ERR); +#endif // SetNativeMethodPrefix support static char** get_all_native_method_prefixes(int* count_ptr) NOT_JVMTI_RETURN_(NULL); diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 6b176ec1f70..3410d9566c9 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -34,6 +34,7 @@ #include "interpreter/rewriter.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/fieldStreams.hpp" #include "oops/klassVtable.hpp" diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 9883c5278b6..b164c7ae45a 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -29,6 +29,7 @@ #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" diff --git a/hotspot/src/share/vm/prims/jvmtiTrace.cpp b/hotspot/src/share/vm/prims/jvmtiTrace.cpp index 1cc63efe074..01edd16c63f 100644 --- a/hotspot/src/share/vm/prims/jvmtiTrace.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTrace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "memory/resourceArea.hpp" #include "prims/jvmtiTrace.hpp" // diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index fa1cc2cc392..b4abd306781 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -34,13 +34,14 @@ #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/javaCalls.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/reflection.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" @@ -73,7 +74,7 @@ void MethodHandles::generate_adapters() { assert(_adapter_code == NULL, "generate only once"); ResourceMark rm; - TraceStartupTime timer("MethodHandles adapters generation"); + TraceTime timer("MethodHandles adapters generation", TRACETIME_LOG(Info, startuptime)); _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size); CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 47c4d7fe6e5..f951f694f1d 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -26,6 +26,7 @@ #include "classfile/classFileStream.hpp" #include "classfile/vmSymbols.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "prims/jni.h" @@ -867,7 +868,10 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env, } const Klass* host_klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class)); - assert(host_klass != NULL, "invariant"); + // Primitive types have NULL Klass* fields in their java.lang.Class instances. + if (host_klass == NULL) { + THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + } const char* host_source = host_klass->external_name(); Handle host_loader(THREAD, host_klass->class_loader()); diff --git a/hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp b/hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp index bd1699770d3..3ed2ab83ae0 100644 --- a/hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp +++ b/hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "prims/jni.h" #include "prims/whitebox.hpp" diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 840e93e7294..88a732370f6 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -35,6 +35,8 @@ #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" #include "oops/oop.inline.hpp" @@ -717,11 +719,6 @@ WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring return result; WB_END -class AlwaysFalseClosure : public BoolObjectClosure { - public: - bool do_object_b(oop p) { return false; } -}; - static AlwaysFalseClosure always_false; WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) @@ -997,7 +994,7 @@ WB_END WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); - Universe::heap()->collect(GCCause::_last_ditch_collection); + Universe::heap()->collect(GCCause::_wb_full_gc); #if INCLUDE_ALL_GCS if (UseG1GC) { // Needs to be cleared explicitly for G1 @@ -1376,8 +1373,8 @@ WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint inde return ConstantPool::encode_invokedynamic_index(index); WB_END -WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) - VM_ClearICs clear_ics; +WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb, jboolean preserve_static_stubs)) + VM_ClearICs clear_ics(preserve_static_stubs == JNI_TRUE); VMThread::execute(&clear_ics); WB_END @@ -1757,7 +1754,7 @@ static JNINativeMethod methods[] = { {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared }, {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored }, - {CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches }, + {CC"clearInlineCaches0", CC"(Z)V", (void*)&WB_ClearInlineCaches }, {CC"addCompilerDirective", CC"(Ljava/lang/String;)I", (void*)&WB_AddCompilerDirective }, {CC"removeCompilerDirective", CC"(I)V", (void*)&WB_RemoveCompilerDirective }, diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 629b1267071..948f80789e4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -66,16 +66,6 @@ #define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp" #define DEFAULT_JAVA_LAUNCHER "generic" -#define UNSUPPORTED_GC_OPTION(gc) \ -do { \ - if (gc) { \ - if (FLAG_IS_CMDLINE(gc)) { \ - warning(#gc " is not supported in this VM. Using Serial GC."); \ - } \ - FLAG_SET_DEFAULT(gc, false); \ - } \ -} while(0) - char* Arguments::_jvm_flags_file = NULL; char** Arguments::_jvm_flags_array = NULL; int Arguments::_num_jvm_flags = 0; @@ -385,6 +375,7 @@ static SpecialFlag const special_jvm_flags[] = { { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "UseAltSigs", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "SegmentedHeapDumpThreshold", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "PrintOopAddress", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, @@ -417,16 +408,36 @@ static AliasedFlag const aliased_jvm_flags[] = { }; static AliasedLoggingFlag const aliased_logging_flags[] = { - { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload }, - { "TraceClassPaths", LogLevel::Info, true, LogTag::_classpath }, - { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve }, - { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, - { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions }, - { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation }, - { "TraceBiasedLocking", LogLevel::Info, true, LogTag::_biasedlocking }, - { NULL, LogLevel::Off, false, LogTag::__NO_TAG } + { "TraceBiasedLocking", LogLevel::Info, true, LOG_TAGS(biasedlocking) }, + { "TraceClassLoading", LogLevel::Info, true, LOG_TAGS(classload) }, + { "TraceClassLoadingPreorder", LogLevel::Debug, true, LOG_TAGS(classload, preorder) }, + { "TraceClassPaths", LogLevel::Info, true, LOG_TAGS(classpath) }, + { "TraceClassResolution", LogLevel::Debug, true, LOG_TAGS(classresolve) }, + { "TraceClassUnloading", LogLevel::Info, true, LOG_TAGS(classunload) }, + { "TraceExceptions", LogLevel::Info, true, LOG_TAGS(exceptions) }, + { "TraceLoaderConstraints", LogLevel::Info, true, LOG_TAGS(classload, constraints) }, + { "TraceMonitorInflation", LogLevel::Debug, true, LOG_TAGS(monitorinflation) }, + { "TraceSafepointCleanupTime", LogLevel::Info, true, LOG_TAGS(safepointcleanup) }, + { NULL, LogLevel::Off, false, LOG_TAGS(_NO_TAG) } }; +#ifndef PRODUCT +// These options are removed in jdk9. Remove this code for jdk10. +static AliasedFlag const removed_develop_logging_flags[] = { + { "TraceClassInitialization", "-Xlog:classinit" }, + { "TraceClassLoaderData", "-Xlog:classloaderdata" }, + { "TraceDefaultMethods", "-Xlog:defaultmethods=debug" }, + { "TraceItables", "-Xlog:itables=debug" }, + { "TraceMonitorMismatch", "-Xlog:monitormismatch=info" }, + { "TraceSafepoint", "-Xlog:safepoint=debug" }, + { "TraceStartupTime", "-Xlog:startuptime" }, + { "TraceVMOperation", "-Xlog:vmoperation=debug" }, + { "PrintVtables", "-Xlog:vtables=debug" }, + { "VerboseVerification", "-Xlog:verification" }, + { NULL, NULL } +}; +#endif //PRODUCT + // Return true if "v" is less than "other", where "other" may be "undefined". static bool version_less_than(JDK_Version v, JDK_Version other) { assert(!v.is_undefined(), "must be defined"); @@ -478,6 +489,18 @@ int Arguments::is_deprecated_flag(const char *flag_name, JDK_Version* version) { return 0; } +#ifndef PRODUCT +const char* Arguments::removed_develop_logging_flag_name(const char* name){ + for (size_t i = 0; removed_develop_logging_flags[i].alias_name != NULL; i++) { + const AliasedFlag& flag = removed_develop_logging_flags[i]; + if (strcmp(flag.alias_name, name) == 0) { + return flag.real_name; + } + } + return NULL; +} +#endif // PRODUCT + const char* Arguments::real_flag_name(const char *flag_name) { for (size_t i = 0; aliased_jvm_flags[i].alias_name != NULL; i++) { const AliasedFlag& flag_status = aliased_jvm_flags[i]; @@ -961,14 +984,39 @@ const char* Arguments::handle_aliases_and_deprecation(const char* arg, bool warn return NULL; } -AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name){ +void log_deprecated_flag(const char* name, bool on, AliasedLoggingFlag alf) { + LogTagType tagSet[] = {alf.tag0, alf.tag1, alf.tag2, alf.tag3, alf.tag4, alf.tag5}; + // Set tagset string buffer at max size of 256, large enough for any alias tagset + const int max_tagset_size = 256; + int max_tagset_len = max_tagset_size - 1; + char tagset_buffer[max_tagset_size]; + tagset_buffer[0] = '\0'; + + // Write tag-set for aliased logging option, in string list form + int max_tags = sizeof(tagSet)/sizeof(tagSet[0]); + for (int i = 0; i < max_tags && tagSet[i] != LogTag::__NO_TAG; i++) { + if (i > 0) { + strncat(tagset_buffer, ",", max_tagset_len - strlen(tagset_buffer)); + } + strncat(tagset_buffer, LogTag::name(tagSet[i]), max_tagset_len - strlen(tagset_buffer)); + } + + log_warning(arguments)("-XX:%s%s is deprecated. Will use -Xlog:%s=%s instead.", + (on) ? "+" : "-", + name, + tagset_buffer, + (on) ? LogLevel::name(alf.level) : "off"); +} + +AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name, bool on){ for (size_t i = 0; aliased_logging_flags[i].alias_name != NULL; i++) { const AliasedLoggingFlag& alf = aliased_logging_flags[i]; if (strcmp(alf.alias_name, name) == 0) { + log_deprecated_flag(name, on, alf); return alf; } } - AliasedLoggingFlag a = {NULL, LogLevel::Off, false, LogTag::__NO_TAG}; + AliasedLoggingFlag a = {NULL, LogLevel::Off, false, LOG_TAGS(_NO_TAG)}; return a; } @@ -981,12 +1029,11 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { char dummy; const char* real_name; bool warn_if_deprecated = true; - AliasedLoggingFlag alf; if (sscanf(arg, "-%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) { - alf = catch_logging_aliases(name); + AliasedLoggingFlag alf = catch_logging_aliases(name, false); if (alf.alias_name != NULL){ - LogConfiguration::configure_stdout(LogLevel::Off, alf.exactMatch, alf.tag, LogTag::__NO_TAG); + LogConfiguration::configure_stdout(LogLevel::Off, alf.exactMatch, alf.tag0, alf.tag1, alf.tag2, alf.tag3, alf.tag4, alf.tag5); return true; } real_name = handle_aliases_and_deprecation(name, warn_if_deprecated); @@ -996,9 +1043,9 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { return set_bool_flag(real_name, false, origin); } if (sscanf(arg, "+%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) { - alf = catch_logging_aliases(name); + AliasedLoggingFlag alf = catch_logging_aliases(name, true); if (alf.alias_name != NULL){ - LogConfiguration::configure_stdout(alf.level, alf.exactMatch, alf.tag, LogTag::__NO_TAG); + LogConfiguration::configure_stdout(alf.level, alf.exactMatch, alf.tag0, alf.tag1, alf.tag2, alf.tag3, alf.tag4, alf.tag5); return true; } real_name = handle_aliases_and_deprecation(name, warn_if_deprecated); @@ -1202,13 +1249,23 @@ bool Arguments::process_argument(const char* arg, char stripped_argname[BUFLEN+1]; strncpy(stripped_argname, argname, arg_len); stripped_argname[arg_len] = '\0'; // strncpy may not null terminate. - if (is_obsolete_flag(stripped_argname, &since)) { char version[256]; since.to_string(version, sizeof(version)); warning("Ignoring option %s; support was removed in %s", stripped_argname, version); return true; } +#ifndef PRODUCT + else { + const char* replacement; + if ((replacement = removed_develop_logging_flag_name(stripped_argname)) != NULL){ + log_warning(arguments)("%s has been removed. Please use %s instead.", + stripped_argname, + replacement); + return false; + } + } +#endif //PRODUCT } // For locked flags, report a custom error message if available. @@ -1897,26 +1954,45 @@ void Arguments::set_conservative_max_heap_alignment() { CollectorPolicy::compute_heap_alignment()); } +bool Arguments::gc_selected() { +#if INCLUDE_ALL_GCS + return UseSerialGC || UseParallelGC || UseParallelOldGC || UseConcMarkSweepGC || UseG1GC; +#else + return UseSerialGC; +#endif // INCLUDE_ALL_GCS +} + void Arguments::select_gc_ergonomically() { +#if INCLUDE_ALL_GCS if (os::is_server_class_machine()) { if (should_auto_select_low_pause_collector()) { - FLAG_SET_ERGO(bool, UseConcMarkSweepGC, true); + FLAG_SET_ERGO_IF_DEFAULT(bool, UseConcMarkSweepGC, true); } else { #if defined(JAVASE_EMBEDDED) - FLAG_SET_ERGO(bool, UseParallelGC, true); + FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true); #else - FLAG_SET_ERGO(bool, UseG1GC, true); + FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true); #endif } } else { - FLAG_SET_ERGO(bool, UseSerialGC, true); + FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true); } +#else + UNSUPPORTED_OPTION(UseG1GC); + UNSUPPORTED_OPTION(UseParallelGC); + UNSUPPORTED_OPTION(UseParallelOldGC); + UNSUPPORTED_OPTION(UseConcMarkSweepGC); + UNSUPPORTED_OPTION(UseParNewGC); + FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true); +#endif // INCLUDE_ALL_GCS } void Arguments::select_gc() { if (!gc_selected()) { select_gc_ergonomically(); - guarantee(gc_selected(), "No GC selected"); + if (!gc_selected()) { + vm_exit_during_initialization("Garbage collector not selected (default collector explicitly disabled)", NULL); + } } } @@ -2041,16 +2117,6 @@ void Arguments::set_g1_gc_flags() { log_trace(gc)("ConcGCThreads: %u", ConcGCThreads); } -#if !INCLUDE_ALL_GCS -#ifdef ASSERT -static bool verify_serial_gc_flags() { - return (UseSerialGC && - !(UseParNewGC || (UseConcMarkSweepGC) || UseG1GC || - UseParallelGC || UseParallelOldGC)); -} -#endif // ASSERT -#endif // INCLUDE_ALL_GCS - void Arguments::set_gc_specific_flags() { #if INCLUDE_ALL_GCS // Set per-collector flags @@ -2072,8 +2138,6 @@ void Arguments::set_gc_specific_flags() { // Keeping the heap 100% free is hard ;-) so limit it to 99%. FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99); } -#else // INCLUDE_ALL_GCS - assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS } @@ -3595,9 +3659,14 @@ jint Arguments::finalize_vm_init_args(ArgumentBootClassPath* bcp_p, bool bcp_ass } #endif +#if !defined(COMPILER2) && !INCLUDE_JVMCI + UNSUPPORTED_OPTION(ProfileInterpreter); + NOT_PRODUCT(UNSUPPORTED_OPTION(TraceProfileInterpreter)); +#endif + #ifndef TIERED // Tiered compilation is undefined. - UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation"); + UNSUPPORTED_OPTION(TieredCompilation); #endif // If we are running in a headless jre, force java.awt.headless property @@ -3923,17 +3992,6 @@ void Arguments::set_shared_spaces_flags() { } } -#if !INCLUDE_ALL_GCS -static void force_serial_gc() { - FLAG_SET_DEFAULT(UseSerialGC, true); - UNSUPPORTED_GC_OPTION(UseG1GC); - UNSUPPORTED_GC_OPTION(UseParallelGC); - UNSUPPORTED_GC_OPTION(UseParallelOldGC); - UNSUPPORTED_GC_OPTION(UseConcMarkSweepGC); - UNSUPPORTED_GC_OPTION(UseParNewGC); -} -#endif // INCLUDE_ALL_GCS - // Sharing support // Construct the path to the archive static char* get_shared_archive_path() { @@ -4297,7 +4355,7 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { } #if defined(_ALLBSD_SOURCE) || defined(AIX) // UseLargePages is not yet supported on BSD and AIX. - UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); + UNSUPPORTED_OPTION(UseLargePages); #endif ArgumentsExt::report_unsupported_options(); @@ -4328,9 +4386,6 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { // Set object alignment values. set_object_alignment(); -#if !INCLUDE_ALL_GCS - force_serial_gc(); -#endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS if (DumpSharedSpaces || RequireSharedSpaces) { jio_fprintf(defaultStream::error_stream(), diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 67a9661b8ae..1dc3135aff6 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -265,7 +265,12 @@ typedef struct { const char* alias_name; LogLevelType level; bool exactMatch; - LogTagType tag; + LogTagType tag0; + LogTagType tag1; + LogTagType tag2; + LogTagType tag3; + LogTagType tag4; + LogTagType tag5; } AliasedLoggingFlag; class Arguments : AllStatic { @@ -503,6 +508,10 @@ class Arguments : AllStatic { // the version number when the flag became obsolete. static bool is_obsolete_flag(const char* flag_name, JDK_Version* version); +#ifndef PRODUCT + static const char* removed_develop_logging_flag_name(const char* name); +#endif // PRODUCT + // Returns 1 if the flag is deprecated (and not yet obsolete or expired). // In this case the 'version' buffer is filled in with the version number when // the flag became deprecated. @@ -517,7 +526,7 @@ class Arguments : AllStatic { // Return NULL if the arg has expired. static const char* handle_aliases_and_deprecation(const char* arg, bool warn); static bool lookup_logging_aliases(const char* arg, char* buffer); - static AliasedLoggingFlag catch_logging_aliases(const char* name); + static AliasedLoggingFlag catch_logging_aliases(const char* name, bool on); static short CompileOnlyClassesNum; static short CompileOnlyClassesMax; static char** CompileOnlyClasses; @@ -558,7 +567,7 @@ class Arguments : AllStatic { static jint adjust_after_os(); static void set_gc_specific_flags(); - static inline bool gc_selected(); // whether a gc has been selected + static bool gc_selected(); // whether a gc has been selected static void select_gc_ergonomically(); #if INCLUDE_JVMCI // Check consistency of jvmci vm argument settings. @@ -723,20 +732,16 @@ class Arguments : AllStatic { static void check_unsupported_dumping_properties() NOT_CDS_RETURN; }; -bool Arguments::gc_selected() { - return UseConcMarkSweepGC || UseG1GC || UseParallelGC || UseParallelOldGC || UseSerialGC; -} - // Disable options not supported in this release, with a warning if they // were explicitly requested on the command-line -#define UNSUPPORTED_OPTION(opt, description) \ -do { \ - if (opt) { \ - if (FLAG_IS_CMDLINE(opt)) { \ - warning(description " is disabled in this release."); \ - } \ - FLAG_SET_DEFAULT(opt, false); \ - } \ +#define UNSUPPORTED_OPTION(opt) \ +do { \ + if (opt) { \ + if (FLAG_IS_CMDLINE(opt)) { \ + warning("-XX:+" #opt " not supported in this VM"); \ + } \ + FLAG_SET_DEFAULT(opt, false); \ + } \ } while(0) #endif // SHARE_VM_RUNTIME_ARGUMENTS_HPP diff --git a/hotspot/src/share/vm/runtime/biasedLocking.cpp b/hotspot/src/share/vm/runtime/biasedLocking.cpp index 1be0d111e56..1d5fd538b8d 100644 --- a/hotspot/src/share/vm/runtime/biasedLocking.cpp +++ b/hotspot/src/share/vm/runtime/biasedLocking.cpp @@ -149,9 +149,13 @@ static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_ if (!mark->has_bias_pattern()) { if (log_is_enabled(Info, biasedlocking)) { ResourceMark rm; - log_info(biasedlocking)(" (Skipping revocation of object of type %s " - "because it's no longer biased)", - obj->klass()->external_name()); + log_info(biasedlocking)(" (Skipping revocation of object " INTPTR_FORMAT + ", mark " INTPTR_FORMAT ", type %s" + ", requesting thread " INTPTR_FORMAT + " because it's no longer biased)", + p2i((void *)obj), (intptr_t) mark, + obj->klass()->external_name(), + (intptr_t) requesting_thread); } return BiasedLocking::NOT_BIASED; } @@ -163,9 +167,9 @@ static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_ // Log at "info" level if not bulk, else "trace" level if (!is_bulk) { ResourceMark rm; - log_info(biasedlocking)("Revoking bias of object " INTPTR_FORMAT " , mark " - INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT - " , allow rebias %d , requesting thread " INTPTR_FORMAT, + log_info(biasedlocking)("Revoking bias of object " INTPTR_FORMAT ", mark " + INTPTR_FORMAT ", type %s, prototype header " INTPTR_FORMAT + ", allow rebias %d, requesting thread " INTPTR_FORMAT, p2i((void *)obj), (intptr_t) mark, obj->klass()->external_name(), @@ -222,13 +226,24 @@ static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_ } // Log at "info" level if not bulk, else "trace" level if (!is_bulk) { - log_info(biasedlocking)(" Revoked bias of object biased toward dead thread"); + log_info(biasedlocking)(" Revoked bias of object biased toward dead thread (" + PTR_FORMAT ")", p2i(biased_thread)); } else { - log_trace(biasedlocking)(" Revoked bias of object biased toward dead thread"); + log_trace(biasedlocking)(" Revoked bias of object biased toward dead thread (" + PTR_FORMAT ")", p2i(biased_thread)); } return BiasedLocking::BIAS_REVOKED; } + // Log at "info" level if not bulk, else "trace" level + if (!is_bulk) { + log_info(biasedlocking)(" Revoked bias of object biased toward live thread (" + PTR_FORMAT ")", p2i(biased_thread)); + } else { + log_trace(biasedlocking)(" Revoked bias of object biased toward live thread (" + PTR_FORMAT ")", p2i(biased_thread)); + } + // Thread owning bias is alive. // Check to see whether it currently owns the lock and, if so, // write down the needed displaced headers to the thread's stack. diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 2f96660c260..2e0139c39e5 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -290,13 +290,11 @@ void CommandLineFlagConstraintList::init(void) { #endif // INCLUDE_ALL_GCS } -// Find constraints by name and return only if found constraint's type is equal or lower than current validating type. -CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { +CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) { CommandLineFlagConstraint* found = NULL; for (int i=0; iname(), name) == 0) && - (constraint->type() <= _validating_type)) { + if (strcmp(constraint->name(), name) == 0) { found = constraint; break; } @@ -304,6 +302,16 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(co return found; } +// Find constraints by name and return only if found constraint's type is equal or lower than current validating type. +CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { + CommandLineFlagConstraint* found = NULL; + CommandLineFlagConstraint* constraint = find(name); + if (constraint && (constraint->type() <= _validating_type)) { + found = constraint; + } + return found; +} + // Check constraints for specific constraint type. bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { guarantee(type > _validating_type, "Constraint check is out of order."); diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp index 120dfff1d64..5affa729c34 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,6 +89,7 @@ public: static void init(); static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } + static CommandLineFlagConstraint* find(const char* name); static CommandLineFlagConstraint* find_if_needs_check(const char* name); static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); } // True if 'AfterErgo' or later constraint functions are validated. diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp index 800de003aad..4390644d708 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorPolicy.hpp" +#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsGC.hpp" @@ -35,6 +36,7 @@ #include "utilities/defaultStream.hpp" #if INCLUDE_ALL_GCS +#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/g1/g1_globals.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" #include "gc/shared/plab.hpp" @@ -113,7 +115,7 @@ Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS - if ((UseConcMarkSweepGC || UseG1GC) && (value < PLAB::min_size())) { + if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", @@ -126,7 +128,7 @@ static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbos static Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS - if ((UseConcMarkSweepGC || UseG1GC) && (value > PLAB::max_size())) { + if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", @@ -381,6 +383,39 @@ Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { return Flag::SUCCESS; } +Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + // ParGCCardsPerStrideChunk should be compared with card table size. + size_t heap_size = Universe::heap()->reserved_region().word_size(); + CardTableModRefBS* bs = (CardTableModRefBS*)GenCollectedHeap::heap()->rem_set()->bs(); + size_t card_table_size = bs->cards_required(heap_size) - 1; // Valid card table size + + if ((size_t)value > card_table_size) { + CommandLineError::print(verbose, + "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and " + "must be less than or equal to card table size (" SIZE_FORMAT ")\n", + value, card_table_size); + return Flag::VIOLATES_CONSTRAINT; + } + + // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread) + // from CardTableModRefBSForCTRS::process_stride(). Note that ParGCStridesPerThread is already checked + // not to make an overflow with ParallelGCThreads from its constraint function. + uintx n_strides = ParallelGCThreads * ParGCStridesPerThread; + uintx ergo_max = max_uintx / n_strides; + if ((uintx)value > ergo_max) { + CommandLineError::print(verbose, + "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be " + "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", + value, ergo_max); + return Flag::VIOLATES_CONSTRAINT; + } + } +#endif + return Flag::SUCCESS; +} + Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { Flag::Error status = Flag::SUCCESS; @@ -448,6 +483,22 @@ Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { return Flag::SUCCESS; } +Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity(); + if (value > max_uintx - max_capacity) { + CommandLineError::print(verbose, + "CMSSamplingGrain (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n", + value, max_uintx - max_capacity); + return Flag::VIOLATES_CONSTRAINT; + } + } +#endif + return Flag::SUCCESS; +} + Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { @@ -457,6 +508,27 @@ Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) return Flag::SUCCESS; } +Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { +#if INCLUDE_ALL_GCS + // Skip for current default value. + if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) { + // CMSBitMapYieldQuantum should be compared with mark bitmap size. + ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen(); + size_t bitmap_size = cms->collector()->markBitMap()->sizeInWords(); + + if (value > bitmap_size) { + CommandLineError::print(verbose, + "CMSBitMapYieldQuantum (" SIZE_FORMAT ") must " + "be less than or equal to bitmap size (" SIZE_FORMAT ") " + "whose size corresponds to the size of old generation of the Java heap\n", + value, bitmap_size); + return Flag::VIOLATES_CONSTRAINT; + } + } +#endif + return Flag::SUCCESS; +} + Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { @@ -589,9 +661,15 @@ Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; } + if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { + CommandLineError::print(verbose, + "MinTLABSize (" SIZE_FORMAT ") must be " + "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n", + value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; } Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp index e4f8472e0a3..ee8bf3f668b 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,12 +56,15 @@ Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); #endif // INCLUDE_ALL_GCS Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); +Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); +Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp index a34896c49aa..abcf73ca3a7 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,3 +130,36 @@ Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { return Flag::SUCCESS; } } + +static inline Flag::Error sharedConstraintFunc(const char *name, size_t value, size_t taken, bool verbose) { + size_t available = (MAX_SHARED_DELTA-(taken+SHARED_PAGE)); + if (value > available) { + CommandLineError::print(verbose, + "%s (" SIZE_FORMAT ") must be " + "smaller than or equal to (" SIZE_FORMAT ")\n", + name, value, available); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error SharedReadWriteSizeConstraintFunc(size_t value, bool verbose) { + size_t taken = (SharedReadOnlySize+SharedMiscDataSize+SharedMiscCodeSize); + return sharedConstraintFunc("SharedReadWriteSize", value, taken, verbose); +} + +Flag::Error SharedReadOnlySizeConstraintFunc(size_t value, bool verbose) { + size_t taken = (SharedReadWriteSize+SharedMiscDataSize+SharedMiscCodeSize); + return sharedConstraintFunc("SharedReadOnlySize", value, taken, verbose); +} + +Flag::Error SharedMiscDataSizeConstraintFunc(size_t value, bool verbose) { + size_t taken = (SharedReadWriteSize+SharedReadOnlySize+SharedMiscCodeSize); + return sharedConstraintFunc("SharedMiscDataSize", value, taken, verbose); +} + +Flag::Error SharedMiscCodeSizeConstraintFunc(size_t value, bool verbose) { + size_t taken = (SharedReadWriteSize+SharedReadOnlySize+SharedMiscDataSize); + return sharedConstraintFunc("SharedMiscCodeSize", value, taken, verbose); +} diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp index 788b3b0dc75..3bfb2825b74 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,4 +45,9 @@ Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); +Flag::Error SharedReadWriteSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SharedReadOnlySizeConstraintFunc(size_t value, bool verbose); +Flag::Error SharedMiscDataSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SharedMiscCodeSizeConstraintFunc(size_t value, bool verbose); + #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */ diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp index 01a523f74c5..2af4847d67a 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp @@ -27,6 +27,7 @@ #include "classfile/symbolTable.hpp" #include "gc/shared/referenceProcessor.hpp" #include "runtime/arguments.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" @@ -378,12 +379,18 @@ CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { return found; } -void CommandLineFlagRangeList::print(const char* name, outputStream* st, bool unspecified) { +void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); if (range != NULL) { range->print(st); - } else if (unspecified == true) { - st->print("[ ... ]"); + } else { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + if (constraint != NULL) { + assert(default_range_str_func!=NULL, "default_range_str_func must be provided"); + st->print("%s", default_range_str_func()); + } else { + st->print("[ ... ]"); + } } } diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp index a6777524890..4b2c1ea7caa 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ public: static CommandLineFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } static CommandLineFlagRange* find(const char* name); static void add(CommandLineFlagRange* range) { _ranges->append(range); } - static void print(const char* name, outputStream* st, bool unspecified = false); + static void print(outputStream* st, const char* name, RangeStrFunc default_range_str_func); // Check the final values of all flags for ranges. static bool check_ranges(); }; diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.cpp b/hotspot/src/share/vm/runtime/compilationPolicy.cpp index aa0333968e7..3538f3d17a1 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" diff --git a/hotspot/src/share/vm/runtime/fieldType.cpp b/hotspot/src/share/vm/runtime/fieldType.cpp index ef929b9c559..c00433b974e 100644 --- a/hotspot/src/share/vm/runtime/fieldType.cpp +++ b/hotspot/src/share/vm/runtime/fieldType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayKlass.hpp" #include "runtime/fieldType.hpp" diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index fc687618e03..e5785c1f11e 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -29,6 +29,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index ade6900975b..1728da3e857 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -84,6 +84,56 @@ ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_FLAGS_EXT +#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 +static char* create_range_str(const char *fmt, ...) { + static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; + static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); + + int size_needed = 0; + do { + va_list args; + va_start(args, fmt); + size_needed = jio_vsnprintf(range_string, string_length, fmt, args); + va_end(args); + + if (size_needed < 0) { + string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; + range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); + guarantee(range_string != NULL, "create_range_str string should not be NULL"); + } + } while (size_needed < 0); + + return range_string; +} + +const char* Flag::get_int_default_range_str() { + return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); +} + +const char* Flag::get_uint_default_range_str() { + return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); +} + +const char* Flag::get_intx_default_range_str() { + return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); +} + +const char* Flag::get_uintx_default_range_str() { + return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); +} + +const char* Flag::get_uint64_t_default_range_str() { + return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); +} + +const char* Flag::get_size_t_default_range_str() { + return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); +} + +const char* Flag::get_double_default_range_str() { + return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); +} + static bool is_product_build() { #ifdef PRODUCT return true; @@ -405,7 +455,25 @@ void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { } else if (!is_bool() && !is_ccstr()) { st->print("%9s %-50s ", _type, _name); - CommandLineFlagRangeList::print(_name, st, true); + RangeStrFunc func = NULL; + if (is_int()) { + func = Flag::get_int_default_range_str; + } else if (is_uint()) { + func = Flag::get_uint_default_range_str; + } else if (is_intx()) { + func = Flag::get_intx_default_range_str; + } else if (is_uintx()) { + func = Flag::get_uintx_default_range_str; + } else if (is_uint64_t()) { + func = Flag::get_uint64_t_default_range_str; + } else if (is_size_t()) { + func = Flag::get_size_t_default_range_str; + } else if (is_double()) { + func = Flag::get_double_default_range_str; + } else { + ShouldNotReachHere(); + } + CommandLineFlagRangeList::print(st, _name, func); st->print(" %-20s", " "); print_kind(st); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 2dfa4965849..a5b73c81d90 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -224,6 +224,9 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); typedef const char* ccstr; typedef const char* ccstrlist; // represents string arguments which accumulate +// function type that will construct default range string +typedef const char* (*RangeStrFunc)(void); + struct Flag { enum Flags { // value origin @@ -305,6 +308,14 @@ struct Flag { static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); + static const char* get_int_default_range_str(); + static const char* get_uint_default_range_str(); + static const char* get_intx_default_range_str(); + static const char* get_uintx_default_range_str(); + static const char* get_uint64_t_default_range_str(); + static const char* get_size_t_default_range_str(); + static const char* get_double_default_range_str(); + void check_writable(); bool is_bool() const; @@ -727,7 +738,7 @@ public: "Control whether SHA instructions can be used " \ "on SPARC, on ARM and on x86") \ \ - diagnostic(bool, UseGHASHIntrinsics, false, \ + product(bool, UseGHASHIntrinsics, false, \ "Use intrinsics for GHASH versions of crypto") \ \ product(size_t, LargePageSizeInBytes, 0, \ @@ -797,27 +808,27 @@ public: product(bool, UseInlineCaches, true, \ "Use Inline Caches for virtual calls ") \ \ - diagnostic(bool, InlineArrayCopy, true, \ + develop(bool, InlineArrayCopy, true, \ "Inline arraycopy native that is known to be part of " \ "base library DLL") \ \ - diagnostic(bool, InlineObjectHash, true, \ + develop(bool, InlineObjectHash, true, \ "Inline Object::hashCode() native that is known to be part " \ "of base library DLL") \ \ - diagnostic(bool, InlineNatives, true, \ + develop(bool, InlineNatives, true, \ "Inline natives that are known to be part of base library DLL") \ \ - diagnostic(bool, InlineMathNatives, true, \ + develop(bool, InlineMathNatives, true, \ "Inline SinD, CosD, etc.") \ \ - diagnostic(bool, InlineClassNatives, true, \ + develop(bool, InlineClassNatives, true, \ "Inline Class.isInstance, etc") \ \ - diagnostic(bool, InlineThreadNatives, true, \ + develop(bool, InlineThreadNatives, true, \ "Inline Thread.currentThread, etc") \ \ - diagnostic(bool, InlineUnsafeOps, true, \ + develop(bool, InlineUnsafeOps, true, \ "Inline memory ops (native methods) from Unsafe") \ \ product(bool, CriticalJNINatives, true, \ @@ -826,34 +837,34 @@ public: notproduct(bool, StressCriticalJNINatives, false, \ "Exercise register saving code in critical natives") \ \ - diagnostic(bool, UseAESIntrinsics, false, \ + product(bool, UseAESIntrinsics, false, \ "Use intrinsics for AES versions of crypto") \ \ - diagnostic(bool, UseAESCTRIntrinsics, false, \ + product(bool, UseAESCTRIntrinsics, false, \ "Use intrinsics for the paralleled version of AES/CTR crypto") \ \ - diagnostic(bool, UseSHA1Intrinsics, false, \ + product(bool, UseSHA1Intrinsics, false, \ "Use intrinsics for SHA-1 crypto hash function. " \ "Requires that UseSHA is enabled.") \ \ - diagnostic(bool, UseSHA256Intrinsics, false, \ + product(bool, UseSHA256Intrinsics, false, \ "Use intrinsics for SHA-224 and SHA-256 crypto hash functions. " \ "Requires that UseSHA is enabled.") \ \ - diagnostic(bool, UseSHA512Intrinsics, false, \ + product(bool, UseSHA512Intrinsics, false, \ "Use intrinsics for SHA-384 and SHA-512 crypto hash functions. " \ "Requires that UseSHA is enabled.") \ \ - diagnostic(bool, UseCRC32Intrinsics, false, \ + product(bool, UseCRC32Intrinsics, false, \ "use intrinsics for java.util.zip.CRC32") \ \ - diagnostic(bool, UseCRC32CIntrinsics, false, \ + product(bool, UseCRC32CIntrinsics, false, \ "use intrinsics for java.util.zip.CRC32C") \ \ - diagnostic(bool, UseAdler32Intrinsics, false, \ + product(bool, UseAdler32Intrinsics, false, \ "use intrinsics for java.util.zip.Adler32") \ \ - diagnostic(bool, UseVectorizedMismatchIntrinsic, false, \ + product(bool, UseVectorizedMismatchIntrinsic, false, \ "Enables intrinsification of ArraysSupport.vectorizedMismatch()") \ \ diagnostic(ccstrlist, DisableIntrinsic, "", \ @@ -951,9 +962,6 @@ public: notproduct(bool, PrintMallocFree, false, \ "Trace calls to C heap malloc/free allocation") \ \ - product(bool, PrintOopAddress, false, \ - "Always print the location of the oop") \ - \ notproduct(bool, VerifyCodeCache, false, \ "Verify code cache on memory allocation/deallocation") \ \ @@ -990,9 +998,6 @@ public: develop(bool, PrintVMMessages, true, \ "Print VM messages on console") \ \ - diagnostic(bool, VerboseVerification, false, \ - "Display detailed verification details") \ - \ notproduct(uintx, ErrorHandlerTest, 0, \ "If > 0, provokes an error after VM initialization; the value " \ "determines which error to provoke. See test_error_handler() " \ @@ -1052,9 +1057,6 @@ public: "directory) of the dump file (defaults to java_pid.hprof " \ "in the working directory)") \ \ - develop(size_t, HeapDumpSegmentSize, 1*G, \ - "Approximate segment size when generating a segmented heap dump") \ - \ develop(bool, BreakAtWarning, false, \ "Execute breakpoint upon encountering VM warning") \ \ @@ -1460,9 +1462,6 @@ public: develop(bool, TimeOopMap2, false, \ "Time calls to GenerateOopMap::compute_map() individually") \ \ - develop(bool, TraceMonitorMismatch, false, \ - "Trace monitor matching failures during OopMapGeneration") \ - \ develop(bool, TraceOopMapRewrites, false, \ "Trace rewriting of method oops during oop map generation") \ \ @@ -1472,9 +1471,6 @@ public: develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - develop(bool, TraceClearedExceptions, false, \ - "Print when an exception is forcibly cleared") \ - \ /* gc */ \ \ product(bool, UseSerialGC, false, \ @@ -1633,6 +1629,7 @@ public: "The number of cards in each chunk of the parallel chunks used " \ "during card table scanning") \ range(1, max_intx) \ + constraint(ParGCCardsPerStrideChunkConstraintFunc,AfterMemoryInit)\ \ product(uintx, OldPLABWeight, 50, \ "Percentage (0-100) used to weight the current sample when " \ @@ -1904,7 +1901,8 @@ public: \ product(uintx, CMSSamplingGrain, 16*K, \ "The minimum distance between eden samples for CMS (see above)") \ - range(1, max_uintx) \ + range(ObjectAlignmentInBytes, max_uintx) \ + constraint(CMSSamplingGrainConstraintFunc,AfterMemoryInit) \ \ product(bool, CMSScavengeBeforeRemark, false, \ "Attempt scavenge before the CMS remark step") \ @@ -1929,6 +1927,7 @@ public: "Bitmap operations should process at most this many bits " \ "between yields") \ range(1, max_uintx) \ + constraint(CMSBitMapYieldQuantumConstraintFunc,AfterMemoryInit) \ \ product(bool, CMSPrintChunksInDump, false, \ "If logging for the \"gc\" and \"promotion\" tags is enabled on" \ @@ -2067,9 +2066,6 @@ public: develop(uintx, MetadataAllocationFailALotInterval, 1000, \ "Metadata allocation failure a lot interval") \ \ - develop(bool, TraceMetadataChunkAllocation, false, \ - "Trace chunk metadata allocations") \ - \ notproduct(bool, ExecuteInternalVMTests, false, \ "Enable execution of internal VM tests") \ \ @@ -2223,10 +2219,10 @@ public: "Decay factor to TenuredGenerationSizeIncrement") \ range(1, max_uintx) \ \ - product(uintx, MaxGCPauseMillis, max_uintx, \ + product(uintx, MaxGCPauseMillis, max_uintx - 1, \ "Adaptive size policy maximum GC pause time goal in millisecond, "\ "or (G1 Only) the maximum GC time per MMU time slice") \ - range(1, max_uintx) \ + range(1, max_uintx - 1) \ constraint(MaxGCPauseMillisConstraintFunc,AfterMemoryInit) \ \ product(uintx, GCPauseIntervalMillis, 0, \ @@ -2390,12 +2386,6 @@ public: product(bool, IgnoreEmptyClassPaths, false, \ "Ignore empty path elements in -classpath") \ \ - product(bool, TraceClassLoadingPreorder, false, \ - "Trace all classes loaded in order referenced (not loaded)") \ - \ - product_rw(bool, TraceLoaderConstraints, false, \ - "Trace loader constraints") \ - \ product(size_t, InitialBootClassLoaderMetaspaceSize, \ NOT_LP64(2200*K) LP64_ONLY(4*M), \ "Initial size of the boot class loader data metaspace") \ @@ -2414,18 +2404,12 @@ public: manageable(bool, PrintClassHistogram, false, \ "Print a histogram of class instances") \ \ - develop(bool, TraceWorkGang, false, \ - "Trace activities of work gangs") \ - \ develop(bool, TraceGCTaskManager, false, \ "Trace actions of the GC task manager") \ \ develop(bool, TraceGCTaskQueue, false, \ "Trace actions of the GC task queues") \ \ - diagnostic(bool, TraceGCTaskThread, false, \ - "Trace actions of the GC task threads") \ - \ develop(bool, TraceParallelOldGCMarkingPhase, false, \ "Trace marking phase in ParallelOldGC") \ \ @@ -2516,9 +2500,6 @@ public: "generate locking/unlocking code for synchronized methods and " \ "monitors") \ \ - develop(bool, GenerateCompilerNullChecks, true, \ - "Generate explicit null checks for loads/stores/calls") \ - \ develop(bool, GenerateRangeChecks, true, \ "Generate range checks for array accesses") \ \ @@ -2545,10 +2526,6 @@ public: LP64_ONLY(range(-1, max_intx/MICROUNITS)) \ NOT_LP64(range(-1, max_intx)) \ \ - product(bool, TraceSafepointCleanupTime, false, \ - "Print the break down of clean up tasks performed during " \ - "safepoint") \ - \ product(bool, Inline, true, \ "Enable inlining") \ \ @@ -2780,10 +2757,6 @@ public: "Produce histogram of IC misses") \ \ /* interpreter */ \ - develop(bool, ClearInterpreterLocals, false, \ - "Always clear local variables of interpreter activations upon " \ - "entry") \ - \ product_pd(bool, RewriteBytecodes, \ "Allow rewriting of bytecodes (bytecodes are not immutable)") \ \ @@ -3267,7 +3240,8 @@ public: range(0, max_uintx) \ \ product_pd(size_t, MetaspaceSize, \ - "Initial size of Metaspaces (in bytes)") \ + "Initial threshold (in bytes) at which a garbage collection " \ + "is done to reduce Metaspace usage") \ constraint(MetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxMetaspaceSize, max_uintx, \ @@ -3293,6 +3267,11 @@ public: range(0, 100) \ constraint(MaxHeapFreeRatioConstraintFunc,AfterErgo) \ \ + product(bool, ShrinkHeapInSteps, true, \ + "When disabled, informs the GC to shrink the java heap directly" \ + " to the target size at the next full GC rather than requiring" \ + " smaller steps during multiple full GCs.") \ + \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ range(0, max_intx) \ @@ -3986,18 +3965,22 @@ public: product(size_t, SharedReadWriteSize, DEFAULT_SHARED_READ_WRITE_SIZE, \ "Size of read-write space for metadata (in bytes)") \ range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE) \ + constraint(SharedReadWriteSizeConstraintFunc,AfterErgo) \ \ product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE, \ "Size of read-only space for metadata (in bytes)") \ range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE) \ + constraint(SharedReadOnlySizeConstraintFunc,AfterErgo) \ \ product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE, \ "Size of the shared miscellaneous data area (in bytes)") \ range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE) \ + constraint(SharedMiscDataSizeConstraintFunc,AfterErgo) \ \ product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE, \ "Size of the shared miscellaneous code area (in bytes)") \ range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE) \ + constraint(SharedMiscCodeSizeConstraintFunc,AfterErgo) \ \ product(size_t, SharedBaseAddress, LP64_ONLY(32*G) \ NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \ diff --git a/hotspot/src/share/vm/runtime/globals_extension.hpp b/hotspot/src/share/vm/runtime/globals_extension.hpp index 55247dcad22..45830e56623 100644 --- a/hotspot/src/share/vm/runtime/globals_extension.hpp +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -290,6 +290,12 @@ typedef enum { #define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::COMMAND_LINE)) #define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::ERGONOMIC)) +#define FLAG_SET_ERGO_IF_DEFAULT(type, name, value) \ + do { \ + if (FLAG_IS_DEFAULT(name)) { \ + FLAG_SET_ERGO(type, name, value); \ + } \ + } while (0) // Can't put the following in CommandLineFlags because // of a circular dependency on the enum definition. diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index f4b7d128046..64313d825e1 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -47,6 +47,7 @@ void eventlog_init(); void mutex_init(); void chunkpool_init(); void perfMemory_init(); +void SuspendibleThreadSet_init() NOT_ALL_GCS_RETURN; // Initialization done by Java thread in init_globals() void management_init(); @@ -93,6 +94,7 @@ void vm_init_globals() { mutex_init(); chunkpool_init(); perfMemory_init(); + SuspendibleThreadSet_init(); } diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index a30acc9a9bd..c84153a9157 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -37,6 +37,7 @@ #endif #include "logging/log.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" #include "oops/generateOopMap.hpp" @@ -465,7 +466,7 @@ void before_exit(JavaThread* thread) { Universe::heap()->stop(); // Print GC/heap related information. - LogHandle(gc, heap, exit) log; + Log(gc, heap, exit) log; if (log.is_info()) { ResourceMark rm; Universe::print_on(log.info_stream()); diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 3d44d322a4c..679ade0eaca 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "logging/log.hpp" +#include "memory/iterator.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/jniHandles.hpp" @@ -128,6 +129,12 @@ void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { } +void JNIHandles::weak_oops_do(OopClosure* f) { + AlwaysTrueClosure always_true; + weak_oops_do(&always_true, f); +} + + void JNIHandles::initialize() { _global_handles = JNIHandleBlock::allocate_block(); _weak_global_handles = JNIHandleBlock::allocate_block(); @@ -185,11 +192,6 @@ long JNIHandles::weak_global_handle_memory_usage() { } -class AlwaysAliveClosure: public BoolObjectClosure { -public: - bool do_object_b(oop obj) { return true; } -}; - class CountHandleClosure: public OopClosure { private: int _count; @@ -211,9 +213,8 @@ void JNIHandles::print_on(outputStream* st) { "JNIHandles not initialized"); CountHandleClosure global_handle_count; - AlwaysAliveClosure always_alive; oops_do(&global_handle_count); - weak_oops_do(&always_alive, &global_handle_count); + weak_oops_do(&global_handle_count); st->print_cr("JNI global references: %d", global_handle_count.count()); st->cr(); @@ -230,10 +231,9 @@ public: void JNIHandles::verify() { VerifyHandleClosure verify_handle; - AlwaysAliveClosure always_alive; oops_do(&verify_handle); - weak_oops_do(&always_alive, &verify_handle); + weak_oops_do(&verify_handle); } diff --git a/hotspot/src/share/vm/runtime/jniHandles.hpp b/hotspot/src/share/vm/runtime/jniHandles.hpp index 7a39655bfae..1503a3696b6 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.hpp +++ b/hotspot/src/share/vm/runtime/jniHandles.hpp @@ -86,6 +86,8 @@ class JNIHandles : AllStatic { static void oops_do(OopClosure* f); // Traversal of weak global handles. Unreachable oops are cleared. static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f); + // Traversal of weak global handles. + static void weak_oops_do(OopClosure* f); }; diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 7066ae21c1d..1a3767c003c 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -70,7 +70,6 @@ Monitor* SerializePage_lock = NULL; Monitor* Threads_lock = NULL; Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; -Monitor* SLT_lock = NULL; Monitor* FullGCCount_lock = NULL; Mutex* SATB_Q_FL_lock = NULL; Monitor* SATB_Q_CBL_mon = NULL; @@ -242,9 +241,6 @@ void mutex_init() { def(JNIGlobalHandle_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always); // locks JNIHandleBlockFreeList_lock def(JNICritical_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions def(AdapterHandlerLibrary_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always); - if (UseConcMarkSweepGC) { - def(SLT_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // used in CMS GC for locking PLL lock - } def(Heap_lock , Monitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes); def(JfieldIdCreation_lock , Mutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index f60329725cd..014ffb28218 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -65,7 +65,6 @@ extern Monitor* Threads_lock; // a lock on the Threads table extern Monitor* CGC_lock; // used for coordination between // fore- & background GC threads. extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. -extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc extern Mutex* SATB_Q_FL_lock; // Protects SATB Q // buffer free list. diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp index 6258d64ad2f..2cd401b4069 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp @@ -44,14 +44,6 @@ #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" -#if defined(__GNUC__) && !defined(IA64) && !defined(PPC64) -// Need to inhibit inlining for older versions of GCC to avoid build-time failures - #define NOINLINE __attribute__((noinline)) -#else - #define NOINLINE -#endif - - #ifdef DTRACE_ENABLED // Only bother with this argument setup if dtrace is available @@ -254,7 +246,7 @@ static volatile int InitDone = 0; // ----------------------------------------------------------------------------- // Enter support -void NOINLINE ObjectMonitor::enter(TRAPS) { +void ObjectMonitor::enter(TRAPS) { // The following code is ordered to check the most common cases first // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors. Thread * const Self = THREAD; @@ -431,7 +423,7 @@ int ObjectMonitor::TryLock(Thread * Self) { #define MAX_RECHECK_INTERVAL 1000 -void NOINLINE ObjectMonitor::EnterI(TRAPS) { +void ObjectMonitor::EnterI(TRAPS) { Thread * const Self = THREAD; assert(Self->is_Java_thread(), "invariant"); assert(((JavaThread *) Self)->thread_state() == _thread_blocked, "invariant"); @@ -681,7 +673,7 @@ void NOINLINE ObjectMonitor::EnterI(TRAPS) { // Knob_Reset and Knob_SpinAfterFutile support and restructuring the // loop accordingly. -void NOINLINE ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) { +void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) { assert(Self != NULL, "invariant"); assert(SelfNode != NULL, "invariant"); assert(SelfNode->_thread == Self, "invariant"); @@ -858,7 +850,7 @@ void ObjectMonitor::UnlinkAfterAcquire(Thread *Self, ObjectWaiter *SelfNode) { // ~~~~~~~~ // ::exit() uses a canonical 1-1 idiom with a MEMBAR although some of // the fast-path operators have been optimized so the common ::exit() -// operation is 1-0. See i486.ad fast_unlock(), for instance. +// operation is 1-0, e.g., see macroAssembler_x86.cpp: fast_unlock(). // The code emitted by fast_unlock() elides the usual MEMBAR. This // greatly improves latency -- MEMBAR and CAS having considerable local // latency on modern processors -- but at the cost of "stranding". Absent the @@ -871,7 +863,7 @@ void ObjectMonitor::UnlinkAfterAcquire(Thread *Self, ObjectWaiter *SelfNode) { // // The CAS() in enter provides for safety and exclusion, while the CAS or // MEMBAR in exit provides for progress and avoids stranding. 1-0 locking -// eliminates the CAS/MEMBAR from the exist path, but it admits stranding. +// eliminates the CAS/MEMBAR from the exit path, but it admits stranding. // We detect and recover from stranding with timers. // // If a thread transiently strands it'll park until (a) another @@ -894,7 +886,7 @@ void ObjectMonitor::UnlinkAfterAcquire(Thread *Self, ObjectWaiter *SelfNode) { // structured the code so the windows are short and the frequency // of such futile wakups is low. -void NOINLINE ObjectMonitor::exit(bool not_suspended, TRAPS) { +void ObjectMonitor::exit(bool not_suspended, TRAPS) { Thread * const Self = THREAD; if (THREAD != _owner) { if (THREAD->is_lock_owned((address) _owner)) { @@ -944,7 +936,6 @@ void NOINLINE ObjectMonitor::exit(bool not_suspended, TRAPS) { for (;;) { assert(THREAD == _owner, "invariant"); - if (Knob_ExitPolicy == 0) { // release semantics: prior loads and stores from within the critical section // must not float (reorder) past the following store that drops the lock. diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 016b6e3d84f..1644e43eb0e 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -37,6 +37,7 @@ #ifdef ASSERT #include "memory/guardedMemory.hpp" #endif +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "prims/jvm.h" #include "prims/jvm_misc.hpp" @@ -61,6 +62,7 @@ #include "utilities/events.hpp" # include +# include OSThread* os::_starting_thread = NULL; address os::_polling_page = NULL; @@ -1282,8 +1284,8 @@ void os::set_memory_serialize_page(address page) { _mem_serialize_page = (volatile int32_t *)page; // We initialize the serialization page shift count here // We assume a cache line size of 64 bytes - assert(SerializePageShiftCount == count, - "thread size changed, fix SerializePageShiftCount constant"); + assert(SerializePageShiftCount == count, "JavaThread size changed; " + "SerializePageShiftCount constant should be %d", count); set_serialize_page_mask((uintptr_t)(vm_page_size() - sizeof(int32_t))); } @@ -1367,6 +1369,131 @@ size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) return page_size_for_region(region_size, min_pages, false); } +static const char* errno_to_string (int e, bool short_text) { + #define ALL_SHARED_ENUMS(X) \ + X(E2BIG, "Argument list too long") \ + X(EACCES, "Permission denied") \ + X(EADDRINUSE, "Address in use") \ + X(EADDRNOTAVAIL, "Address not available") \ + X(EAFNOSUPPORT, "Address family not supported") \ + X(EAGAIN, "Resource unavailable, try again") \ + X(EALREADY, "Connection already in progress") \ + X(EBADF, "Bad file descriptor") \ + X(EBADMSG, "Bad message") \ + X(EBUSY, "Device or resource busy") \ + X(ECANCELED, "Operation canceled") \ + X(ECHILD, "No child processes") \ + X(ECONNABORTED, "Connection aborted") \ + X(ECONNREFUSED, "Connection refused") \ + X(ECONNRESET, "Connection reset") \ + X(EDEADLK, "Resource deadlock would occur") \ + X(EDESTADDRREQ, "Destination address required") \ + X(EDOM, "Mathematics argument out of domain of function") \ + X(EEXIST, "File exists") \ + X(EFAULT, "Bad address") \ + X(EFBIG, "File too large") \ + X(EHOSTUNREACH, "Host is unreachable") \ + X(EIDRM, "Identifier removed") \ + X(EILSEQ, "Illegal byte sequence") \ + X(EINPROGRESS, "Operation in progress") \ + X(EINTR, "Interrupted function") \ + X(EINVAL, "Invalid argument") \ + X(EIO, "I/O error") \ + X(EISCONN, "Socket is connected") \ + X(EISDIR, "Is a directory") \ + X(ELOOP, "Too many levels of symbolic links") \ + X(EMFILE, "Too many open files") \ + X(EMLINK, "Too many links") \ + X(EMSGSIZE, "Message too large") \ + X(ENAMETOOLONG, "Filename too long") \ + X(ENETDOWN, "Network is down") \ + X(ENETRESET, "Connection aborted by network") \ + X(ENETUNREACH, "Network unreachable") \ + X(ENFILE, "Too many files open in system") \ + X(ENOBUFS, "No buffer space available") \ + X(ENODATA, "No message is available on the STREAM head read queue") \ + X(ENODEV, "No such device") \ + X(ENOENT, "No such file or directory") \ + X(ENOEXEC, "Executable file format error") \ + X(ENOLCK, "No locks available") \ + X(ENOLINK, "Reserved") \ + X(ENOMEM, "Not enough space") \ + X(ENOMSG, "No message of the desired type") \ + X(ENOPROTOOPT, "Protocol not available") \ + X(ENOSPC, "No space left on device") \ + X(ENOSR, "No STREAM resources") \ + X(ENOSTR, "Not a STREAM") \ + X(ENOSYS, "Function not supported") \ + X(ENOTCONN, "The socket is not connected") \ + X(ENOTDIR, "Not a directory") \ + X(ENOTEMPTY, "Directory not empty") \ + X(ENOTSOCK, "Not a socket") \ + X(ENOTSUP, "Not supported") \ + X(ENOTTY, "Inappropriate I/O control operation") \ + X(ENXIO, "No such device or address") \ + X(EOPNOTSUPP, "Operation not supported on socket") \ + X(EOVERFLOW, "Value too large to be stored in data type") \ + X(EPERM, "Operation not permitted") \ + X(EPIPE, "Broken pipe") \ + X(EPROTO, "Protocol error") \ + X(EPROTONOSUPPORT, "Protocol not supported") \ + X(EPROTOTYPE, "Protocol wrong type for socket") \ + X(ERANGE, "Result too large") \ + X(EROFS, "Read-only file system") \ + X(ESPIPE, "Invalid seek") \ + X(ESRCH, "No such process") \ + X(ETIME, "Stream ioctl() timeout") \ + X(ETIMEDOUT, "Connection timed out") \ + X(ETXTBSY, "Text file busy") \ + X(EWOULDBLOCK, "Operation would block") \ + X(EXDEV, "Cross-device link") + + #define DEFINE_ENTRY(e, text) { e, #e, text }, + + static const struct { + int v; + const char* short_text; + const char* long_text; + } table [] = { + + ALL_SHARED_ENUMS(DEFINE_ENTRY) + + // The following enums are not defined on all platforms. + #ifdef ESTALE + DEFINE_ENTRY(ESTALE, "Reserved") + #endif + #ifdef EDQUOT + DEFINE_ENTRY(EDQUOT, "Reserved") + #endif + #ifdef EMULTIHOP + DEFINE_ENTRY(EMULTIHOP, "Reserved") + #endif + + // End marker. + { -1, "Unknown errno", "Unknown error" } + + }; + + #undef DEFINE_ENTRY + #undef ALL_FLAGS + + int i = 0; + while (table[i].v != -1 && table[i].v != e) { + i ++; + } + + return short_text ? table[i].short_text : table[i].long_text; + +} + +const char* os::strerror(int e) { + return errno_to_string(e, false); +} + +const char* os::errno_name(int e) { + return errno_to_string(e, true); +} + #ifndef PRODUCT void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count) { @@ -1540,8 +1667,8 @@ bool os::release_memory(char* addr, size_t bytes) { return res; } -void os::pretouch_memory(char* start, char* end) { - for (volatile char *p = start; p < end; p += os::vm_page_size()) { +void os::pretouch_memory(void* start, void* end) { + for (volatile char *p = (char*)start; p < (char*)end; p += os::vm_page_size()) { *p = 0; } } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 7b71ca5228d..04b19698cf3 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -325,7 +325,7 @@ class os: AllStatic { // to make the OS back the memory range with actual memory. // Current implementation may not touch the last page if unaligned addresses // are passed. - static void pretouch_memory(char* start, char* end); + static void pretouch_memory(void* start, void* end); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot, @@ -617,6 +617,22 @@ class os: AllStatic { static size_t lasterror(char *buf, size_t len); static int get_last_error(); + // Replacement for strerror(). + // Will return the english description of the error (e.g. "File not found", as + // suggested in the POSIX standard. + // Will return "Unknown error" for an unknown errno value. + // Will not attempt to localize the returned string. + // Will always return a valid string which is a static constant. + // Will not change the value of errno. + static const char* strerror(int e); + + // Will return the literalized version of the given errno (e.g. "EINVAL" + // for EINVAL). + // Will return "Unknown error" for an unknown errno value. + // Will always return a valid string which is a static constant. + // Will not change the value of errno. + static const char* errno_name(int e); + // Determines whether the calling process is being debugged by a user-mode debugger. static bool is_debugger_attached(); diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index b60c63a1ad8..1832711848b 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -76,9 +76,9 @@ static void trace_class_resolution(const Klass* to_class) { const char * to = to_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - log_info(classresolve)("%s %s %s:%d (reflection)", from, to, source_file, line_number); + log_debug(classresolve)("%s %s %s:%d (reflection)", from, to, source_file, line_number); } else { - log_info(classresolve)("%s %s (reflection)", from, to); + log_debug(classresolve)("%s %s (reflection)", from, to); } } } @@ -487,7 +487,7 @@ Reflection::VerifyClassAccessResults Reflection::verify_class_access( is_same_class_package(current_class, new_class)) { return ACCESS_OK; } - // Allow all accesses from sun/reflect/MagicAccessorImpl subclasses to + // Allow all accesses from jdk/internal/reflect/MagicAccessorImpl subclasses to // succeed trivially. if (current_class->is_subclass_of(SystemDictionary::reflect_MagicAccessorImpl_klass())) { return ACCESS_OK; @@ -698,7 +698,7 @@ bool Reflection::verify_field_access(const Klass* current_class, return true; } - // Allow all accesses from sun/reflect/MagicAccessorImpl subclasses to + // Allow all accesses from jdk/internal/reflect/MagicAccessorImpl subclasses to // succeed trivially. if (current_class->is_subclass_of(SystemDictionary::reflect_MagicAccessorImpl_klass())) { return true; @@ -769,7 +769,7 @@ static oop get_mirror_from_signature(methodHandle method, Handle(THREAD, protection_domain), true, CHECK_NULL); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { trace_class_resolution(k); } return k->java_mirror(); @@ -824,7 +824,7 @@ static Handle new_type(Symbol* signature, KlassHandle k, TRAPS) { Handle(THREAD, k->protection_domain()), true, CHECK_(Handle())); - if (log_is_enabled(Info, classresolve)) { + if (log_is_enabled(Debug, classresolve)) { trace_class_resolution(result); } diff --git a/hotspot/src/share/vm/runtime/reflectionUtils.cpp b/hotspot/src/share/vm/runtime/reflectionUtils.cpp index 331d5a750a0..fbab2e0fd60 100644 --- a/hotspot/src/share/vm/runtime/reflectionUtils.cpp +++ b/hotspot/src/share/vm/runtime/reflectionUtils.cpp @@ -76,9 +76,9 @@ void FilteredFieldsMap::initialize() { int offset; offset = java_lang_Throwable::get_backtrace_offset(); _filtered_fields->append(new FilteredField(SystemDictionary::Throwable_klass(), offset)); - offset = sun_reflect_ConstantPool::oop_offset(); + offset = reflect_ConstantPool::oop_offset(); _filtered_fields->append(new FilteredField(SystemDictionary::reflect_ConstantPool_klass(), offset)); - offset = sun_reflect_UnsafeStaticFieldAccessorImpl::base_offset(); + offset = reflect_UnsafeStaticFieldAccessorImpl::base_offset(); _filtered_fields->append(new FilteredField(SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass(), offset)); } diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 437e3bd4176..ceb934ac46d 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,10 @@ #include "runtime/sweeper.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/timerTrace.hpp" #include "services/runtimeService.hpp" +#include "trace/tracing.hpp" +#include "trace/traceMacros.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS @@ -79,7 +82,7 @@ static bool timeout_error_printed = false; // Roll all threads forward to a safepoint and suspend them all void SafepointSynchronize::begin() { - + EventSafepointBegin begin_event; Thread* myThread = Thread::current(); assert(myThread->is_VM_thread(), "Only VM thread may execute a safepoint"); @@ -169,191 +172,218 @@ void SafepointSynchronize::begin() { // between states, the safepointing code will wait for the thread to // block itself when it attempts transitions to a new state. // - _state = _synchronizing; - OrderAccess::fence(); + { + EventSafepointStateSync sync_event; + int initial_running = 0; - // Flush all thread states to memory - if (!UseMembar) { - os::serialize_thread_states(); - } + _state = _synchronizing; + OrderAccess::fence(); - // Make interpreter safepoint aware - Interpreter::notice_safepoints(); + // Flush all thread states to memory + if (!UseMembar) { + os::serialize_thread_states(); + } - if (DeferPollingPageLoopCount < 0) { - // Make polling safepoint aware - guarantee (PageArmed == 0, "invariant") ; - PageArmed = 1 ; - os::make_polling_page_unreadable(); - } + // Make interpreter safepoint aware + Interpreter::notice_safepoints(); - // Consider using active_processor_count() ... but that call is expensive. - int ncpus = os::processor_count() ; + if (DeferPollingPageLoopCount < 0) { + // Make polling safepoint aware + guarantee (PageArmed == 0, "invariant") ; + PageArmed = 1 ; + os::make_polling_page_unreadable(); + } + + // Consider using active_processor_count() ... but that call is expensive. + int ncpus = os::processor_count() ; #ifdef ASSERT - for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) { - assert(cur->safepoint_state()->is_running(), "Illegal initial state"); - // Clear the visited flag to ensure that the critical counts are collected properly. - cur->set_visited_for_critical_count(false); - } + for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) { + assert(cur->safepoint_state()->is_running(), "Illegal initial state"); + // Clear the visited flag to ensure that the critical counts are collected properly. + cur->set_visited_for_critical_count(false); + } #endif // ASSERT - if (SafepointTimeout) - safepoint_limit_time = os::javaTimeNanos() + (jlong)SafepointTimeoutDelay * MICROUNITS; + if (SafepointTimeout) + safepoint_limit_time = os::javaTimeNanos() + (jlong)SafepointTimeoutDelay * MICROUNITS; - // Iterate through all threads until it have been determined how to stop them all at a safepoint - unsigned int iterations = 0; - int steps = 0 ; - while(still_running > 0) { - for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) { - assert(!cur->is_ConcurrentGC_thread(), "A concurrent GC thread is unexpectly being suspended"); - ThreadSafepointState *cur_state = cur->safepoint_state(); - if (cur_state->is_running()) { - cur_state->examine_state_of_thread(); - if (!cur_state->is_running()) { - still_running--; - // consider adjusting steps downward: - // steps = 0 - // steps -= NNN - // steps >>= 1 - // steps = MIN(steps, 2000-100) - // if (iterations != 0) steps -= NNN - } - if (log_is_enabled(Trace, safepoint)) { - ResourceMark rm; - cur_state->print_on(LogHandle(safepoint)::debug_stream()); + // Iterate through all threads until it have been determined how to stop them all at a safepoint + unsigned int iterations = 0; + int steps = 0 ; + while(still_running > 0) { + for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) { + assert(!cur->is_ConcurrentGC_thread(), "A concurrent GC thread is unexpectly being suspended"); + ThreadSafepointState *cur_state = cur->safepoint_state(); + if (cur_state->is_running()) { + cur_state->examine_state_of_thread(); + if (!cur_state->is_running()) { + still_running--; + // consider adjusting steps downward: + // steps = 0 + // steps -= NNN + // steps >>= 1 + // steps = MIN(steps, 2000-100) + // if (iterations != 0) steps -= NNN + } + if (log_is_enabled(Trace, safepoint)) { + ResourceMark rm; + cur_state->print_on(Log(safepoint)::trace_stream()); + } } } - } - if (PrintSafepointStatistics && iterations == 0) { - begin_statistics(nof_threads, still_running); - } - - if (still_running > 0) { - // Check for if it takes to long - if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) { - print_safepoint_timeout(_spinning_timeout); + if (iterations == 0) { + initial_running = still_running; + if (PrintSafepointStatistics) { + begin_statistics(nof_threads, still_running); + } } - // Spin to avoid context switching. - // There's a tension between allowing the mutators to run (and rendezvous) - // vs spinning. As the VM thread spins, wasting cycles, it consumes CPU that - // a mutator might otherwise use profitably to reach a safepoint. Excessive - // spinning by the VM thread on a saturated system can increase rendezvous latency. - // Blocking or yielding incur their own penalties in the form of context switching - // and the resultant loss of $ residency. - // - // Further complicating matters is that yield() does not work as naively expected - // on many platforms -- yield() does not guarantee that any other ready threads - // will run. As such we revert to naked_short_sleep() after some number of iterations. - // nakes_short_sleep() is implemented as a short unconditional sleep. - // Typical operating systems round a "short" sleep period up to 10 msecs, so sleeping - // can actually increase the time it takes the VM thread to detect that a system-wide - // stop-the-world safepoint has been reached. In a pathological scenario such as that - // described in CR6415670 the VMthread may sleep just before the mutator(s) become safe. - // In that case the mutators will be stalled waiting for the safepoint to complete and the - // the VMthread will be sleeping, waiting for the mutators to rendezvous. The VMthread - // will eventually wake up and detect that all mutators are safe, at which point - // we'll again make progress. - // - // Beware too that that the VMThread typically runs at elevated priority. - // Its default priority is higher than the default mutator priority. - // Obviously, this complicates spinning. - // - // Note too that on Windows XP SwitchThreadTo() has quite different behavior than Sleep(0). - // Sleep(0) will _not yield to lower priority threads, while SwitchThreadTo() will. - // - // See the comments in synchronizer.cpp for additional remarks on spinning. - // - // In the future we might: - // 1. Modify the safepoint scheme to avoid potentially unbounded spinning. - // This is tricky as the path used by a thread exiting the JVM (say on - // on JNI call-out) simply stores into its state field. The burden - // is placed on the VM thread, which must poll (spin). - // 2. Find something useful to do while spinning. If the safepoint is GC-related - // we might aggressively scan the stacks of threads that are already safe. - // 3. Use Solaris schedctl to examine the state of the still-running mutators. - // If all the mutators are ONPROC there's no reason to sleep or yield. - // 4. YieldTo() any still-running mutators that are ready but OFFPROC. - // 5. Check system saturation. If the system is not fully saturated then - // simply spin and avoid sleep/yield. - // 6. As still-running mutators rendezvous they could unpark the sleeping - // VMthread. This works well for still-running mutators that become - // safe. The VMthread must still poll for mutators that call-out. - // 7. Drive the policy on time-since-begin instead of iterations. - // 8. Consider making the spin duration a function of the # of CPUs: - // Spin = (((ncpus-1) * M) + K) + F(still_running) - // Alternately, instead of counting iterations of the outer loop - // we could count the # of threads visited in the inner loop, above. - // 9. On windows consider using the return value from SwitchThreadTo() - // to drive subsequent spin/SwitchThreadTo()/Sleep(N) decisions. + if (still_running > 0) { + // Check for if it takes to long + if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) { + print_safepoint_timeout(_spinning_timeout); + } - if (int(iterations) == DeferPollingPageLoopCount) { - guarantee (PageArmed == 0, "invariant") ; - PageArmed = 1 ; - os::make_polling_page_unreadable(); + // Spin to avoid context switching. + // There's a tension between allowing the mutators to run (and rendezvous) + // vs spinning. As the VM thread spins, wasting cycles, it consumes CPU that + // a mutator might otherwise use profitably to reach a safepoint. Excessive + // spinning by the VM thread on a saturated system can increase rendezvous latency. + // Blocking or yielding incur their own penalties in the form of context switching + // and the resultant loss of $ residency. + // + // Further complicating matters is that yield() does not work as naively expected + // on many platforms -- yield() does not guarantee that any other ready threads + // will run. As such we revert to naked_short_sleep() after some number of iterations. + // nakes_short_sleep() is implemented as a short unconditional sleep. + // Typical operating systems round a "short" sleep period up to 10 msecs, so sleeping + // can actually increase the time it takes the VM thread to detect that a system-wide + // stop-the-world safepoint has been reached. In a pathological scenario such as that + // described in CR6415670 the VMthread may sleep just before the mutator(s) become safe. + // In that case the mutators will be stalled waiting for the safepoint to complete and the + // the VMthread will be sleeping, waiting for the mutators to rendezvous. The VMthread + // will eventually wake up and detect that all mutators are safe, at which point + // we'll again make progress. + // + // Beware too that that the VMThread typically runs at elevated priority. + // Its default priority is higher than the default mutator priority. + // Obviously, this complicates spinning. + // + // Note too that on Windows XP SwitchThreadTo() has quite different behavior than Sleep(0). + // Sleep(0) will _not yield to lower priority threads, while SwitchThreadTo() will. + // + // See the comments in synchronizer.cpp for additional remarks on spinning. + // + // In the future we might: + // 1. Modify the safepoint scheme to avoid potentially unbounded spinning. + // This is tricky as the path used by a thread exiting the JVM (say on + // on JNI call-out) simply stores into its state field. The burden + // is placed on the VM thread, which must poll (spin). + // 2. Find something useful to do while spinning. If the safepoint is GC-related + // we might aggressively scan the stacks of threads that are already safe. + // 3. Use Solaris schedctl to examine the state of the still-running mutators. + // If all the mutators are ONPROC there's no reason to sleep or yield. + // 4. YieldTo() any still-running mutators that are ready but OFFPROC. + // 5. Check system saturation. If the system is not fully saturated then + // simply spin and avoid sleep/yield. + // 6. As still-running mutators rendezvous they could unpark the sleeping + // VMthread. This works well for still-running mutators that become + // safe. The VMthread must still poll for mutators that call-out. + // 7. Drive the policy on time-since-begin instead of iterations. + // 8. Consider making the spin duration a function of the # of CPUs: + // Spin = (((ncpus-1) * M) + K) + F(still_running) + // Alternately, instead of counting iterations of the outer loop + // we could count the # of threads visited in the inner loop, above. + // 9. On windows consider using the return value from SwitchThreadTo() + // to drive subsequent spin/SwitchThreadTo()/Sleep(N) decisions. + + if (int(iterations) == DeferPollingPageLoopCount) { + guarantee (PageArmed == 0, "invariant") ; + PageArmed = 1 ; + os::make_polling_page_unreadable(); + } + + // Instead of (ncpus > 1) consider either (still_running < (ncpus + EPSILON)) or + // ((still_running + _waiting_to_block - TryingToBlock)) < ncpus) + ++steps ; + if (ncpus > 1 && steps < SafepointSpinBeforeYield) { + SpinPause() ; // MP-Polite spin + } else + if (steps < DeferThrSuspendLoopCount) { + os::naked_yield() ; + } else { + os::naked_short_sleep(1); + } + + iterations ++ ; } - - // Instead of (ncpus > 1) consider either (still_running < (ncpus + EPSILON)) or - // ((still_running + _waiting_to_block - TryingToBlock)) < ncpus) - ++steps ; - if (ncpus > 1 && steps < SafepointSpinBeforeYield) { - SpinPause() ; // MP-Polite spin - } else - if (steps < DeferThrSuspendLoopCount) { - os::naked_yield() ; - } else { - os::naked_short_sleep(1); - } - - iterations ++ ; + assert(iterations < (uint)max_jint, "We have been iterating in the safepoint loop too long"); } - assert(iterations < (uint)max_jint, "We have been iterating in the safepoint loop too long"); - } - assert(still_running == 0, "sanity check"); + assert(still_running == 0, "sanity check"); - if (PrintSafepointStatistics) { - update_statistics_on_spin_end(); - } + if (PrintSafepointStatistics) { + update_statistics_on_spin_end(); + } + + if (sync_event.should_commit()) { + sync_event.set_safepointId(safepoint_counter()); + sync_event.set_initialThreadCount(initial_running); + sync_event.set_runningThreadCount(_waiting_to_block); + sync_event.set_iterations(iterations); + sync_event.commit(); + } + } //EventSafepointStateSync // wait until all threads are stopped - while (_waiting_to_block > 0) { - log_debug(safepoint)("Waiting for %d thread(s) to block", _waiting_to_block); - if (!SafepointTimeout || timeout_error_printed) { - Safepoint_lock->wait(true); // true, means with no safepoint checks - } else { - // Compute remaining time - jlong remaining_time = safepoint_limit_time - os::javaTimeNanos(); + { + EventSafepointWaitBlocked wait_blocked_event; + int initial_waiting_to_block = _waiting_to_block; - // If there is no remaining time, then there is an error - if (remaining_time < 0 || Safepoint_lock->wait(true, remaining_time / MICROUNITS)) { - print_safepoint_timeout(_blocking_timeout); + while (_waiting_to_block > 0) { + log_debug(safepoint)("Waiting for %d thread(s) to block", _waiting_to_block); + if (!SafepointTimeout || timeout_error_printed) { + Safepoint_lock->wait(true); // true, means with no safepoint checks + } else { + // Compute remaining time + jlong remaining_time = safepoint_limit_time - os::javaTimeNanos(); + + // If there is no remaining time, then there is an error + if (remaining_time < 0 || Safepoint_lock->wait(true, remaining_time / MICROUNITS)) { + print_safepoint_timeout(_blocking_timeout); + } } } - } - assert(_waiting_to_block == 0, "sanity check"); + assert(_waiting_to_block == 0, "sanity check"); #ifndef PRODUCT - if (SafepointTimeout) { - jlong current_time = os::javaTimeNanos(); - if (safepoint_limit_time < current_time) { - tty->print_cr("# SafepointSynchronize: Finished after " - INT64_FORMAT_W(6) " ms", - ((current_time - safepoint_limit_time) / MICROUNITS + - (jlong)SafepointTimeoutDelay)); + if (SafepointTimeout) { + jlong current_time = os::javaTimeNanos(); + if (safepoint_limit_time < current_time) { + tty->print_cr("# SafepointSynchronize: Finished after " + INT64_FORMAT_W(6) " ms", + ((current_time - safepoint_limit_time) / MICROUNITS + + (jlong)SafepointTimeoutDelay)); + } } - } #endif - assert((_safepoint_counter & 0x1) == 0, "must be even"); - assert(Threads_lock->owned_by_self(), "must hold Threads_lock"); - _safepoint_counter ++; + assert((_safepoint_counter & 0x1) == 0, "must be even"); + assert(Threads_lock->owned_by_self(), "must hold Threads_lock"); + _safepoint_counter ++; - // Record state - _state = _synchronized; + // Record state + _state = _synchronized; - OrderAccess::fence(); + OrderAccess::fence(); + + if (wait_blocked_event.should_commit()) { + wait_blocked_event.set_safepointId(safepoint_counter()); + wait_blocked_event.set_runningThreadCount(initial_waiting_to_block); + wait_blocked_event.commit(); + } + } // EventSafepointWaitBlocked #ifdef ASSERT for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) { @@ -377,17 +407,32 @@ void SafepointSynchronize::begin() { } // Call stuff that needs to be run when a safepoint is just about to be completed - do_cleanup_tasks(); + { + EventSafepointCleanup cleanup_event; + do_cleanup_tasks(); + if (cleanup_event.should_commit()) { + cleanup_event.set_safepointId(safepoint_counter()); + cleanup_event.commit(); + } + } if (PrintSafepointStatistics) { // Record how much time spend on the above cleanup tasks update_statistics_on_cleanup_end(os::javaTimeNanos()); } + if (begin_event.should_commit()) { + begin_event.set_safepointId(safepoint_counter()); + begin_event.set_totalThreadCount(nof_threads); + begin_event.set_jniCriticalThreadCount(_current_jni_active_count); + begin_event.commit(); + } } // Wake up all threads, so they are ready to resume execution after the safepoint // operation has been carried out void SafepointSynchronize::end() { + EventSafepointEnd event; + int safepoint_id = safepoint_counter(); // Keep the odd counter as "id" assert(Threads_lock->owned_by_self(), "must hold Threads_lock"); assert((_safepoint_counter & 0x1) == 1, "must be odd"); @@ -474,6 +519,11 @@ void SafepointSynchronize::end() { // record this time so VMThread can keep track how much time has elapsed // since last safepoint. _end_of_last_safepoint = os::javaTimeMillis(); + + if (event.should_commit()) { + event.set_safepointId(safepoint_id); + event.commit(); + } } bool SafepointSynchronize::is_cleanup_needed() { @@ -482,44 +532,71 @@ bool SafepointSynchronize::is_cleanup_needed() { return false; } - +static void event_safepoint_cleanup_task_commit(EventSafepointCleanupTask& event, const char* name) { + if (event.should_commit()) { + event.set_safepointId(SafepointSynchronize::safepoint_counter()); + event.set_name(name); + event.commit(); + } +} // Various cleaning tasks that should be done periodically at safepoints void SafepointSynchronize::do_cleanup_tasks() { { - TraceTime t1("deflating idle monitors", TraceSafepointCleanupTime); + const char* name = "deflating idle monitors"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); ObjectSynchronizer::deflate_idle_monitors(); + event_safepoint_cleanup_task_commit(event, name); } { - TraceTime t2("updating inline caches", TraceSafepointCleanupTime); + const char* name = "updating inline caches"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); InlineCacheBuffer::update_inline_caches(); + event_safepoint_cleanup_task_commit(event, name); } { - TraceTime t3("compilation policy safepoint handler", TraceSafepointCleanupTime); + const char* name = "compilation policy safepoint handler"; + EventSafepointCleanupTask event; + TraceTime timer("compilation policy safepoint handler", TRACETIME_LOG(Info, safepointcleanup)); CompilationPolicy::policy()->do_safepoint_work(); + event_safepoint_cleanup_task_commit(event, name); } { - TraceTime t4("mark nmethods", TraceSafepointCleanupTime); + const char* name = "mark nmethods"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); NMethodSweeper::mark_active_nmethods(); + event_safepoint_cleanup_task_commit(event, name); } if (SymbolTable::needs_rehashing()) { - TraceTime t5("rehashing symbol table", TraceSafepointCleanupTime); + const char* name = "rehashing symbol table"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); SymbolTable::rehash_table(); + event_safepoint_cleanup_task_commit(event, name); } if (StringTable::needs_rehashing()) { - TraceTime t6("rehashing string table", TraceSafepointCleanupTime); + const char* name = "rehashing string table"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); StringTable::rehash_table(); + event_safepoint_cleanup_task_commit(event, name); } { // CMS delays purging the CLDG until the beginning of the next safepoint and to // make sure concurrent sweep is done - TraceTime t7("purging class loader data graph", TraceSafepointCleanupTime); + const char* name = "purging class loader data graph"; + EventSafepointCleanupTask event; + TraceTime timer(name, TRACETIME_LOG(Info, safepointcleanup)); ClassLoaderDataGraph::purge_if_needed(); + event_safepoint_cleanup_task_commit(event, name); } } diff --git a/hotspot/src/share/vm/runtime/safepoint.hpp b/hotspot/src/share/vm/runtime/safepoint.hpp index ab5d2e9445d..d1df743f34f 100644 --- a/hotspot/src/share/vm/runtime/safepoint.hpp +++ b/hotspot/src/share/vm/runtime/safepoint.hpp @@ -145,6 +145,7 @@ public: // Query inline static bool is_at_safepoint() { return _state == _synchronized; } inline static bool is_synchronizing() { return _state == _synchronizing; } + inline static int safepoint_counter() { return _safepoint_counter; } inline static bool do_call_back() { return (_state != _not_synchronized); diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index fe697685022..89d0f2c66d3 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/klass.hpp" #include "oops/objArrayKlass.hpp" @@ -993,19 +994,6 @@ address SharedRuntime::native_method_throw_unsatisfied_link_error_entry() { return CAST_FROM_FN_PTR(address, &throw_unsatisfied_link_error); } - -#ifndef PRODUCT -JRT_ENTRY(intptr_t, SharedRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2)) - const frame f = thread->last_frame(); - assert(f.is_interpreted_frame(), "must be an interpreted frame"); -#ifndef PRODUCT - methodHandle mh(THREAD, f.interpreter_frame_method()); - BytecodeTracer::trace(mh, f.interpreter_frame_bcp(), tos, tos2); -#endif // !PRODUCT - return preserve_this_value; -JRT_END -#endif // !PRODUCT - JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(obj->is_oop(), "must be a valid oop"); #if INCLUDE_JVMCI @@ -1981,8 +1969,8 @@ JRT_END // Handles the uncommon case in locking, i.e., contention or an inflated lock. JRT_BLOCK_ENTRY(void, SharedRuntime::complete_monitor_locking_C(oopDesc* _obj, BasicLock* lock, JavaThread* thread)) // Disable ObjectSynchronizer::quick_enter() in default config - // until JDK-8077392 is resolved. - if ((SyncFlags & 256) != 0 && !SafepointSynchronize::is_synchronizing()) { + // on AARCH64 until JDK-8153107 is resolved. + if (AARCH64_ONLY((SyncFlags & 256) != 0 &&) !SafepointSynchronize::is_synchronizing()) { // Only try quick_enter() if we're not trying to reach a safepoint // so that the calling thread reaches the safepoint more quickly. if (ObjectSynchronizer::quick_enter(_obj, thread, lock)) return; @@ -2966,7 +2954,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) ) Method* moop = fr.interpreter_frame_method(); int max_locals = moop->max_locals(); // Allocate temp buffer, 1 word per local & 2 per active monitor - int buf_size_words = max_locals + active_monitor_count*2; + int buf_size_words = max_locals + active_monitor_count * BasicObjectLock::size(); intptr_t *buf = NEW_C_HEAP_ARRAY(intptr_t,buf_size_words, mtCode); // Copy the locals. Order is preserved so that loading of longs works. diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index 10c94e6c366..b3f87cdc7c6 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -269,9 +269,6 @@ class SharedRuntime: AllStatic { static address native_method_throw_unsatisfied_link_error_entry(); static address native_method_throw_unsupported_operation_exception_entry(); - // bytecode tracing is only used by the TraceBytecodes - static intptr_t trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2) PRODUCT_RETURN0; - static oop retrieve_receiver(Symbol* sig, frame caller); static void register_finalizer(JavaThread* thread, oopDesc* obj); diff --git a/hotspot/src/share/vm/runtime/signature.cpp b/hotspot/src/share/vm/runtime/signature.cpp index 9e616a44add..937c1ff7edc 100644 --- a/hotspot/src/share/vm/runtime/signature.cpp +++ b/hotspot/src/share/vm/runtime/signature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp index 3f8b76c9327..2a0138871fc 100644 --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp @@ -233,6 +233,14 @@ void SimpleThresholdPolicy::compile(const methodHandle& mh, int bci, CompLevel l if (level == CompLevel_none) { return; } + +#if INCLUDE_JVMCI + // We can't compile with a JVMCI compiler until the module system is initialized. + if (level == CompLevel_full_optimization && UseJVMCICompiler && !Universe::is_module_initialized()) { + return; + } +#endif + // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling // in the interpreter and then compile with C2 (the transition function will request that, // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index 71080e5b76c..ac98cd18ea6 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -28,7 +28,7 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/interfaceSupport.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/copy.hpp" @@ -183,7 +183,7 @@ extern void StubGenerator_generate(CodeBuffer* code, bool all); // only interfac void StubRoutines::initialize1() { if (_code1 == NULL) { ResourceMark rm; - TraceStartupTime timer("StubRoutines generation 1"); + TraceTime timer("StubRoutines generation 1", TRACETIME_LOG(Info, startuptime)); _code1 = BufferBlob::create("StubRoutines (1)", code_size1); if (_code1 == NULL) { vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)"); @@ -276,7 +276,7 @@ static void test_safefetchN() { void StubRoutines::initialize2() { if (_code2 == NULL) { ResourceMark rm; - TraceStartupTime timer("StubRoutines generation 2"); + TraceTime timer("StubRoutines generation 2", TRACETIME_LOG(Info, startuptime)); _code2 = BufferBlob::create("StubRoutines (2)", code_size2); if (_code2 == NULL) { vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)"); diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index 7203ff9fbe7..ef8a271106a 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,13 +48,6 @@ #include "utilities/events.hpp" #include "utilities/preserveException.hpp" -#if defined(__GNUC__) && !defined(PPC64) -// Need to inhibit inlining for older versions of GCC to avoid build-time failures - #define NOINLINE __attribute__((noinline)) -#else - #define NOINLINE -#endif - // The "core" versions of monitor enter and exit reside in this file. // The interpreter and compilers contain specialized transliterated // variants of the enter-exit fast-path operations. See i486.ad fast_lock(), @@ -211,7 +204,7 @@ bool ObjectSynchronizer::quick_notify(oopDesc * obj, Thread * self, bool all) { // quick_enter() as our thread state remains _in_Java. bool ObjectSynchronizer::quick_enter(oop obj, Thread * Self, - BasicLock * Lock) { + BasicLock * lock) { assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); assert(Self->is_Java_thread(), "invariant"); assert(((JavaThread *) Self)->thread_state() == _thread_in_Java, "invariant"); @@ -234,6 +227,18 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread * Self, return true; } + // This Java Monitor is inflated so obj's header will never be + // displaced to this thread's BasicLock. Make the displaced header + // non-NULL so this BasicLock is not seen as recursive nor as + // being locked. We do this unconditionally so that this thread's + // BasicLock cannot be mis-interpreted by any stack walkers. For + // performance reasons, stack walkers generally first check for + // Biased Locking in the object's header, the second check is for + // stack-locking in the object's header, the third check is for + // recursive stack-locking in the displaced header in the BasicLock, + // and last are the inflated Java Monitor (ObjectMonitor) checks. + lock->set_displaced_header(markOopDesc::unused_mark()); + if (owner == NULL && Atomic::cmpxchg_ptr(Self, &(m->_owner), NULL) == NULL) { assert(m->_recursions == 0, "invariant"); @@ -278,38 +283,52 @@ void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, } void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) { - assert(!object->mark()->has_bias_pattern(), "should not see bias pattern here"); - // if displaced header is null, the previous enter is recursive enter, no-op + markOop mark = object->mark(); + // We cannot check for Biased Locking if we are racing an inflation. + assert(mark == markOopDesc::INFLATING() || + !mark->has_bias_pattern(), "should not see bias pattern here"); + markOop dhw = lock->displaced_header(); - markOop mark; if (dhw == NULL) { - // Recursive stack-lock. - // Diagnostics -- Could be: stack-locked, inflating, inflated. - mark = object->mark(); - assert(!mark->is_neutral(), "invariant"); - if (mark->has_locker() && mark != markOopDesc::INFLATING()) { - assert(THREAD->is_lock_owned((address)mark->locker()), "invariant"); - } - if (mark->has_monitor()) { - ObjectMonitor * m = mark->monitor(); - assert(((oop)(m->object()))->mark() == mark, "invariant"); - assert(m->is_entered(THREAD), "invariant"); + // If the displaced header is NULL, then this exit matches up with + // a recursive enter. No real work to do here except for diagnostics. +#ifndef PRODUCT + if (mark != markOopDesc::INFLATING()) { + // Only do diagnostics if we are not racing an inflation. Simply + // exiting a recursive enter of a Java Monitor that is being + // inflated is safe; see the has_monitor() comment below. + assert(!mark->is_neutral(), "invariant"); + assert(!mark->has_locker() || + THREAD->is_lock_owned((address)mark->locker()), "invariant"); + if (mark->has_monitor()) { + // The BasicLock's displaced_header is marked as a recursive + // enter and we have an inflated Java Monitor (ObjectMonitor). + // This is a special case where the Java Monitor was inflated + // after this thread entered the stack-lock recursively. When a + // Java Monitor is inflated, we cannot safely walk the Java + // Monitor owner's stack and update the BasicLocks because a + // Java Monitor can be asynchronously inflated by a thread that + // does not own the Java Monitor. + ObjectMonitor * m = mark->monitor(); + assert(((oop)(m->object()))->mark() == mark, "invariant"); + assert(m->is_entered(THREAD), "invariant"); + } } +#endif return; } - mark = object->mark(); - - // If the object is stack-locked by the current thread, try to - // swing the displaced header from the box back to the mark. if (mark == (markOop) lock) { + // If the object is stack-locked by the current thread, try to + // swing the displaced header from the BasicLock back to the mark. assert(dhw->is_neutral(), "invariant"); - if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) { - TEVENT(fast_exit: release stacklock); + if ((markOop) Atomic::cmpxchg_ptr(dhw, object->mark_addr(), mark) == mark) { + TEVENT(fast_exit: release stack-lock); return; } } + // We have to take the slow-path of possible inflation and then exit. ObjectSynchronizer::inflate(THREAD, object, inflate_cause_vm_internal)->exit(true, THREAD); @@ -1038,7 +1057,7 @@ void ObjectSynchronizer::verifyInUse(Thread *Self) { assert(free_tally == Self->omFreeCount, "free count off"); } -ObjectMonitor * NOINLINE ObjectSynchronizer::omAlloc(Thread * Self) { +ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) { // A large MAXPRIVATE value reduces both list lock contention // and list coherency traffic, but also tends to increase the // number of objectMonitors in circulation as well as the STW @@ -1313,7 +1332,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_helper(oop obj) { inflate_cause_vm_internal); } -ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self, +ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self, oop object, const InflateCause cause) { @@ -1742,6 +1761,7 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure { void do_monitor(ObjectMonitor* mid) { if (mid->owner() == THREAD) { if (ObjectMonitor::Knob_VerifyMatch != 0) { + ResourceMark rm; Handle obj((oop) mid->object()); tty->print("INFO: unexpected locked object:"); javaVFrame::print_locked_object_class_name(tty, obj, "locked"); diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index c8348999d9a..b08d6b6b1f2 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -35,6 +35,7 @@ #include "compiler/compileTask.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/workgroup.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" @@ -44,6 +45,7 @@ #include "logging/logConfiguration.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayOop.hpp" @@ -68,7 +70,7 @@ #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniPeriodicChecker.hpp" -#include "runtime/logTimer.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/memprofiler.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" @@ -152,7 +154,6 @@ void universe_post_module_init(); // must happen after call_initPhase2 // Current thread is maintained as a thread-local variable THREAD_LOCAL_DECL Thread* Thread::_thr_current = NULL; #endif - // Class hierarchy // - Thread // - VMThread @@ -791,10 +792,6 @@ void Thread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { handle_area()->oops_do(f); } -void Thread::nmethods_do(CodeBlobClosure* cf) { - // no nmethods in a generic thread... -} - void Thread::metadata_handles_do(void f(Metadata*)) { // Only walk the Handles in Thread. if (metadata_handles() != NULL) { @@ -2093,7 +2090,7 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) { if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - outputStream* logstream = LogHandle(exceptions)::info_stream(); + outputStream* logstream = Log(exceptions)::info_stream(); logstream->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", p2i(this)); if (has_last_Java_frame()) { frame f = last_frame(); @@ -2827,8 +2824,6 @@ void JavaThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) } void JavaThread::nmethods_do(CodeBlobClosure* cf) { - Thread::nmethods_do(cf); // (super method is a no-op) - assert((!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -2887,7 +2882,9 @@ void JavaThread::print_thread_state() const { // Called by Threads::print() for VM_PrintThreads operation void JavaThread::print_on(outputStream *st) const { - st->print("\"%s\" ", get_thread_name()); + st->print_raw("\""); + st->print_raw(get_thread_name()); + st->print_raw("\" "); oop thread_oop = threadObj(); if (thread_oop != NULL) { st->print("#" INT64_FORMAT " ", java_lang_Thread::thread_id(thread_oop)); @@ -3301,6 +3298,7 @@ CodeCacheSweeperThread::CodeCacheSweeperThread() : JavaThread(&sweeper_thread_entry) { _scanned_nmethod = NULL; } + void CodeCacheSweeperThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { JavaThread::oops_do(f, cld_f, cf); if (_scanned_nmethod != NULL && cf != NULL) { @@ -3311,6 +3309,16 @@ void CodeCacheSweeperThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobC } } +void CodeCacheSweeperThread::nmethods_do(CodeBlobClosure* cf) { + JavaThread::nmethods_do(cf); + if (_scanned_nmethod != NULL && cf != NULL) { + // Safepoints can occur when the sweeper is scanning an nmethod so + // process it here to make sure it isn't unloaded in the middle of + // a scan. + cf->do_code_blob(_scanned_nmethod); + } +} + // ======= Threads ======== @@ -3416,7 +3424,7 @@ static void call_initPhase3(TRAPS) { } void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { - TraceStartupTime timer("Initialize java.lang classes"); + TraceTime timer("Initialize java.lang classes", TRACETIME_LOG(Info, startuptime)); if (EagerXrunInit && Arguments::init_libraries_at_startup()) { create_vm_init_libraries(); @@ -3468,7 +3476,7 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { } void Threads::initialize_jsr292_core_classes(TRAPS) { - TraceStartupTime timer("Initialize java.lang.invoke classes"); + TraceTime timer("Initialize java.lang.invoke classes", TRACETIME_LOG(Info, startuptime)); initialize_class(vmSymbols::java_lang_invoke_MethodHandle(), CHECK); initialize_class(vmSymbols::java_lang_invoke_MemberName(), CHECK); @@ -3539,7 +3547,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { HOTSPOT_VM_INIT_BEGIN(); // Timing (must come after argument parsing) - TraceStartupTime timer("Create VM"); + TraceTime timer("Create VM", TRACETIME_LOG(Info, startuptime)); // Initialize the os module after parsing the args jint os_init_2_result = os::init_2(); @@ -3628,7 +3636,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { JvmtiExport::transition_pending_onload_raw_monitors(); // Create the VMThread - { TraceStartupTime timer("Start VMThread"); + { TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime)); VMThread::create(); Thread* vmthread = VMThread::vm_thread(); @@ -3703,18 +3711,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. -#if INCLUDE_ALL_GCS - // Support for ConcurrentMarkSweep. This should be cleaned up - // and better encapsulated. The ugly nested if test would go away - // once things are properly refactored. XXX YSR - if (UseConcMarkSweepGC || UseG1GC) { - if (UseConcMarkSweepGC) { - ConcurrentMarkSweepThread::makeSurrogateLockerThread(CHECK_JNI_ERR); - } else { - ConcurrentMarkThread::makeSurrogateLockerThread(CHECK_JNI_ERR); - } - } -#endif // INCLUDE_ALL_GCS + // Initialize reference pending list locker + bool needs_locker_thread = Universe::heap()->needs_reference_pending_list_locker_thread(); + ReferencePendingListLocker::initialize(needs_locker_thread, CHECK_JNI_ERR); // Signal Dispatcher needs to be started before VMInit event is posted os::signal_init(); @@ -4348,9 +4347,13 @@ void Threads::create_thread_roots_marking_tasks(GCTaskQueue* q) { void Threads::nmethods_do(CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { - p->nmethods_do(cf); + // This is used by the code cache sweeper to mark nmethods that are active + // on the stack of a Java thread. Ignore the sweeper thread itself to avoid + // marking CodeCacheSweeperThread::_scanned_nmethod as active. + if(!p->is_Code_cache_sweeper_thread()) { + p->nmethods_do(cf); + } } - VMThread::vm_thread()->nmethods_do(cf); } void Threads::metadata_do(void f(Metadata*)) { diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index eed983d3841..4f993ab8fa1 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -509,9 +509,6 @@ class Thread: public ThreadShadow { } } - // Sweeper support - void nmethods_do(CodeBlobClosure* cf); - // jvmtiRedefineClasses support void metadata_handles_do(void f(Metadata*)); @@ -1649,7 +1646,7 @@ class JavaThread: public Thread { void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); // Sweeper operations - void nmethods_do(CodeBlobClosure* cf); + virtual void nmethods_do(CodeBlobClosure* cf); // RedefineClasses Support void metadata_do(void f(Metadata*)); @@ -1997,10 +1994,10 @@ class CodeCacheSweeperThread : public JavaThread { bool is_hidden_from_external_view() const { return true; } bool is_Code_cache_sweeper_thread() const { return true; } - // GC support - // Apply "f->do_oop" to all root oops in "this". - // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames + + // Prevent GC from unloading _scanned_nmethod void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); + void nmethods_do(CodeBlobClosure* cf); }; // A thread used for Compilation. diff --git a/hotspot/src/share/vm/runtime/timer.cpp b/hotspot/src/share/vm/runtime/timer.cpp index dddf328b302..dc776fdd688 100644 --- a/hotspot/src/share/vm/runtime/timer.cpp +++ b/hotspot/src/share/vm/runtime/timer.cpp @@ -114,54 +114,6 @@ jlong TimeStamp::ticks_since_update() const { return os::elapsed_counter() - _counter; } -TraceTime::TraceTime(const char* title, - bool doit, - LogTagType tag) { - _active = doit; - _verbose = true; - _tag = tag; - _title = title; - - if (_active) { - _accum = NULL; - _t.start(); - } -} - -TraceTime::TraceTime(const char* title, - elapsedTimer* accumulator, - bool doit, - bool verbose, - LogTagType tag) { - _active = doit; - _verbose = verbose; - _tag = tag; - _title = title; - - if (_active) { - _accum = accumulator; - _t.start(); - } -} - -TraceTime::~TraceTime() { - if (_active) { - _t.stop(); - if (_accum!=NULL) _accum->add(_t); - if (_verbose) { - switch (_tag) { - case LogTag::_startuptime : - log_info(startuptime)("%s, %3.7f secs", _title, _t.seconds()); - break; - case LogTag::__NO_TAG : - default : - tty->print_cr("[%s, %3.7f secs]", _title, _t.seconds()); - tty->flush(); - } - } - } -} - TraceCPUTime::TraceCPUTime(bool doit, bool print_cr, outputStream *logfile) : @@ -216,3 +168,4 @@ TraceCPUTime::~TraceCPUTime() { _logfile->flush(); } } + diff --git a/hotspot/src/share/vm/runtime/timer.hpp b/hotspot/src/share/vm/runtime/timer.hpp index c14e2522917..5c935312ddf 100644 --- a/hotspot/src/share/vm/runtime/timer.hpp +++ b/hotspot/src/share/vm/runtime/timer.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_VM_RUNTIME_TIMER_HPP #define SHARE_VM_RUNTIME_TIMER_HPP -#include "logging/logTag.hpp" #include "utilities/globalDefinitions.hpp" // Timers for simple measurement. @@ -73,43 +72,6 @@ class TimeStamp VALUE_OBJ_CLASS_SPEC { jlong ticks_since_update() const; }; -// TraceTime is used for tracing the execution time of a block -// Usage: -// { TraceTime t("block time") -// some_code(); -// } -// - -class TraceTime: public StackObj { - private: - bool _active; // do timing - bool _verbose; // report every timing - elapsedTimer _t; // timer - elapsedTimer* _accum; // accumulator - const char* _title; // name of timer - LogTagType _tag; // stream to print to - - public: - // Constructors - TraceTime(const char* title, - bool doit = true, - LogTagType tag = LogTag::__NO_TAG); - TraceTime(const char* title, - elapsedTimer* accumulator, - bool doit = true, - bool verbose = false, - LogTagType tag = LogTag::__NO_TAG); - ~TraceTime(); - - // Accessors - void set_verbose(bool verbose) { _verbose = verbose; } - bool verbose() const { return _verbose; } - - // Activation - void suspend() { if (_active) _t.stop(); } - void resume() { if (_active) _t.start(); } -}; - class TraceCPUTime: public StackObj { private: bool _active; // true if times will be measured and printed diff --git a/hotspot/src/share/vm/runtime/timerTrace.cpp b/hotspot/src/share/vm/runtime/timerTrace.cpp new file mode 100644 index 00000000000..03320e45638 --- /dev/null +++ b/hotspot/src/share/vm/runtime/timerTrace.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/timerTrace.hpp" + +TraceTime::TraceTime(const char* title, + bool doit) { + _active = doit; + _verbose = true; + _title = title; + _print = NULL; + + if (_active) { + _accum = NULL; + _t.start(); + } +} + +TraceTime::TraceTime(const char* title, + elapsedTimer* accumulator, + bool doit, + bool verbose) { + _active = doit; + _verbose = verbose; + _title = title; + _print = NULL; + + if (_active) { + _accum = accumulator; + _t.start(); + } +} + +TraceTime::TraceTime(const char* title, + TraceTimerLogPrintFunc ttlpf) { + _active = ttlpf!= NULL; + _verbose = true; + _title = title; + _print = ttlpf; + + if (_active) { + _accum = NULL; + _t.start(); + } +} + +TraceTime::~TraceTime() { + if (!_active) { + return; + } + _t.stop(); + if (_accum != NULL) { + _accum->add(_t); + } + if (!_verbose) { + return; + } + if (_print) { + _print("%s, %3.7f secs", _title, _t.seconds()); + } else { + tty->print_cr("[%s, %3.7f secs]", _title, _t.seconds()); + tty->flush(); + } +} + diff --git a/hotspot/src/share/vm/runtime/timerTrace.hpp b/hotspot/src/share/vm/runtime/timerTrace.hpp new file mode 100644 index 00000000000..b6f1089eb11 --- /dev/null +++ b/hotspot/src/share/vm/runtime/timerTrace.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_TIMERTRACE_HPP +#define SHARE_VM_RUNTIME_TIMERTRACE_HPP + +#include "logging/log.hpp" +#include "utilities/globalDefinitions.hpp" + +// TraceTime is used for tracing the execution time of a block +// Usage: +// { +// TraceTime t("some timer", TIMERTRACE_LOG(Info, startuptime, tagX...)); +// some_code(); +// } +// + +typedef void (*TraceTimerLogPrintFunc)(const char*, ...); + +// We need to explicit take address of LogImpl<>write<> and static cast +// due to MSVC is not compliant with templates two-phase lookup +#define TRACETIME_LOG(TT_LEVEL, ...) \ + log_is_enabled(TT_LEVEL, __VA_ARGS__) ? static_cast(&LogImpl::write) : (TraceTimerLogPrintFunc)NULL + +class TraceTime: public StackObj { + private: + bool _active; // do timing + bool _verbose; // report every timing + elapsedTimer _t; // timer + elapsedTimer* _accum; // accumulator + const char* _title; // name of timer + TraceTimerLogPrintFunc _print; + + public: + // Constructors + TraceTime(const char* title, + bool doit = true); + + TraceTime(const char* title, + elapsedTimer* accumulator, + bool doit = true, + bool verbose = false); + + TraceTime(const char* title, + TraceTimerLogPrintFunc ttlpf); + + ~TraceTime(); + + // Accessors + void set_verbose(bool verbose) { _verbose = verbose; } + bool verbose() const { return _verbose; } + + // Activation + void suspend() { if (_active) _t.stop(); } + void resume() { if (_active) _t.start(); } +}; + + +#endif // SHARE_VM_RUNTIME_TIMERTRACE_HPP diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 84d2c6ebd3b..0e9c451a621 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -54,6 +54,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/generationSpec.hpp" +#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/space.hpp" #include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/bytecodes.hpp" @@ -384,8 +385,8 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(MethodCounters, _interpreter_profile_limit, int) \ nonstatic_field(MethodCounters, _invoke_mask, int) \ nonstatic_field(MethodCounters, _backedge_mask, int) \ - nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \ - nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \ + COMPILER2_OR_JVMCI_PRESENT(nonstatic_field(MethodCounters, _interpreter_invocation_count, int)) \ + COMPILER2_OR_JVMCI_PRESENT(nonstatic_field(MethodCounters, _interpreter_throwout_count, u2)) \ nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \ nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ @@ -1692,6 +1693,7 @@ typedef CompactHashtable SymbolCompactHashTable; declare_type(JavaThread, Thread) \ declare_type(JvmtiAgentThread, JavaThread) \ declare_type(ServiceThread, JavaThread) \ + declare_type(ReferencePendingListLockerThread, JavaThread) \ declare_type(CompilerThread, JavaThread) \ declare_type(CodeCacheSweeperThread, JavaThread) \ declare_toplevel_type(OSThread) \ diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index f4584b1fc9b..138431a1475 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -32,6 +32,7 @@ #include "runtime/interfaceSupport.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" +#include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" @@ -352,14 +353,16 @@ void VMThread::evaluate_operation(VM_Operation* op) { op->evaluate(); if (event.should_commit()) { - bool is_concurrent = op->evaluate_concurrently(); + const bool is_concurrent = op->evaluate_concurrently(); + const bool evaluate_at_safepoint = op->evaluate_at_safepoint(); event.set_operation(op->type()); - event.set_safepoint(op->evaluate_at_safepoint()); + event.set_safepoint(evaluate_at_safepoint); event.set_blocking(!is_concurrent); // Only write caller thread information for non-concurrent vm operations. // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. // This is because the caller thread could have exited already. event.set_caller(is_concurrent ? 0 : THREAD_TRACE_ID(op->calling_thread())); + event.set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_counter() : 0); event.commit(); } diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index db7341d869f..3ac2816775a 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -59,7 +59,7 @@ void VM_Operation::evaluate() { outputStream* debugstream; bool enabled = log_is_enabled(Debug, vmoperation); if (enabled) { - debugstream = LogHandle(vmoperation)::debug_stream(); + debugstream = Log(vmoperation)::debug_stream(); debugstream->print("begin "); print_on_error(debugstream); debugstream->cr(); @@ -105,6 +105,14 @@ void VM_ThreadStop::doit() { } } +void VM_ClearICs::doit() { + if (_preserve_static_stubs) { + CodeCache::cleanup_inline_caches(); + } else { + CodeCache::clear_inline_caches(); + } +} + void VM_Deoptimize::doit() { // We do not want any GCs to happen while we are in the middle of this VM operation ResourceMark rm; diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index a5b0ddbf47b..22626d2c2a8 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -231,9 +231,11 @@ class VM_ThreadStop: public VM_Operation { }; class VM_ClearICs: public VM_Operation { + private: + bool _preserve_static_stubs; public: - VM_ClearICs() {} - void doit() { CodeCache::clear_inline_caches(); } + VM_ClearICs(bool preserve_static_stubs) { _preserve_static_stubs = preserve_static_stubs; } + void doit(); VMOp_Type type() const { return VMOp_ClearICs; } }; diff --git a/hotspot/src/share/vm/services/classLoadingService.cpp b/hotspot/src/share/vm/services/classLoadingService.cpp index 4acb22502ce..67bdb223653 100644 --- a/hotspot/src/share/vm/services/classLoadingService.cpp +++ b/hotspot/src/share/vm/services/classLoadingService.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" #include "runtime/mutexLocker.hpp" diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index dc2b2171408..6ed19904a78 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -28,6 +28,7 @@ #include "compiler/compileBroker.hpp" #include "compiler/directivesParser.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" #include "runtime/javaCalls.hpp" @@ -61,17 +62,19 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); -#if INCLUDE_SERVICES // Heap dumping/inspection supported +#if INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +#if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +#endif // INCLUDE_JVMTI #endif // INCLUDE_SERVICES #if INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -255,6 +258,7 @@ void JVMTIDataDumpDCmd::execute(DCmdSource source, TRAPS) { } } +#if INCLUDE_SERVICES JVMTIAgentLoadDCmd::JVMTIAgentLoadDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _libpath("library path", "Absolute path of the JVMTI agent to load.", @@ -314,6 +318,7 @@ int JVMTIAgentLoadDCmd::num_arguments() { return 0; } } +#endif // INCLUDE_SERVICES void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { // load VMSupport diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index 8f5dc9172ae..727ab33e64a 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -174,6 +174,8 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +#if INCLUDE_SERVICES +#if INCLUDE_JVMTI class JVMTIAgentLoadDCmd : public DCmdWithParser { protected: DCmdArgument _libpath; @@ -193,6 +195,8 @@ public: static int num_arguments(); virtual void execute(DCmdSource source, TRAPS); }; +#endif // INCLUDE_JVMTI +#endif // INCLUDE_SERVICES class VMDynamicLibrariesDCmd : public DCmd { public: diff --git a/hotspot/src/share/vm/services/diagnosticFramework.cpp b/hotspot/src/share/vm/services/diagnosticFramework.cpp index c3d571d316a..09c310768d5 100644 --- a/hotspot/src/share/vm/services/diagnosticFramework.cpp +++ b/hotspot/src/share/vm/services/diagnosticFramework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" diff --git a/hotspot/src/share/vm/services/gcNotifier.cpp b/hotspot/src/share/vm/services/gcNotifier.cpp index 0336428e2b4..3130fdbfcc1 100644 --- a/hotspot/src/share/vm/services/gcNotifier.cpp +++ b/hotspot/src/share/vm/services/gcNotifier.cpp @@ -37,6 +37,7 @@ #include "services/memoryService.hpp" #include "memoryManager.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" GCNotificationRequest *GCNotifier::first_request = NULL; GCNotificationRequest *GCNotifier::last_request = NULL; diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 986855894d2..2b5cd47db05 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -29,6 +29,7 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" @@ -459,7 +460,7 @@ DumpWriter::DumpWriter(const char* path) { // if the open failed we record the error if (_fd < 0) { - _error = (char*)os::strdup(strerror(errno)); + _error = (char*)os::strdup(os::strerror(errno)); } } @@ -509,7 +510,7 @@ void DumpWriter::write_internal(void* s, size_t len) { if (n < 0) { // EINTR cannot happen here, os::write will take care of that - set_error(strerror(errno)); + set_error(os::strerror(errno)); os::close(file_descriptor()); set_file_descriptor(-1); return; diff --git a/hotspot/src/share/vm/services/lowMemoryDetector.cpp b/hotspot/src/share/vm/services/lowMemoryDetector.cpp index 42c500ad68e..6fbfc9a713d 100644 --- a/hotspot/src/share/vm/services/lowMemoryDetector.cpp +++ b/hotspot/src/share/vm/services/lowMemoryDetector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/java.hpp" diff --git a/hotspot/src/share/vm/services/threadService.cpp b/hotspot/src/share/vm/services/threadService.cpp index 7d49726d1ac..f89ff8b87bc 100644 --- a/hotspot/src/share/vm/services/threadService.cpp +++ b/hotspot/src/share/vm/services/threadService.cpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "memory/heapInspection.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp index 78c9335d228..16fabaca22f 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.cpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,6 +32,7 @@ #include "code/oopRecorder.hpp" #include "compiler/abstractCompiler.hpp" #include "compiler/oopMap.hpp" +#include "memory/resourceArea.hpp" #include "shark/llvmHeaders.hpp" #include "shark/sharkBuilder.hpp" #include "shark/sharkCodeBuffer.hpp" diff --git a/hotspot/src/share/vm/shark/sharkInliner.cpp b/hotspot/src/share/vm/shark/sharkInliner.cpp index 47465848d7d..4e56a8382e3 100644 --- a/hotspot/src/share/vm/shark/sharkInliner.cpp +++ b/hotspot/src/share/vm/shark/sharkInliner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,6 +29,7 @@ #include "ci/ciStreams.hpp" #include "interpreter/bytecodes.hpp" #include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "shark/sharkBlock.hpp" #include "shark/sharkConstant.hpp" #include "shark/sharkInliner.hpp" diff --git a/hotspot/src/share/vm/trace/trace.dtd b/hotspot/src/share/vm/trace/trace.dtd index a61984aaa26..155bea64c22 100644 --- a/hotspot/src/share/vm/trace/trace.dtd +++ b/hotspot/src/share/vm/trace/trace.dtd @@ -23,7 +23,7 @@ --> - + diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 5bcdfd1c4d0..3c0bcdaea96 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -30,572 +30,10 @@ ]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/hotspot/src/share/vm/trace/traceMacros.hpp b/hotspot/src/share/vm/trace/traceMacros.hpp index 23a155748ce..89f14c3691d 100644 --- a/hotspot/src/share/vm/trace/traceMacros.hpp +++ b/hotspot/src/share/vm/trace/traceMacros.hpp @@ -30,6 +30,7 @@ typedef u8 traceid; #define EVENT_THREAD_EXIT(thread) #define EVENT_THREAD_DESTRUCT(thread) #define TRACE_KLASS_CREATION(k, p, t) +#define TRACE_KLASS_DEFINITION(k, t) #define TRACE_INIT_KLASS_ID(k) #define TRACE_INIT_MODULE_ID(m) diff --git a/hotspot/src/share/vm/trace/traceevents.xml b/hotspot/src/share/vm/trace/traceevents.xml new file mode 100644 index 00000000000..83bb051b6f2 --- /dev/null +++ b/hotspot/src/share/vm/trace/traceevents.xml @@ -0,0 +1,618 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotspot/src/share/vm/trace/tracerelationdecls.xml b/hotspot/src/share/vm/trace/tracerelationdecls.xml new file mode 100644 index 00000000000..06a83aab418 --- /dev/null +++ b/hotspot/src/share/vm/trace/tracerelationdecls.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index 9ffc0bc100e..fced8fbb522 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,20 +29,26 @@ #include "utilities/bitMap.inline.hpp" #include "utilities/copy.hpp" -BitMap::BitMap(bm_word_t* map, idx_t size_in_bits) : - _map(map), _size(size_in_bits), _map_allocator(false) -{ - assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); -} - +STATIC_ASSERT(sizeof(BitMap::bm_word_t) == BytesPerWord); // "Implementation assumption." BitMap::BitMap(idx_t size_in_bits, bool in_resource_area) : - _map(NULL), _size(0), _map_allocator(false) + _map(NULL), _size(0) { - assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); resize(size_in_bits, in_resource_area); } +#ifdef ASSERT +void BitMap::verify_index(idx_t index) const { + assert(index < _size, "BitMap index out of bounds"); +} + +void BitMap::verify_range(idx_t beg_index, idx_t end_index) const { + assert(beg_index <= end_index, "BitMap range error"); + // Note that [0,0) and [size,size) are both valid ranges. + if (end_index != _size) verify_index(end_index); +} +#endif // #ifdef ASSERT + void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { idx_t old_size_in_words = size_in_words(); bm_word_t* old_map = map(); @@ -54,7 +60,7 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, MIN2(old_size_in_words, new_size_in_words)); } else { - _map = _map_allocator.reallocate(new_size_in_words); + _map = ArrayAllocator::reallocate(old_map, old_size_in_words, new_size_in_words); } if (new_size_in_words > old_size_in_words) { @@ -157,8 +163,10 @@ void BitMap::clear_large_range(idx_t beg, idx_t end) { idx_t beg_full_word = word_index_round_up(beg); idx_t end_full_word = word_index(end); - assert(end_full_word - beg_full_word >= 32, - "the range must include at least 32 bytes"); + if (end_full_word - beg_full_word < 32) { + clear_range(beg, end); + return; + } // The range includes at least one full word. clear_range_within_word(beg, bit_index(beg_full_word)); diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp index 6085602e7ac..e57264b2e9a 100644 --- a/hotspot/src/share/vm/utilities/bitMap.hpp +++ b/hotspot/src/share/vm/utilities/bitMap.hpp @@ -48,7 +48,6 @@ class BitMap VALUE_OBJ_CLASS_SPEC { } RangeSizeHint; private: - ArrayAllocator _map_allocator; bm_word_t* _map; // First word in bitmap idx_t _size; // Size of bitmap (in bits) @@ -101,9 +100,8 @@ class BitMap VALUE_OBJ_CLASS_SPEC { idx_t word_index_round_up(idx_t bit) const; // Verification. - inline void verify_index(idx_t index) const NOT_DEBUG_RETURN; - inline void verify_range(idx_t beg_index, idx_t end_index) const - NOT_DEBUG_RETURN; + void verify_index(idx_t index) const NOT_DEBUG_RETURN; + void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN; // Statistics. static idx_t* _pop_count_table; @@ -114,10 +112,10 @@ class BitMap VALUE_OBJ_CLASS_SPEC { public: // Constructs a bitmap with no map, and size 0. - BitMap() : _map(NULL), _size(0), _map_allocator(false) {} + BitMap() : _map(NULL), _size(0) {} // Constructs a bitmap with the given map and size. - BitMap(bm_word_t* map, idx_t size_in_bits); + BitMap(bm_word_t* map, idx_t size_in_bits) :_map(map), _size(size_in_bits) {} // Constructs an empty bitmap of the given size (that is, this clears the // new bitmap). Allocates the map array in resource area if @@ -307,36 +305,12 @@ class BitMap2D VALUE_OBJ_CLASS_SPEC { return _map.size() / _bits_per_slot; } - bool is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) { - verify_bit_within_slot_index(bit_within_slot_index); - return (bit_index(slot_index, bit_within_slot_index) < size_in_bits()); - } - - bool at(idx_t slot_index, idx_t bit_within_slot_index) const { - verify_bit_within_slot_index(bit_within_slot_index); - return _map.at(bit_index(slot_index, bit_within_slot_index)); - } - - void set_bit(idx_t slot_index, idx_t bit_within_slot_index) { - verify_bit_within_slot_index(bit_within_slot_index); - _map.set_bit(bit_index(slot_index, bit_within_slot_index)); - } - - void clear_bit(idx_t slot_index, idx_t bit_within_slot_index) { - verify_bit_within_slot_index(bit_within_slot_index); - _map.clear_bit(bit_index(slot_index, bit_within_slot_index)); - } - - void at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) { - verify_bit_within_slot_index(bit_within_slot_index); - _map.at_put(bit_index(slot_index, bit_within_slot_index), value); - } - - void at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) { - verify_bit_within_slot_index(bit_within_slot_index); - _map.at_put_grow(bit_index(slot_index, bit_within_slot_index), value); - } - + bool is_valid_index(idx_t slot_index, idx_t bit_within_slot_index); + bool at(idx_t slot_index, idx_t bit_within_slot_index) const; + void set_bit(idx_t slot_index, idx_t bit_within_slot_index); + void clear_bit(idx_t slot_index, idx_t bit_within_slot_index); + void at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value); + void at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value); void clear(); }; diff --git a/hotspot/src/share/vm/utilities/bitMap.inline.hpp b/hotspot/src/share/vm/utilities/bitMap.inline.hpp index b85c49aa243..57cb847ae63 100644 --- a/hotspot/src/share/vm/utilities/bitMap.inline.hpp +++ b/hotspot/src/share/vm/utilities/bitMap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,6 @@ #include "runtime/atomic.inline.hpp" #include "utilities/bitMap.hpp" -#ifdef ASSERT -inline void BitMap::verify_index(idx_t index) const { - assert(index < _size, "BitMap index out of bounds"); -} - -inline void BitMap::verify_range(idx_t beg_index, idx_t end_index) const { - assert(beg_index <= end_index, "BitMap range error"); - // Note that [0,0) and [size,size) are both valid ranges. - if (end_index != _size) verify_index(end_index); -} -#endif // #ifdef ASSERT - inline void BitMap::set_bit(idx_t bit) { verify_index(bit); *word_addr(bit) |= bit_mask(bit); @@ -105,7 +93,7 @@ inline void BitMap::set_range(idx_t beg, idx_t end, RangeSizeHint hint) { } inline void BitMap::clear_range(idx_t beg, idx_t end, RangeSizeHint hint) { - if (hint == small_range && end - beg == 1) { + if (end - beg == 1) { clear_bit(beg); } else { if (hint == large_range) { @@ -344,6 +332,36 @@ inline BitMap::idx_t BitMap::get_next_zero_offset(idx_t l_offset, return get_next_zero_offset_inline(l_offset, r_offset); } +inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) { + verify_bit_within_slot_index(bit_within_slot_index); + return (bit_index(slot_index, bit_within_slot_index) < size_in_bits()); +} + +inline bool BitMap2D::at(idx_t slot_index, idx_t bit_within_slot_index) const { + verify_bit_within_slot_index(bit_within_slot_index); + return _map.at(bit_index(slot_index, bit_within_slot_index)); +} + +inline void BitMap2D::set_bit(idx_t slot_index, idx_t bit_within_slot_index) { + verify_bit_within_slot_index(bit_within_slot_index); + _map.set_bit(bit_index(slot_index, bit_within_slot_index)); +} + +inline void BitMap2D::clear_bit(idx_t slot_index, idx_t bit_within_slot_index) { + verify_bit_within_slot_index(bit_within_slot_index); + _map.clear_bit(bit_index(slot_index, bit_within_slot_index)); +} + +inline void BitMap2D::at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) { + verify_bit_within_slot_index(bit_within_slot_index); + _map.at_put(bit_index(slot_index, bit_within_slot_index), value); +} + +inline void BitMap2D::at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) { + verify_bit_within_slot_index(bit_within_slot_index); + _map.at_put_grow(bit_index(slot_index, bit_within_slot_index), value); +} + inline void BitMap2D::clear() { _map.clear(); } diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index f0aa8371f17..f6fd336bca8 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -224,6 +224,11 @@ void report_vm_error(const char* file, int line, const char* error_msg, const ch va_end(detail_args); } +void report_vm_status_error(const char* file, int line, const char* error_msg, + int status, const char* detail) { + report_vm_error(file, line, error_msg, "error %s(%d), %s", os::errno_name(status), status, detail); +} + void report_fatal(const char* file, int line, const char* detail_fmt, ...) { if (Debugging || error_is_suppressed(file, line)) return; diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index 64e587351d4..398e38b6f84 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,13 @@ do { \ // an extra arg and use strerror to convert it to a meaningful string // like "Invalid argument", "out of memory" etc #define vmassert_status(p, status, msg) \ - vmassert(p, "error %s(%d), %s", strerror(status), status, msg) +do { \ + if (!(p)) { \ + report_vm_status_error(__FILE__, __LINE__, "assert(" #p ") failed", \ + status, msg); \ + BREAKPOINT; \ + } \ +} while (0) // For backward compatibility. #define assert_status(p, status, msg) vmassert_status(p, status, msg) @@ -209,6 +215,8 @@ void report_vm_error(const char* file, int line, const char* error_msg, void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...); #endif +void report_vm_status_error(const char* file, int line, const char* error_msg, + int status, const char* detail); void report_fatal(const char* file, int line, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(3, 4); void report_vm_out_of_memory(const char* file, int line, size_t size, VMErrorType vm_err_type, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(5, 6); diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp index 71b3e95a11a..fa4981986ef 100644 --- a/hotspot/src/share/vm/utilities/exceptions.cpp +++ b/hotspot/src/share/vm/utilities/exceptions.cpp @@ -27,6 +27,7 @@ #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" @@ -52,11 +53,11 @@ void ThreadShadow::set_pending_exception(oop exception, const char* file, int li } void ThreadShadow::clear_pending_exception() { - if (TraceClearedExceptions) { - if (_pending_exception != NULL) { - tty->print_cr("Thread::clear_pending_exception: cleared exception:"); - _pending_exception->print(); - } + if (_pending_exception != NULL && log_is_enabled(Debug, exceptions)) { + ResourceMark rm; + outputStream* logst = Log(exceptions)::debug_stream(); + logst->print("Thread::clear_pending_exception: cleared exception:"); + _pending_exception->print_on(logst); } _pending_exception = NULL; _exception_file = NULL; @@ -508,12 +509,13 @@ void Exceptions::log_exception(Handle exception, stringStream tempst) { ResourceMark rm; Symbol* message = java_lang_Throwable::detail_message(exception()); if (message != NULL) { - log_info(exceptions)("Exception <%s: %s> (" INTPTR_FORMAT ")\n thrown in %s", + log_info(exceptions)("Exception <%s: %s>\n thrown in %s", exception->print_value_string(), - message->as_C_string(), p2i(exception()), tempst.as_string()); + message->as_C_string(), + tempst.as_string()); } else { - log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ")\n thrown in %s", + log_info(exceptions)("Exception <%s>\n thrown in %s", exception->print_value_string(), - p2i(exception()), tempst.as_string()); + tempst.as_string()); } } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.cpp b/hotspot/src/share/vm/utilities/globalDefinitions.cpp index 24dedf470f2..98abb71dbe1 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp @@ -358,6 +358,20 @@ size_t lcm(size_t a, size_t b) { return size_t(result); } + +// Test that nth_bit macro and friends behave as +// expected, even with low-precedence operators. + +STATIC_ASSERT(nth_bit(3) == 0x8); +STATIC_ASSERT(nth_bit(1|2) == 0x8); + +STATIC_ASSERT(right_n_bits(3) == 0x7); +STATIC_ASSERT(right_n_bits(1|2) == 0x7); + +STATIC_ASSERT(left_n_bits(3) == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000)); +STATIC_ASSERT(left_n_bits(1|2) == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000)); + + #ifndef PRODUCT // For unit testing only class GlobalDefinitions { diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 4c2c0baf84a..3fa2c942f13 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -42,6 +42,12 @@ # include "utilities/globalDefinitions_xlc.hpp" #endif +#ifndef NOINLINE +#define NOINLINE +#endif +#ifndef ALWAYSINLINE +#define ALWAYSINLINE inline +#endif #ifndef PRAGMA_DIAG_PUSH #define PRAGMA_DIAG_PUSH #endif @@ -1084,9 +1090,9 @@ const intptr_t OneBit = 1; // only right_most bit set in a word // get a word with the n.th or the right-most or left-most n bits set // (note: #define used only so that they can be used in enum constant definitions) -#define nth_bit(n) (n >= BitsPerWord ? 0 : OneBit << (n)) +#define nth_bit(n) (((n) >= BitsPerWord) ? 0 : (OneBit << (n))) #define right_n_bits(n) (nth_bit(n) - 1) -#define left_n_bits(n) (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n))) +#define left_n_bits(n) (right_n_bits(n) << (((n) >= BitsPerWord) ? 0 : (BitsPerWord - (n)))) // bit-operations using a mask m inline void set_bits (intptr_t& x, intptr_t m) { x |= m; } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index bdcc095ba94..63a04ad80e0 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -322,4 +322,8 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #define THREAD_LOCAL_DECL __thread #endif +// Inlining support +#define NOINLINE __attribute__ ((noinline)) +#define ALWAYSINLINE __attribute__ ((always_inline)) + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp index 7e1fa1917e9..8b127114ca0 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -277,4 +277,8 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #define THREAD_LOCAL_DECL __thread #endif +// Inlining support +#define NOINLINE +#define ALWAYSINLINE __attribute__((always_inline)) + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_SPARCWORKS_HPP diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index 038f348a434..c387fe72a6d 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,4 +240,11 @@ inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { #define THREAD_LOCAL_DECL __declspec( thread ) #endif +// Inlining support +// MSVC has '__declspec(noinline)' but according to the official documentation +// it only applies to member functions. There are reports though which pretend +// that it also works for freestanding functions. +#define NOINLINE __declspec(noinline) +#define ALWAYSINLINE __forceinline + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_VISCPP_HPP diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp index 1892e1a5cb3..68e204d45f0 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -184,4 +184,8 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #define THREAD_LOCAL_DECL __thread #endif +// Inlining support +#define NOINLINE +#define ALWAYSINLINE __attribute__((always_inline)) + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP diff --git a/hotspot/src/share/vm/utilities/internalVMTests.cpp b/hotspot/src/share/vm/utilities/internalVMTests.cpp index 7b20c0b6e09..4adaf307425 100644 --- a/hotspot/src/share/vm/utilities/internalVMTests.cpp +++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp @@ -67,8 +67,16 @@ void InternalVMTests::run() { run_unit_test(Test_linked_list); run_unit_test(TestChunkedList_test); run_unit_test(JSON_test); - run_unit_test(Test_log_length); + run_unit_test(Test_logtarget); + run_unit_test(Test_logstream); + run_unit_test(Test_loghandle); + run_unit_test(Test_logtargethandle); + run_unit_test(Test_log_gctracetime); run_unit_test(Test_configure_stdout); + run_unit_test(Test_logconfiguration_subscribe); + run_unit_test(Test_log_prefix); + run_unit_test(Test_log_big); + run_unit_test(Test_logtagset_duplicates); run_unit_test(DirectivesParser_test); run_unit_test(Test_TempNewSymbol); #if INCLUDE_VM_STRUCTS diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index ccdb90813b7..40e92c7a64a 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,17 @@ #define NOT_COMPILER2(code) code #endif // COMPILER2 +// COMPILER2 or JVMCI +#if defined(COMPILER2) || INCLUDE_JVMCI +#define COMPILER2_OR_JVMCI 1 +#define COMPILER2_OR_JVMCI_PRESENT(code) code +#define NOT_COMPILER2_OR_JVMCI(code) +#else +#define COMPILER2_OR_JVMCI 0 +#define COMPILER2_OR_JVMCI_PRESENT(code) +#define NOT_COMPILER2_OR_JVMCI(code) code +#endif + #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 869e252aa83..0f1057ed1ce 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -24,8 +24,6 @@ #include "precompiled.hpp" #include "compiler/compileLog.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/gcId.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/os.hpp" @@ -504,7 +502,7 @@ fileStream::fileStream(const char* file_name) { if (_file != NULL) { _need_close = true; } else { - warning("Cannot open file %s due to %s\n", file_name, strerror(errno)); + warning("Cannot open file %s due to %s\n", file_name, os::strerror(errno)); _need_close = false; } } @@ -514,7 +512,7 @@ fileStream::fileStream(const char* file_name, const char* opentype) { if (_file != NULL) { _need_close = true; } else { - warning("Cannot open file %s due to %s\n", file_name, strerror(errno)); + warning("Cannot open file %s due to %s\n", file_name, os::strerror(errno)); _need_close = false; } } @@ -1099,14 +1097,3 @@ bool networkStream::connect(const char *ip, short port) { } #endif - -void logStream::write(const char* s, size_t len) { - if (len > 0 && s[len - 1] == '\n') { - _current_line.write(s, len - 1); - _log_func("%s", _current_line.as_string()); - _current_line.reset(); - } else { - _current_line.write(s, len); - } - update_position(s, len); -} diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index 9c2b6979879..72ea5143afb 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -29,7 +29,6 @@ #include "runtime/timer.hpp" #include "utilities/globalDefinitions.hpp" -class GCId; DEBUG_ONLY(class ResourceMark;) // Output streams for printing @@ -247,18 +246,6 @@ class fdStream : public outputStream { void flush() {}; }; -class logStream : public outputStream { -private: - stringStream _current_line; - void (*_log_func)(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2); -public: - void write(const char* s, size_t len); - logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {} - ~logStream() { - guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?"); - } -}; - void ostream_init(); void ostream_init_log(); void ostream_exit(); diff --git a/hotspot/src/share/vm/utilities/stack.inline.hpp b/hotspot/src/share/vm/utilities/stack.inline.hpp index 4d4c17bcfff..d1cb7690b85 100644 --- a/hotspot/src/share/vm/utilities/stack.inline.hpp +++ b/hotspot/src/share/vm/utilities/stack.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,17 +27,6 @@ #include "utilities/stack.hpp" -// Stack is used by the GC code and in some hot paths a lot of the Stack -// code gets inlined. This is generally good, but when too much code has -// been inlined, no further inlining is allowed by GCC. Therefore we need -// to prevent parts of the slow path in Stack to be inlined to allow other -// code to be. -#if defined(TARGET_COMPILER_gcc) -#define NOINLINE __attribute__((noinline)) -#else -#define NOINLINE -#endif - template StackBase::StackBase(size_t segment_size, size_t max_cache_size, size_t max_size): _seg_size(segment_size), @@ -151,6 +140,11 @@ void Stack::free(E* addr, size_t bytes) FREE_C_HEAP_ARRAY(char, (char*) addr); } +// Stack is used by the GC code and in some hot paths a lot of the Stack +// code gets inlined. This is generally good, but when too much code has +// been inlined, no further inlining is allowed by GCC. Therefore we need +// to prevent parts of the slow path in Stack to be inlined to allow other +// code to be. template NOINLINE void Stack::push_segment() { @@ -280,6 +274,4 @@ E* StackIterator::next_addr() return _cur_seg + --_cur_seg_size; } -#undef NOINLINE - #endif // SHARE_VM_UTILITIES_STACK_INLINE_HPP diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 2d0942349be..0f128c1f286 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1260,8 +1260,9 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt out.print_raw("#\n# Compiler replay data is saved as:\n# "); out.print_raw_cr(buffer); } else { + int e = errno; out.print_raw("#\n# Can't open file to dump replay data. Error: "); - out.print_raw_cr(strerror(os::get_last_error())); + out.print_raw_cr(os::strerror(e)); } } } @@ -1301,7 +1302,8 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt out.print_raw_cr("\" ..."); if (os::fork_and_exec(cmd) < 0) { - out.print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno); + out.print_cr("os::fork_and_exec failed: %s (%s=%d)", + os::strerror(errno), os::errno_name(errno), errno); } } @@ -1359,7 +1361,8 @@ void VM_ReportJavaOutOfMemory::doit() { tty->print_cr("\"%s\"...", cmd); if (os::fork_and_exec(cmd) < 0) { - tty->print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno); + tty->print_cr("os::fork_and_exec failed: %s (%s=%d)", + os::strerror(errno), os::errno_name(errno), errno); } } } diff --git a/hotspot/src/share/vm/utilities/xmlstream.cpp b/hotspot/src/share/vm/utilities/xmlstream.cpp index 0233639fe85..829de94dd4d 100644 --- a/hotspot/src/share/vm/utilities/xmlstream.cpp +++ b/hotspot/src/share/vm/utilities/xmlstream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "code/nmethod.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile index 5c703e9d5cc..3468e65bcac 100644 --- a/hotspot/test/Makefile +++ b/hotspot/test/Makefile @@ -159,6 +159,24 @@ ifdef TESTNATIVE_DIR JTREG_NATIVE_PATH = -nativepath:$(shell $(GETMIXEDPATH) "$(TESTNATIVE_DIR)/hotspot/jtreg/native") endif +# jtreg failure handler config +ifeq ($(FAILURE_HANDLER_DIR), ) + ifneq ($(TESTNATIVE_DIR), ) + FAILURE_HANDLER_DIR := $(TESTNATIVE_DIR)/failure_handler + endif +endif +ifneq ($(FAILURE_HANDLER_DIR), ) + FAILURE_HANDLER_DIR_MIXED := $(shell $(GETMIXEDPATH) "$(FAILURE_HANDLER_DIR)") + JTREG_FAILURE_HANDLER_OPTIONS := \ + -timeoutHandlerDir:$(FAILURE_HANDLER_DIR_MIXED)/jtregFailureHandler.jar \ + -observerDir:$(FAILURE_HANDLER_DIR_MIXED)/jtregFailureHandler.jar \ + -timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \ + -observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver + ifeq ($(PLATFORM), windows) + JTREG_FAILURE_HANDLER_OPTIONS += -J-Djava.library.path="$(FAILURE_HANDLER_DIR_MIXED)" + endif +endif + # Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip ifdef JPRT_ARCHIVE_BUNDLE @@ -322,6 +340,7 @@ jtreg_tests: prep $(PRODUCT_HOME) $(JTREG) -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTwork") \ -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ $(JTREG_NATIVE_PATH) \ + $(JTREG_FAILURE_HANDLER_OPTIONS) \ $(JTREG_EXCLUSIONS) \ $(JTREG_TEST_OPTIONS) \ $(TEST_SELECTION) \ diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 0a2acb997da..e74ab567871 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -52,6 +52,25 @@ hotspot_all = \ / + +hotspot_compiler = \ + compiler + +hotspot_gc = \ + gc + +hotspot_runtime = \ + runtime + +hotspot_serviceability = \ + serviceability + +hotspot_misc = \ + / \ + -:hotspot_compiler \ + -:hotspot_gc \ + -:hotspot_runtime \ + -:hotspot_serviceability # Full JDK can run all tests # @@ -230,6 +249,7 @@ compact1_minimal = \ # needs_g1gc = \ compiler/regalloc/C1ObjectSpillInLogicOp.java \ + gc/TestHumongousReferenceObject.java \ gc/TestSmallHeap.java \ gc/TestSystemGC.java \ gc/arguments/TestAlignmentToUseLargePages.java \ @@ -253,7 +273,7 @@ needs_g1gc = \ hotspot_native_sanity = \ native_sanity -hotspot_compiler_1 = \ +hotspot_fast_compiler_1 = \ compiler/arraycopy/ \ compiler/c1/ \ compiler/c2/ \ @@ -268,7 +288,7 @@ hotspot_compiler_1 = \ -compiler/c2/7070134 \ -compiler/c2/8004867 -hotspot_compiler_2 = \ +hotspot_fast_compiler_2 = \ compiler/classUnloading/ \ compiler/codecache/ \ compiler/codegen/ \ @@ -287,7 +307,7 @@ hotspot_compiler_2 = \ -compiler/codecache/stress \ -compiler/gcbarriers/PreserveFPRegistersTest.java -hotspot_compiler_3 = \ +hotspot_fast_compiler_3 = \ compiler/intrinsics/ \ compiler/jsr292/ \ compiler/loopopts/ \ @@ -308,22 +328,27 @@ hotspot_compiler_3 = \ -compiler/loopopts/7052494 \ -compiler/runtime/6826736 -hotspot_compiler_closed = \ +hotspot_fast_compiler_closed = \ sanity/ExecuteInternalVMTests.java -hotspot_gc = \ +hotspot_fast_gc_1 = \ + gc/g1/ + +hotspot_fast_gc_2 = \ sanity/ExecuteInternalVMTests.java \ gc/ \ - -gc/g1/TestGreyReclaimedHumongousObjects.java \ + -gc/g1/ \ + -gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java \ + -gc/cms/TestMBeanCMS.java \ -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java -hotspot_gc_closed = \ +hotspot_fast_gc_closed = \ sanity/ExecuteInternalVMTests.java -hotspot_gc_gcold = \ +hotspot_fast_gc_gcold = \ stress/gc/TestGCOld.java -hotspot_runtime = \ +hotspot_fast_runtime = \ runtime/ \ -runtime/ErrorHandling/ErrorHandler.java \ -runtime/RedefineObject/TestRedefineObject.java \ @@ -335,6 +360,15 @@ hotspot_runtime = \ -runtime/memory/ReserveMemory.java \ -runtime/memory/RunUnitTestsConcurrently.java \ -runtime/Unsafe/RangeCheck.java \ + -runtime/SelectionResolution/AbstractMethodErrorTest.java \ + -runtime/SelectionResolution/IllegalAccessErrorTest.java \ + -runtime/SelectionResolution/InvokeInterfaceICCE.java \ + -runtime/SelectionResolution/InvokeInterfaceSuccessTest.java \ + -runtime/SelectionResolution/InvokeSpecialICCE.java \ + -runtime/SelectionResolution/InvokeSpecialSuccessTest.java \ + -runtime/SelectionResolution/InvokeStaticICCE.java \ + -runtime/SelectionResolution/InvokeVirtualICCE.java \ + -runtime/SelectionResolution/InvokeVirtualSuccessTest.java \ -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ -runtime/SharedArchiveFile/DefaultUseWithClient.java \ -runtime/Thread/CancellableThreadTest.java \ @@ -343,21 +377,21 @@ hotspot_runtime = \ sanity/ \ testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java -hotspot_serviceability = \ +hotspot_fast_serviceability = \ sanity/ExecuteInternalVMTests.java \ serviceability/dcmd/compiler \ serviceability/logging hotspot_jprt = \ - :hotspot_compiler_1 \ - :hotspot_compiler_2 \ - :hotspot_compiler_3 \ - :hotspot_compiler_closed \ - :hotspot_gc \ - :hotspot_gc_closed \ - :hotspot_gc_gcold \ - :hotspot_runtime \ - :hotspot_serviceability + :hotspot_fast_compiler_1 \ + :hotspot_fast_compiler_2 \ + :hotspot_fast_compiler_3 \ + :hotspot_fast_compiler_closed \ + :hotspot_fast_gc \ + :hotspot_fast_gc_closed \ + :hotspot_fast_gc_gcold \ + :hotspot_fast_runtime \ + :hotspot_fast_serviceability #All tests that depends on nashorn extension. # diff --git a/hotspot/test/compiler/arguments/CheckCICompilerCount.java b/hotspot/test/compiler/arguments/CheckCICompilerCount.java index b07af8da62e..f568dbec0dd 100644 --- a/hotspot/test/compiler/arguments/CheckCICompilerCount.java +++ b/hotspot/test/compiler/arguments/CheckCICompilerCount.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,7 +160,7 @@ public class CheckCICompilerCount { } catch (RuntimeException e) { // Check if tiered compilation is available in this JVM // Version. Throw exception only if it is available. - if (!(tiered && out.getOutput().contains("TieredCompilation is disabled in this release."))) { + if (!(tiered && out.getOutput().contains("-XX:+TieredCompilation not supported in this VM"))) { throw new RuntimeException(e); } } diff --git a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java index cdb2a27ae03..653536fad72 100644 --- a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java +++ b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -344,7 +344,7 @@ public class CheckCompileThresholdScaling { } catch (RuntimeException e) { // Check if tiered compilation is available in this JVM // Version. Throw exception only if it is available. - if (!(tiered && out.getOutput().contains("TieredCompilation is disabled in this release."))) { + if (!(tiered && out.getOutput().contains("-XX:+TieredCompilation not supported in this VM"))) { throw new RuntimeException(e); } } diff --git a/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java b/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java index c002cdbe94b..45ae4b88e9a 100644 --- a/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java +++ b/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public class CheckSegmentedCodeCache { out.shouldContain(NON_METHOD); } catch (RuntimeException e) { // Check if TieredCompilation is disabled (in a client VM) - if(!out.getOutput().contains("TieredCompilation is disabled in this release.")) { + if(!out.getOutput().contains("-XX:+TieredCompilation not supported in this VM")) { // Code cache is not segmented throw new RuntimeException("No code cache segmentation."); } diff --git a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java index 7a4539a684f..365ca7bbfb2 100644 --- a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java +++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,25 +21,14 @@ * questions. */ -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; - -import jdk.test.lib.*; - /* * @test * @bug 8050079 * @summary Compiles a monomorphic call to finalizeObject() on a modified java.lang.Object to test C1 CHA. - * @library /testlibrary - * @modules java.base/jdk.internal.misc - * java.management - * java.base/jdk.internal - * @ignore 8132924 - * @compile -XDignore.symbol.file java/lang/Object.java TestMonomorphicObjectCall.java - * @run main TestMonomorphicObjectCall + * @build java.base/java.lang.Object + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-VerifyDependencies + * -XX:TieredStopAtLevel=1 -XX:CompileOnly=TestMonomorphicObjectCall::callFinalize + * -XX:CompileOnly=java.lang.Object::finalizeObject TestMonomorphicObjectCall */ public class TestMonomorphicObjectCall { @@ -51,32 +40,7 @@ public class TestMonomorphicObjectCall { } public static void main(String[] args) throws Throwable { - if (args.length == 0) { - byte[] bytecode = Files.readAllBytes(Paths.get(System.getProperty("test.classes") + File.separator + - "java" + File.separator + "lang" + File.separator + "Object.class")); - ClassFileInstaller.writeClassToDisk("java.lang.Object", bytecode, "mods/java.base"); - // Execute new instance with modified java.lang.Object - executeTestJvm(); - } else { - // Trigger compilation of 'callFinalize' - callFinalize(new Object()); - } - } - - public static void executeTestJvm() throws Throwable { - // Execute test with modified version of java.lang.Object - // in -Xbootclasspath. - String[] vmOpts = new String[] { - "-Xpatch:mods", - "-Xcomp", - "-XX:+IgnoreUnrecognizedVMOptions", - "-XX:-VerifyDependencies", - "-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize", - "-XX:CompileOnly=Object::finalizeObject", - "-XX:TieredStopAtLevel=1", - TestMonomorphicObjectCall.class.getName(), - "true"}; - OutputAnalyzer output = ProcessTools.executeTestJvm(vmOpts); - output.shouldHaveExitValue(0); + // Trigger compilation of 'callFinalize' + callFinalize(new Object()); } } diff --git a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/java/lang/Object.java b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/java.base/java/lang/Object.java similarity index 97% rename from hotspot/test/compiler/dependencies/MonomorphicObjectCall/java/lang/Object.java rename to hotspot/test/compiler/dependencies/MonomorphicObjectCall/java.base/java/lang/Object.java index f63c62684d0..ada2cd7bc20 100644 --- a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/java/lang/Object.java +++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/java.base/java/lang/Object.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java b/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java index 4b310e9069e..4d7b274c284 100644 --- a/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java +++ b/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java @@ -28,7 +28,7 @@ * @summary Add C2 x86 intrinsic for BigInteger::mulAdd() method * * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch - * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-UseSquareToLenIntrinsic -XX:-UseMultiplyToLenIntrinsic + * -XX:+IgnoreUnrecognizedVMOptions -XX:-UseSquareToLenIntrinsic -XX:-UseMultiplyToLenIntrinsic * -XX:CompileCommand=dontinline,TestMulAdd::main * -XX:CompileCommand=option,TestMulAdd::base_multiply,ccstr,DisableIntrinsic,_mulAdd * -XX:CompileCommand=option,java.math.BigInteger::multiply,ccstr,DisableIntrinsic,_mulAdd diff --git a/hotspot/test/compiler/jsr292/InvokerGC.java b/hotspot/test/compiler/jsr292/InvokerGC.java new file mode 100644 index 00000000000..c0a47184f06 --- /dev/null +++ b/hotspot/test/compiler/jsr292/InvokerGC.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8067247 + * @library /test/lib /compiler/whitebox / + * @run main/bootclasspath -Xcomp -Xbatch + * -XX:CompileCommand=compileonly,InvokerGC::test + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * InvokerGC + */ + +import java.lang.invoke.*; +import sun.hotspot.WhiteBox; + +public class InvokerGC { + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + static MethodHandle mh; + static { + try { + mh = MethodHandles.lookup().findStatic(InvokerGC.class, "dummy", MethodType.methodType(void.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static void dummy() {} + + static void test() { + try { + mh.invoke(); + } catch (Throwable e) { + throw new Error(e); + } + } + + public static void main(String[] args) throws Throwable { + mh.invoke(); // Pre-generate an invoker for ()V signature + + test(); // trigger method compilation + test(); + + WB.fullGC(); // WB.fullGC has always clear softref policy. + + test(); + + WB.clearInlineCaches(true); // Preserve static stubs. + + test(); // Trigger call site re-resolution. Invoker LambdaForm should stay the same. + + System.out.println("TEST PASSED"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java index df4046d889f..ed05fe8a188 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java @@ -28,8 +28,8 @@ import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import sun.hotspot.WhiteBox; -import sun.reflect.ConstantPool; -import sun.reflect.ConstantPool.Tag; +import jdk.internal.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool.Tag; import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java index 783b26188e9..12310ddf3ce 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -34,8 +34,8 @@ import java.util.Map; import jdk.internal.misc.SharedSecrets; import jdk.internal.org.objectweb.asm.Opcodes; import sun.hotspot.WhiteBox; -import sun.reflect.ConstantPool; -import sun.reflect.ConstantPool.Tag; +import jdk.internal.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool.Tag; /** * Class contains hard-coded constant pool tables for dummy classes used for diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java index 21be817e7db..88629b101a3 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java index b17763bd3ac..87020af5181 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java index 1c23c7458c1..3b64af7ffea 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java index 16add7012e0..4f1cac0fb47 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java index 9dc255210fb..65f6ec0efdf 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java index adcf6cb85f4..391a9dc12f6 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java index b63fa7af5ee..812c2586165 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java @@ -28,7 +28,8 @@ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @library ../common/patches - * @modules java.base/jdk.internal.org.objectweb.asm + * @modules java.base/jdk.internal.reflect + * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot * jdk.vm.ci/jdk.vm.ci.code @@ -76,7 +77,7 @@ public class MethodIsIgnoredBySecurityStackWalkTest { testCases.put(aClass.getMethod("invoke", Object.class, Object[].class), true); - aClass = Class.forName("sun.reflect.NativeMethodAccessorImpl"); + aClass = Class.forName("jdk.internal.reflect.NativeMethodAccessorImpl"); testCases.put(aClass.getMethod("invoke", Object.class, Object[].class), true); testCases.put(aClass.getDeclaredMethod("invoke0", Method.class, diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java index 285f0ff77af..cd16f512e52 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * jdk.vm.ci/jdk.vm.ci.hotspot * jdk.vm.ci/jdk.vm.ci.meta diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java index 2d7145dec15..3c004ce0c09 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java index 1e0f269e8cd..6a1cfb7623e 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java @@ -29,6 +29,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree * jdk.vm.ci/jdk.vm.ci.hotspot diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java index cad8ccd9f31..92f7a19b5e0 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib / * @library ../common/patches * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.reflect * java.base/jdk.internal.org.objectweb.asm * jdk.vm.ci/jdk.vm.ci.hotspot * jdk.vm.ci/jdk.vm.ci.meta diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java index 5e6f972a883..1110b1eac31 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java @@ -47,14 +47,20 @@ * compiler.jvmci.common.CTVMUtilities * compiler.jvmci.common.testcases.SimpleClass * jdk.test.lib.Asserts + * jdk.test.lib.Utils * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI - * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=false + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.failoninit=false + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed + * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI -XX:JVMCINMethodSizeLimit=0 + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.failoninit=false * compiler.jvmci.events.JvmciNotifyInstallEventTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-EnableJVMCI * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed - * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=true + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.failoninit=true * compiler.jvmci.events.JvmciNotifyInstallEventTest */ @@ -64,6 +70,7 @@ import compiler.jvmci.common.CTVMUtilities; import compiler.jvmci.common.testcases.SimpleClass; import jdk.test.lib.Asserts; import java.lang.reflect.Method; +import jdk.test.lib.Utils; import jdk.vm.ci.hotspot.HotSpotVMEventListener; import jdk.vm.ci.code.CompiledCode; import jdk.vm.ci.code.InstalledCode; @@ -79,8 +86,8 @@ import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { private static final String METHOD_NAME = "testMethod"; - private static final boolean IS_POSITIVE = !Boolean.getBoolean( - "compiler.jvmci.events.JvmciNotifyInstallEventTest.noevent"); + private static final boolean FAIL_ON_INIT = !Boolean.getBoolean( + "compiler.jvmci.events.JvmciNotifyInstallEventTest.failoninit"); private static volatile int gotInstallNotification = 0; public static void main(String args[]) { @@ -91,12 +98,12 @@ public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { if (gotInstallNotification != 0) { throw new Error("Got install notification before test actions"); } - HotSpotCodeCacheProvider codeCache = null; + HotSpotCodeCacheProvider codeCache; try { codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime() .getHostJVMCIBackend().getCodeCache(); } catch (InternalError ie) { - if (IS_POSITIVE) { + if (FAIL_ON_INIT) { throw new AssertionError( "Got unexpected InternalError trying to get code cache", ie); @@ -104,7 +111,7 @@ public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { // passed return; } - Asserts.assertTrue(IS_POSITIVE, + Asserts.assertTrue(FAIL_ON_INIT, "Haven't caught InternalError in negative case"); Method testMethod; try { @@ -114,18 +121,30 @@ public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { } HotSpotResolvedJavaMethod method = CTVMUtilities .getResolvedMethod(SimpleClass.class, testMethod); - HotSpotCompiledCode compiledCode = new HotSpotCompiledCode(METHOD_NAME, new byte[0], 0, new Site[0], - new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], 16, - new DataPatch[0], false, 0, null); - codeCache.installCode(method, compiledCode, /* installedCode = */ null, /* speculationLog = */ null, - /* isDefault = */ false); + HotSpotCompiledCode compiledCode = new HotSpotCompiledCode(METHOD_NAME, + new byte[0], 0, new Site[0], new Assumption[0], + new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], + 16, new DataPatch[0], false, 0, null); + codeCache.installCode(method, compiledCode, /* installedCode = */ null, + /* speculationLog = */ null, /* isDefault = */ false); Asserts.assertEQ(gotInstallNotification, 1, "Got unexpected event count after 1st install attempt"); // since "empty" compilation result is ok, a second attempt should be ok - codeCache.installCode(method, compiledCode, /* installedCode = */ null, /* speculationLog = */ null, - /* isDefault = */ false); + codeCache.installCode(method, compiledCode, /* installedCode = */ null, + /* speculationLog = */ null, /* isDefault = */ false); Asserts.assertEQ(gotInstallNotification, 2, "Got unexpected event count after 2nd install attempt"); + // and an incorrect cases + Utils.runAndCheckException(() -> { + codeCache.installCode(method, null, null, null, true); + }, NullPointerException.class); + Asserts.assertEQ(gotInstallNotification, 2, + "Got unexpected event count after 3rd install attempt"); + Utils.runAndCheckException(() -> { + codeCache.installCode(null, null, null, null, true); + }, NullPointerException.class); + Asserts.assertEQ(gotInstallNotification, 2, + "Got unexpected event count after 4th install attempt"); } @Override diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 2011bc0c863..9c904502ef9 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -25,7 +25,8 @@ * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library ../../../../../ - * @modules jdk.vm.ci/jdk.vm.ci.meta + * @modules java.base/jdk.internal.reflect + * jdk.vm.ci/jdk.vm.ci.meta * jdk.vm.ci/jdk.vm.ci.runtime * jdk.vm.ci/jdk.vm.ci.common * @build jdk.vm.ci.runtime.test.TestResolvedJavaType @@ -70,7 +71,7 @@ import jdk.vm.ci.meta.TrustedInterface; import org.junit.Test; -import sun.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool; /** * Tests for {@link ResolvedJavaType}. diff --git a/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java b/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java index 57a61459192..9dc2e1422ac 100644 --- a/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java +++ b/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java @@ -26,10 +26,19 @@ * @test * @bug 8073184 * @summary CastII that guards counted loops confuses range check elimination with LoopLimitCheck off - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LoopLimitCheck -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck * */ +/* + * The test was originally run with + * + * -XX:+UnlockDiagnosticVMOptions -XX:-LoopLimitCheck + * + * to trigger a problem with code guarded with !LoopLimitCheck. + * JDK-8072422 has removed that code but kept the test because the + * test generates an interesting graph shape. + */ public class TestCastIINoLoopLimitCheck { static void m(int i, int index, char[] buf) { diff --git a/hotspot/test/compiler/runtime/6859338/Test6859338.java b/hotspot/test/compiler/runtime/6859338/Test6859338.java index 73576840db1..03d68126f66 100644 --- a/hotspot/test/compiler/runtime/6859338/Test6859338.java +++ b/hotspot/test/compiler/runtime/6859338/Test6859338.java @@ -27,7 +27,7 @@ * @bug 6859338 * @summary Assertion failure in sharedRuntime.cpp * - * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-InlineObjectHash -Xbatch -XX:-ProfileInterpreter Test6859338 + * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:-InlineObjectHash -Xbatch -XX:-ProfileInterpreter Test6859338 */ public class Test6859338 { diff --git a/hotspot/test/gc/TestHumongousReferenceObject.java b/hotspot/test/gc/TestHumongousReferenceObject.java new file mode 100644 index 00000000000..728b8911de8 --- /dev/null +++ b/hotspot/test/gc/TestHumongousReferenceObject.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General 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 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 License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.vm.annotation.Contended; + +/* + * @test + * @summary Test that verifies that iteration over large, plain Java objects, that potentially cross region boundaries on G1, with references in them works. + * @requires vm.gc == "null" + * @bug 8151499 + * @modules java.base/jdk.internal.vm.annotation + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseParallelGC -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=1M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=2M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=8M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + */ +public class TestHumongousReferenceObject { + + /* + Due to 300 fields with 8K @Contended padding around each field, it takes 2.4M bytes per instance. + With small G1 regions, it is bound to cross regions. G1 should properly (card) mark the object nevertheless. + With 1G heap, it is enough to allocate ~400 of these objects to provoke at least one GC. + */ + + static volatile Object instance; + + public static void main(String[] args) { + for (int c = 0; c < 400; c++) { + instance = new TestHumongousReferenceObject(); + } + } + + @Contended Integer int_1 = new Integer(1); + @Contended Integer int_2 = new Integer(2); + @Contended Integer int_3 = new Integer(3); + @Contended Integer int_4 = new Integer(4); + @Contended Integer int_5 = new Integer(5); + @Contended Integer int_6 = new Integer(6); + @Contended Integer int_7 = new Integer(7); + @Contended Integer int_8 = new Integer(8); + @Contended Integer int_9 = new Integer(9); + @Contended Integer int_10 = new Integer(10); + @Contended Integer int_11 = new Integer(11); + @Contended Integer int_12 = new Integer(12); + @Contended Integer int_13 = new Integer(13); + @Contended Integer int_14 = new Integer(14); + @Contended Integer int_15 = new Integer(15); + @Contended Integer int_16 = new Integer(16); + @Contended Integer int_17 = new Integer(17); + @Contended Integer int_18 = new Integer(18); + @Contended Integer int_19 = new Integer(19); + @Contended Integer int_20 = new Integer(20); + @Contended Integer int_21 = new Integer(21); + @Contended Integer int_22 = new Integer(22); + @Contended Integer int_23 = new Integer(23); + @Contended Integer int_24 = new Integer(24); + @Contended Integer int_25 = new Integer(25); + @Contended Integer int_26 = new Integer(26); + @Contended Integer int_27 = new Integer(27); + @Contended Integer int_28 = new Integer(28); + @Contended Integer int_29 = new Integer(29); + @Contended Integer int_30 = new Integer(30); + @Contended Integer int_31 = new Integer(31); + @Contended Integer int_32 = new Integer(32); + @Contended Integer int_33 = new Integer(33); + @Contended Integer int_34 = new Integer(34); + @Contended Integer int_35 = new Integer(35); + @Contended Integer int_36 = new Integer(36); + @Contended Integer int_37 = new Integer(37); + @Contended Integer int_38 = new Integer(38); + @Contended Integer int_39 = new Integer(39); + @Contended Integer int_40 = new Integer(40); + @Contended Integer int_41 = new Integer(41); + @Contended Integer int_42 = new Integer(42); + @Contended Integer int_43 = new Integer(43); + @Contended Integer int_44 = new Integer(44); + @Contended Integer int_45 = new Integer(45); + @Contended Integer int_46 = new Integer(46); + @Contended Integer int_47 = new Integer(47); + @Contended Integer int_48 = new Integer(48); + @Contended Integer int_49 = new Integer(49); + @Contended Integer int_50 = new Integer(50); + @Contended Integer int_51 = new Integer(51); + @Contended Integer int_52 = new Integer(52); + @Contended Integer int_53 = new Integer(53); + @Contended Integer int_54 = new Integer(54); + @Contended Integer int_55 = new Integer(55); + @Contended Integer int_56 = new Integer(56); + @Contended Integer int_57 = new Integer(57); + @Contended Integer int_58 = new Integer(58); + @Contended Integer int_59 = new Integer(59); + @Contended Integer int_60 = new Integer(60); + @Contended Integer int_61 = new Integer(61); + @Contended Integer int_62 = new Integer(62); + @Contended Integer int_63 = new Integer(63); + @Contended Integer int_64 = new Integer(64); + @Contended Integer int_65 = new Integer(65); + @Contended Integer int_66 = new Integer(66); + @Contended Integer int_67 = new Integer(67); + @Contended Integer int_68 = new Integer(68); + @Contended Integer int_69 = new Integer(69); + @Contended Integer int_70 = new Integer(70); + @Contended Integer int_71 = new Integer(71); + @Contended Integer int_72 = new Integer(72); + @Contended Integer int_73 = new Integer(73); + @Contended Integer int_74 = new Integer(74); + @Contended Integer int_75 = new Integer(75); + @Contended Integer int_76 = new Integer(76); + @Contended Integer int_77 = new Integer(77); + @Contended Integer int_78 = new Integer(78); + @Contended Integer int_79 = new Integer(79); + @Contended Integer int_80 = new Integer(80); + @Contended Integer int_81 = new Integer(81); + @Contended Integer int_82 = new Integer(82); + @Contended Integer int_83 = new Integer(83); + @Contended Integer int_84 = new Integer(84); + @Contended Integer int_85 = new Integer(85); + @Contended Integer int_86 = new Integer(86); + @Contended Integer int_87 = new Integer(87); + @Contended Integer int_88 = new Integer(88); + @Contended Integer int_89 = new Integer(89); + @Contended Integer int_90 = new Integer(90); + @Contended Integer int_91 = new Integer(91); + @Contended Integer int_92 = new Integer(92); + @Contended Integer int_93 = new Integer(93); + @Contended Integer int_94 = new Integer(94); + @Contended Integer int_95 = new Integer(95); + @Contended Integer int_96 = new Integer(96); + @Contended Integer int_97 = new Integer(97); + @Contended Integer int_98 = new Integer(98); + @Contended Integer int_99 = new Integer(99); + @Contended Integer int_100 = new Integer(100); + @Contended Integer int_101 = new Integer(101); + @Contended Integer int_102 = new Integer(102); + @Contended Integer int_103 = new Integer(103); + @Contended Integer int_104 = new Integer(104); + @Contended Integer int_105 = new Integer(105); + @Contended Integer int_106 = new Integer(106); + @Contended Integer int_107 = new Integer(107); + @Contended Integer int_108 = new Integer(108); + @Contended Integer int_109 = new Integer(109); + @Contended Integer int_110 = new Integer(110); + @Contended Integer int_111 = new Integer(111); + @Contended Integer int_112 = new Integer(112); + @Contended Integer int_113 = new Integer(113); + @Contended Integer int_114 = new Integer(114); + @Contended Integer int_115 = new Integer(115); + @Contended Integer int_116 = new Integer(116); + @Contended Integer int_117 = new Integer(117); + @Contended Integer int_118 = new Integer(118); + @Contended Integer int_119 = new Integer(119); + @Contended Integer int_120 = new Integer(120); + @Contended Integer int_121 = new Integer(121); + @Contended Integer int_122 = new Integer(122); + @Contended Integer int_123 = new Integer(123); + @Contended Integer int_124 = new Integer(124); + @Contended Integer int_125 = new Integer(125); + @Contended Integer int_126 = new Integer(126); + @Contended Integer int_127 = new Integer(127); + @Contended Integer int_128 = new Integer(128); + @Contended Integer int_129 = new Integer(129); + @Contended Integer int_130 = new Integer(130); + @Contended Integer int_131 = new Integer(131); + @Contended Integer int_132 = new Integer(132); + @Contended Integer int_133 = new Integer(133); + @Contended Integer int_134 = new Integer(134); + @Contended Integer int_135 = new Integer(135); + @Contended Integer int_136 = new Integer(136); + @Contended Integer int_137 = new Integer(137); + @Contended Integer int_138 = new Integer(138); + @Contended Integer int_139 = new Integer(139); + @Contended Integer int_140 = new Integer(140); + @Contended Integer int_141 = new Integer(141); + @Contended Integer int_142 = new Integer(142); + @Contended Integer int_143 = new Integer(143); + @Contended Integer int_144 = new Integer(144); + @Contended Integer int_145 = new Integer(145); + @Contended Integer int_146 = new Integer(146); + @Contended Integer int_147 = new Integer(147); + @Contended Integer int_148 = new Integer(148); + @Contended Integer int_149 = new Integer(149); + @Contended Integer int_150 = new Integer(150); + @Contended Integer int_151 = new Integer(151); + @Contended Integer int_152 = new Integer(152); + @Contended Integer int_153 = new Integer(153); + @Contended Integer int_154 = new Integer(154); + @Contended Integer int_155 = new Integer(155); + @Contended Integer int_156 = new Integer(156); + @Contended Integer int_157 = new Integer(157); + @Contended Integer int_158 = new Integer(158); + @Contended Integer int_159 = new Integer(159); + @Contended Integer int_160 = new Integer(160); + @Contended Integer int_161 = new Integer(161); + @Contended Integer int_162 = new Integer(162); + @Contended Integer int_163 = new Integer(163); + @Contended Integer int_164 = new Integer(164); + @Contended Integer int_165 = new Integer(165); + @Contended Integer int_166 = new Integer(166); + @Contended Integer int_167 = new Integer(167); + @Contended Integer int_168 = new Integer(168); + @Contended Integer int_169 = new Integer(169); + @Contended Integer int_170 = new Integer(170); + @Contended Integer int_171 = new Integer(171); + @Contended Integer int_172 = new Integer(172); + @Contended Integer int_173 = new Integer(173); + @Contended Integer int_174 = new Integer(174); + @Contended Integer int_175 = new Integer(175); + @Contended Integer int_176 = new Integer(176); + @Contended Integer int_177 = new Integer(177); + @Contended Integer int_178 = new Integer(178); + @Contended Integer int_179 = new Integer(179); + @Contended Integer int_180 = new Integer(180); + @Contended Integer int_181 = new Integer(181); + @Contended Integer int_182 = new Integer(182); + @Contended Integer int_183 = new Integer(183); + @Contended Integer int_184 = new Integer(184); + @Contended Integer int_185 = new Integer(185); + @Contended Integer int_186 = new Integer(186); + @Contended Integer int_187 = new Integer(187); + @Contended Integer int_188 = new Integer(188); + @Contended Integer int_189 = new Integer(189); + @Contended Integer int_190 = new Integer(190); + @Contended Integer int_191 = new Integer(191); + @Contended Integer int_192 = new Integer(192); + @Contended Integer int_193 = new Integer(193); + @Contended Integer int_194 = new Integer(194); + @Contended Integer int_195 = new Integer(195); + @Contended Integer int_196 = new Integer(196); + @Contended Integer int_197 = new Integer(197); + @Contended Integer int_198 = new Integer(198); + @Contended Integer int_199 = new Integer(199); + @Contended Integer int_200 = new Integer(200); + @Contended Integer int_201 = new Integer(201); + @Contended Integer int_202 = new Integer(202); + @Contended Integer int_203 = new Integer(203); + @Contended Integer int_204 = new Integer(204); + @Contended Integer int_205 = new Integer(205); + @Contended Integer int_206 = new Integer(206); + @Contended Integer int_207 = new Integer(207); + @Contended Integer int_208 = new Integer(208); + @Contended Integer int_209 = new Integer(209); + @Contended Integer int_210 = new Integer(210); + @Contended Integer int_211 = new Integer(211); + @Contended Integer int_212 = new Integer(212); + @Contended Integer int_213 = new Integer(213); + @Contended Integer int_214 = new Integer(214); + @Contended Integer int_215 = new Integer(215); + @Contended Integer int_216 = new Integer(216); + @Contended Integer int_217 = new Integer(217); + @Contended Integer int_218 = new Integer(218); + @Contended Integer int_219 = new Integer(219); + @Contended Integer int_220 = new Integer(220); + @Contended Integer int_221 = new Integer(221); + @Contended Integer int_222 = new Integer(222); + @Contended Integer int_223 = new Integer(223); + @Contended Integer int_224 = new Integer(224); + @Contended Integer int_225 = new Integer(225); + @Contended Integer int_226 = new Integer(226); + @Contended Integer int_227 = new Integer(227); + @Contended Integer int_228 = new Integer(228); + @Contended Integer int_229 = new Integer(229); + @Contended Integer int_230 = new Integer(230); + @Contended Integer int_231 = new Integer(231); + @Contended Integer int_232 = new Integer(232); + @Contended Integer int_233 = new Integer(233); + @Contended Integer int_234 = new Integer(234); + @Contended Integer int_235 = new Integer(235); + @Contended Integer int_236 = new Integer(236); + @Contended Integer int_237 = new Integer(237); + @Contended Integer int_238 = new Integer(238); + @Contended Integer int_239 = new Integer(239); + @Contended Integer int_240 = new Integer(240); + @Contended Integer int_241 = new Integer(241); + @Contended Integer int_242 = new Integer(242); + @Contended Integer int_243 = new Integer(243); + @Contended Integer int_244 = new Integer(244); + @Contended Integer int_245 = new Integer(245); + @Contended Integer int_246 = new Integer(246); + @Contended Integer int_247 = new Integer(247); + @Contended Integer int_248 = new Integer(248); + @Contended Integer int_249 = new Integer(249); + @Contended Integer int_250 = new Integer(250); + @Contended Integer int_251 = new Integer(251); + @Contended Integer int_252 = new Integer(252); + @Contended Integer int_253 = new Integer(253); + @Contended Integer int_254 = new Integer(254); + @Contended Integer int_255 = new Integer(255); + @Contended Integer int_256 = new Integer(256); + @Contended Integer int_257 = new Integer(257); + @Contended Integer int_258 = new Integer(258); + @Contended Integer int_259 = new Integer(259); + @Contended Integer int_260 = new Integer(260); + @Contended Integer int_261 = new Integer(261); + @Contended Integer int_262 = new Integer(262); + @Contended Integer int_263 = new Integer(263); + @Contended Integer int_264 = new Integer(264); + @Contended Integer int_265 = new Integer(265); + @Contended Integer int_266 = new Integer(266); + @Contended Integer int_267 = new Integer(267); + @Contended Integer int_268 = new Integer(268); + @Contended Integer int_269 = new Integer(269); + @Contended Integer int_270 = new Integer(270); + @Contended Integer int_271 = new Integer(271); + @Contended Integer int_272 = new Integer(272); + @Contended Integer int_273 = new Integer(273); + @Contended Integer int_274 = new Integer(274); + @Contended Integer int_275 = new Integer(275); + @Contended Integer int_276 = new Integer(276); + @Contended Integer int_277 = new Integer(277); + @Contended Integer int_278 = new Integer(278); + @Contended Integer int_279 = new Integer(279); + @Contended Integer int_280 = new Integer(280); + @Contended Integer int_281 = new Integer(281); + @Contended Integer int_282 = new Integer(282); + @Contended Integer int_283 = new Integer(283); + @Contended Integer int_284 = new Integer(284); + @Contended Integer int_285 = new Integer(285); + @Contended Integer int_286 = new Integer(286); + @Contended Integer int_287 = new Integer(287); + @Contended Integer int_288 = new Integer(288); + @Contended Integer int_289 = new Integer(289); + @Contended Integer int_290 = new Integer(290); + @Contended Integer int_291 = new Integer(291); + @Contended Integer int_292 = new Integer(292); + @Contended Integer int_293 = new Integer(293); + @Contended Integer int_294 = new Integer(294); + @Contended Integer int_295 = new Integer(295); + @Contended Integer int_296 = new Integer(296); + @Contended Integer int_297 = new Integer(297); + @Contended Integer int_298 = new Integer(298); + @Contended Integer int_299 = new Integer(299); + @Contended Integer int_300 = new Integer(300); +} diff --git a/hotspot/test/gc/arguments/TestDisableDefaultGC.java b/hotspot/test/gc/arguments/TestDisableDefaultGC.java new file mode 100644 index 00000000000..73ac9d446c2 --- /dev/null +++ b/hotspot/test/gc/arguments/TestDisableDefaultGC.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestDisableDefaultGC + * @summary Test that the VM complains when the default GC is disabled and no other GC is specified + * @bug 8068579 + * @key gc + * @library /testlibrary + * @requires vm.gc=="null" + * @modules java.base/jdk.internal.misc + * java.management + * @run driver TestDisableDefaultGC + */ + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestDisableDefaultGC { + public static void main(String[] args) throws Exception { + // Start VM, disabling all possible default GCs + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:-UseSerialGC", + "-XX:-UseParallelGC", + "-XX:-UseG1GC", + "-XX:-UseConcMarkSweepGC", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldMatch("Garbage collector not selected"); + output.shouldHaveExitValue(1); + } +} diff --git a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java index 8004d36f04b..46bd3334c42 100644 --- a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java +++ b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,10 +112,12 @@ class TestMaxHeapSizeTools { } private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception { + expectError(new String[] { gcflag, "-XX:InitialHeapSize=1023K", "-version" }); expectError(new String[] { gcflag, "-Xms64M", "-XX:InitialHeapSize=32M", "-version" }); } private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception { + expectValid(new String[] { gcflag, "-XX:InitialHeapSize=1024K", "-version" }); expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms4M", "-version" }); expectValid(new String[] { gcflag, "-Xms4M", "-XX:InitialHeapSize=8M", "-version" }); expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms8M", "-version" }); @@ -124,11 +126,13 @@ class TestMaxHeapSizeTools { } private static void checkInvalidInitialMaxHeapCombinations(String gcflag) throws Exception { + expectError(new String[] { gcflag, "-XX:MaxHeapSize=2047K", "-version" }); expectError(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:InitialHeapSize=8M", "-version" }); expectError(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-XX:MaxHeapSize=4M", "-version" }); } private static void checkValidInitialMaxHeapCombinations(String gcflag) throws Exception { + expectValid(new String[] { gcflag, "-XX:MaxHeapSize=2048K", "-version" }); expectValid(new String[] { gcflag, "-XX:InitialHeapSize=4M", "-XX:MaxHeapSize=8M", "-version" }); expectValid(new String[] { gcflag, "-XX:MaxHeapSize=8M", "-XX:InitialHeapSize=4M", "-version" }); expectValid(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:InitialHeapSize=4M", "-version" }); diff --git a/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java b/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java index a9f0f89a697..d77449e8d34 100644 --- a/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java +++ b/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,11 +61,11 @@ public class TestMaxMinHeapFreeRatioFlags { negativeTest(-1, false, 50, false, options); negativeTest(50, true, -1, true, options); - positiveTest(10, false, 90, false, options); - positiveTest(10, true, 80, false, options); - positiveTest(20, false, 70, true, options); - positiveTest(25, true, 65, true, options); - positiveTest(40, false, 50, false, options); + positiveTest(10, false, 90, false, true, options); + positiveTest(10, true, 80, false, true, options); + positiveTest(20, false, 70, true, true, options); + positiveTest(25, true, 65, true, true, options); + positiveTest(40, false, 50, false, true, options); } /** @@ -79,7 +79,7 @@ public class TestMaxMinHeapFreeRatioFlags { * @param options additional options for JVM */ public static void positiveTest(int minRatio, boolean useXminf, - int maxRatio, boolean useXmaxf, + int maxRatio, boolean useXmaxf, boolean shrinkHeapInSteps, LinkedList options) throws Exception { LinkedList vmOptions = new LinkedList<>(options); @@ -90,9 +90,11 @@ public class TestMaxMinHeapFreeRatioFlags { "-Xms" + HEAP_SIZE, "-XX:NewSize=" + NEW_SIZE, "-XX:MaxNewSize=" + MAX_NEW_SIZE, + "-XX:" + (shrinkHeapInSteps ? '+' : '-') + "ShrinkHeapInSteps", RatioVerifier.class.getName(), Integer.toString(minRatio), - Integer.toString(maxRatio) + Integer.toString(maxRatio), + Boolean.toString(shrinkHeapInSteps) ); ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()])); @@ -151,8 +153,8 @@ public class TestMaxMinHeapFreeRatioFlags { public static LinkedList garbage = new LinkedList<>(); public static void main(String args[]) throws Exception { - if (args.length != 2) { - throw new IllegalArgumentException("Expected 2 args: "); + if (args.length != 3) { + throw new IllegalArgumentException("Expected 3 args: "); } if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld) { System.out.println("Test is not applicable to parallel GC"); @@ -161,8 +163,10 @@ public class TestMaxMinHeapFreeRatioFlags { double minRatio = Integer.valueOf(args[0]) / 100.0; double maxRatio = Integer.valueOf(args[1]) / 100.0; + boolean shrinkHeapInSteps = Boolean.valueOf(args[2]); long maxHeapSize = getMax(); + int gcTries = (shrinkHeapInSteps ? GC_TRIES : 1); // commit 0.5 of total heap size to have enough space // to both shink and expand @@ -170,7 +174,7 @@ public class TestMaxMinHeapFreeRatioFlags { garbage.add(new byte[ARRAY_LENGTH]); } - forceGC(); + forceGC(gcTries); // Verify that current heap free ratio lies between specified limits verifyRatio(minRatio, maxRatio); @@ -185,7 +189,7 @@ public class TestMaxMinHeapFreeRatioFlags { memoryToFill -= CHUNK_SIZE; } - forceGC(); + forceGC(gcTries); // Verify that after memory allocation heap free ratio is still conforming specified limits verifyRatio(minRatio, maxRatio); // Verify that heap was actually expanded @@ -204,7 +208,7 @@ public class TestMaxMinHeapFreeRatioFlags { memoryToFree -= CHUNK_SIZE; } - forceGC(); + forceGC(gcTries); // Verify that heap free ratio is still conforming specified limits verifyRatio(minRatio, maxRatio); // Verify that heap was actually shrinked @@ -214,8 +218,8 @@ public class TestMaxMinHeapFreeRatioFlags { } - public static void forceGC() { - for (int i = 0; i < GC_TRIES; i++) { + public static void forceGC(int gcTries) { + for (int i = 0; i < gcTries; i++) { System.gc(); try { Thread.sleep(10); diff --git a/hotspot/test/gc/arguments/TestSelectDefaultGC.java b/hotspot/test/gc/arguments/TestSelectDefaultGC.java index 689f86c85b4..8dc1435271b 100644 --- a/hotspot/test/gc/arguments/TestSelectDefaultGC.java +++ b/hotspot/test/gc/arguments/TestSelectDefaultGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,9 @@ * @bug 8068582 * @key gc * @library /testlibrary + * @requires vm.gc=="null" * @modules java.base/jdk.internal.misc * java.management - * @ignore 8148239 * @run driver TestSelectDefaultGC */ @@ -41,24 +41,40 @@ public class TestSelectDefaultGC { output.shouldMatch(" " + option + " .*=.* " + value + " "); } - public static void main(String[] args) throws Exception { + public static void testDefaultGC(boolean actAsServer) throws Exception { + String[] args = new String[] { + "-XX:" + (actAsServer ? "+" : "-") + "AlwaysActAsServerClassMachine", + "-XX:" + (actAsServer ? "-" : "+") + "NeverActAsServerClassMachine", + "-XX:+PrintFlagsFinal", + "-version" + }; + // Start VM without specifying GC - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintFlagsFinal", "-version"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); - boolean isServerVM = Platform.isServer(); - boolean isEmbeddedVM = Platform.isEmbedded(); + final boolean isServer = actAsServer; + final boolean isEmbedded = Platform.isEmbedded(); // Verify GC selection - // G1 is default for non-embedded server VMs - assertVMOption(output, "UseG1GC", isServerVM && !isEmbeddedVM); - // Parallel is default for embedded server VMs - assertVMOption(output, "UseParallelGC", isServerVM && isEmbeddedVM); - assertVMOption(output, "UseParallelOldGC", isServerVM && isEmbeddedVM); - // Serial is default for non-server VMs - assertVMOption(output, "UseSerialGC", !isServerVM); + // G1 is default for non-embedded server class machines + assertVMOption(output, "UseG1GC", isServer && !isEmbedded); + // Parallel is default for embedded server class machines + assertVMOption(output, "UseParallelGC", isServer && isEmbedded); + assertVMOption(output, "UseParallelOldGC", isServer && isEmbedded); + // Serial is default for non-server class machines + assertVMOption(output, "UseSerialGC", !isServer); + // CMS is never default assertVMOption(output, "UseConcMarkSweepGC", false); assertVMOption(output, "UseParNewGC", false); } + + public static void main(String[] args) throws Exception { + // Test server class machine + testDefaultGC(false); + + // Test non-server class machine + testDefaultGC(true); + } } diff --git a/hotspot/test/gc/arguments/TestShrinkHeapInSteps.java b/hotspot/test/gc/arguments/TestShrinkHeapInSteps.java new file mode 100644 index 00000000000..82dd54af734 --- /dev/null +++ b/hotspot/test/gc/arguments/TestShrinkHeapInSteps.java @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestShrinkHeapInSteps + * @key gc + * @summary Verify that -XX:-ShrinkHeapInSteps works properly. + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * @build TestMaxMinHeapFreeRatioFlags TestShrinkHeapInSteps + * @run driver/timeout=240 TestShrinkHeapInSteps + */ + +import java.util.LinkedList; +import java.util.Arrays; +import java.util.Collections; +import jdk.test.lib.Utils; + +public class TestShrinkHeapInSteps { + public static void main(String args[]) throws Exception { + LinkedList options = new LinkedList<>( + Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*HeapFreeRatio","-XX:\\+ExplicitGCInvokesConcurrent")) + ); + + // Leverage the existing TestMaxMinHeapFreeRatioFlags test, but pass + // "false" for the shrinkHeapInSteps argument. This will cause it to + // run with -XX:-ShrinkHeapInSteps, and only do 1 full GC instead of 10. + TestMaxMinHeapFreeRatioFlags.positiveTest(10, false, 90, false, false, options); + TestMaxMinHeapFreeRatioFlags.positiveTest(10, true, 80, false, false, options); + TestMaxMinHeapFreeRatioFlags.positiveTest(20, false, 70, true, false, options); + TestMaxMinHeapFreeRatioFlags.positiveTest(25, true, 65, true, false, options); + TestMaxMinHeapFreeRatioFlags.positiveTest(40, false, 50, false, false, options); + } +} diff --git a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java index afa2103783c..1cd9e1191de 100644 --- a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java +++ b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,14 @@ public class TestDynamicNumberOfGCThreads { System.arraycopy(baseArgs, 0, finalArgs, extraArgs.length, baseArgs.length); pb_enabled = ProcessTools.createJavaProcessBuilder(finalArgs); verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); + + // Turn on parallel reference processing + String[] parRefProcArg = {"-XX:+ParallelRefProcEnabled", "-XX:-ShowMessageBoxOnError"}; + String[] parRefArgs = new String[baseArgs.length + parRefProcArg.length]; + System.arraycopy(parRefProcArg, 0, parRefArgs, 0, parRefProcArg.length); + System.arraycopy(baseArgs, 0, parRefArgs, parRefProcArg.length, baseArgs.length); + pb_enabled = ProcessTools.createJavaProcessBuilder(parRefArgs); + verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); } static class GCTest { diff --git a/hotspot/test/gc/g1/Test2GbHeap.java b/hotspot/test/gc/g1/Test2GbHeap.java index 8baa3199e18..7ec0b58ee13 100644 --- a/hotspot/test/gc/g1/Test2GbHeap.java +++ b/hotspot/test/gc/g1/Test2GbHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public class Test2GbHeap { if (output.getOutput().contains("Could not reserve enough space for 2097152KB object heap")) { // Will fail on machines with too little memory (and Windows 32-bit VM), ignore such failures. output.shouldHaveExitValue(1); - } else if (output.getOutput().contains("G1 GC is disabled in this release")) { + } else if (output.getOutput().contains("-XX:+UseG1GC not supported in this VM")) { // G1 is not supported on embedded, ignore such failures. output.shouldHaveExitValue(1); } else { diff --git a/hotspot/test/gc/g1/TestRegionLivenessPrint.java b/hotspot/test/gc/g1/TestRegionLivenessPrint.java new file mode 100644 index 00000000000..17af16c38a8 --- /dev/null +++ b/hotspot/test/gc/g1/TestRegionLivenessPrint.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestRegionLivenessPrint.java + * @bug 8151920 + * @requires vm.gc=="G1" | vm.gc=="null" + * @summary Make sure that G1 does not assert when printing region liveness data on a humongous continues region. + * @key gc + * @library /testlibrary /test/lib + * @modules java.base/jdk.internal.misc + * @build TestRegionLivenessPrint + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+WhiteBoxAPI -XX:+UseG1GC -Xmx128M -XX:G1HeapRegionSize=1m -Xlog:gc+liveness=trace TestRegionLivenessPrint + */ + +import sun.hotspot.WhiteBox; + +public class TestRegionLivenessPrint { + + static byte[] bigobj = new byte[1024* 1024 * 2]; + + public static void main(String[] args) throws InterruptedException { + WhiteBox wb = WhiteBox.getWhiteBox(); + // Run a concurrent mark cycle to trigger the liveness accounting log messages. + wb.g1StartConcMarkCycle(); + while (wb.g1InConcurrentMark()) { + Thread.sleep(100); + } + } + +} diff --git a/hotspot/test/gc/g1/TestStringSymbolTableStats.java b/hotspot/test/gc/g1/TestStringSymbolTableStats.java index b5c9d0f7018..d3c7056387e 100644 --- a/hotspot/test/gc/g1/TestStringSymbolTableStats.java +++ b/hotspot/test/gc/g1/TestStringSymbolTableStats.java @@ -39,7 +39,7 @@ public class TestStringSymbolTableStats { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-XX:+UnlockExperimentalVMOptions", - "-Xlog:gc+stringdedup=trace", + "-Xlog:gc+stringtable=trace", SystemGCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff --git a/hotspot/test/gc/g1/ihop/TestIHOPErgo.java b/hotspot/test/gc/g1/ihop/TestIHOPErgo.java new file mode 100644 index 00000000000..10299299c73 --- /dev/null +++ b/hotspot/test/gc/g1/ihop/TestIHOPErgo.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test TestIHOPErgo + * @bug 8148397 + * @summary Test checks that behavior of Adaptive and Static IHOP at concurrent cycle initiation + * @requires vm.gc=="G1" | vm.gc=="null" + * @requires vm.opt.FlightRecorder != true + * @requires vm.opt.ExplicitGCInvokesConcurrent != true + * @library /testlibrary /test/lib / + * @modules java.management + * @build gc.g1.ihop.TestIHOPErgo + * gc.g1.ihop.lib.IhopUtils + * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo + */ +package gc.g1.ihop; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +import gc.g1.ihop.lib.IhopUtils; + +/** + * The test starts the AppIHOP multiple times varying settings of MaxHeapSize. + * The test parses GC log from AppIHOP to check: + * - occupancy is not less than threshold for Adaptive and Static IHOP at + * concurrent cycle initiation + * - Adaptive IHOP prediction was started during AppIHOP executing + * - log contains ergonomic messages in log + */ +public class TestIHOPErgo { + + // Common GC tune and logging options for test. + private final static String[] COMMON_OPTIONS = { + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1MixedGCLiveThresholdPercent=100", + "-XX:G1HeapWastePercent=0", + "-XX:MaxGCPauseMillis=30000", + "-XX:G1MixedGCCountTarget=1", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=1m", + "-XX:+G1UseAdaptiveIHOP", + "-Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug", + "-XX:+AlwaysTenure", + "-XX:G1AdaptiveIHOPNumInitialSamples=1", + "-XX:InitiatingHeapOccupancyPercent=30" + }; + + public static void main(String[] args) throws Throwable { + + // heap size MB, sleep time for allocator, true/false for adaptive/static + runTest(64, 0, false); + runTest(64, 100, false); + runTest(128, 100, false); + runTest(256, 50, false); + runTest(512, 30, false); + runTest(64, 50, true); + runTest(128, 200, true); + runTest(256, 100, true); + runTest(512, 50, true); + } + + /** + * Runs AppIHOP in separate VM and checks GC log. + * + * @param heapSize heap size + * @param sleepTime sleep time between memory allocations. + * @param isIhopAdaptive true forAdaptive IHOP, false for Static + * + * @throws Throwable + */ + private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) throws Throwable { + System.out.println("IHOP test:"); + System.out.println(" MaxHeapSize : " + heapSize); + + List options = new ArrayList<>(); + Collections.addAll(options, + "-Dheap.size=" + heapSize, + "-Dsleep.time=" + sleepTime, + "-XX:MaxHeapSize=" + heapSize + "M", + "-XX:NewSize=" + heapSize / 8 + "M", + "-XX:MaxNewSize=" + heapSize / 8 + "M", + "-XX:InitialHeapSize=" + heapSize + "M", + "-XX:" + (isIhopAdaptive ? "+" : "-") + "G1UseAdaptiveIHOP" + ); + + Collections.addAll(options, COMMON_OPTIONS); + options.add(AppIHOP.class.getName()); + OutputAnalyzer out = executeTest(options); + + // Checks that log contains message which indicates that IHOP prediction is active + if (isIhopAdaptive) { + IhopUtils.checkAdaptiveIHOPWasActivated(out); + } + // Checks that log contains messages which indicates that VM initiates/checks heap occupancy + // and tries to start concurrent cycle. + IhopUtils.checkErgoMessagesExist(out); + + // Checks threshold and occupancy values + IhopUtils.checkIhopLogValues(out); + } + + private static OutputAnalyzer executeTest(List options) throws Throwable, RuntimeException { + OutputAnalyzer out; + out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); + if (out.getExitValue() != 0) { + System.out.println(out.getOutput()); + throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); + } + return out; + } + + /** + * The AppIHOP fills 60% of heap and allocates and frees 30% of existing + * heap 'iterations' times to achieve IHOP activation. To be executed in + * separate VM. Expected properties: + * heap.size - heap size which is used to calculate amount of memory + * to be allocated and freed + * sleep.time - short pause between filling each MB + */ + public static class AppIHOP { + + public final static LinkedList GARBAGE = new LinkedList<>(); + + private final int ITERATIONS = 10; + private final int OBJECT_SIZE = 100000; + // 60% of the heap will be filled before test cycles. + // 30% of the heap will be filled and freed during test cycle. + private final long HEAP_PREALLOC_PCT = 60; + private final long HEAP_ALLOC_PCT = 30; + private final long HEAP_SIZE; + // Amount of memory to be allocated before iterations start + private final long HEAP_PREALLOC_SIZE; + // Amount of memory to be allocated and freed during iterations + private final long HEAP_ALLOC_SIZE; + private final int SLEEP_TIME; + + public static void main(String[] args) throws InterruptedException { + new AppIHOP().start(); + } + + AppIHOP() { + HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024; + SLEEP_TIME = Integer.getInteger("sleep.time"); + + HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100; + HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100; + } + + public void start() throws InterruptedException { + fill(HEAP_PREALLOC_SIZE); + fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS); + } + + /** + * Fills allocationSize bytes of garbage. + * + * @param allocationSize amount of garbage + */ + private void fill(long allocationSize) { + long allocated = 0; + while (allocated < allocationSize) { + GARBAGE.addFirst(new byte[OBJECT_SIZE]); + allocated += OBJECT_SIZE; + } + } + + /** + * Allocates allocationSize bytes of garbage. Performs a short pauses + * during allocation. Frees allocated garbage. + * + * @param allocationSize amount of garbage per iteration + * @param iterations iteration count + * + * @throws InterruptedException + */ + private void fillAndFree(long allocationSize, int iterations) throws InterruptedException { + + for (int i = 0; i < iterations; ++i) { + System.out.println("Iteration:" + i); + long allocated = 0; + long counter = 0; + while (allocated < allocationSize) { + GARBAGE.addFirst(new byte[OBJECT_SIZE]); + allocated += OBJECT_SIZE; + counter += OBJECT_SIZE; + if (counter > 1024 * 1024) { + counter = 0; + if (SLEEP_TIME != 0) { + Thread.sleep(SLEEP_TIME); + } + } + } + long removed = 0; + while (removed < allocationSize) { + GARBAGE.removeLast(); + removed += OBJECT_SIZE; + } + } + } + } +} diff --git a/hotspot/test/gc/g1/ihop/TestIHOPStatic.java b/hotspot/test/gc/g1/ihop/TestIHOPStatic.java new file mode 100644 index 00000000000..4e91a95c089 --- /dev/null +++ b/hotspot/test/gc/g1/ihop/TestIHOPStatic.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test TestIHOPStatic + * @bug 8148397 + * @summary Test checks concurrent cycle initiation which depends on IHOP value. + * @requires vm.gc=="G1" | vm.gc=="null" + * @requires vm.opt.FlightRecorder != true + * @requires vm.opt.ExplicitGCInvokesConcurrent != true + * @library /testlibrary / + * @modules java.management + * @build gc.g1.ihop.TestIHOPStatic + * gc.g1.ihop.lib.IhopUtils + * @run driver/timeout=240 gc.g1.ihop.TestIHOPStatic + */ +package gc.g1.ihop; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.Utils; + +import gc.g1.ihop.lib.IhopUtils; + +/** + * The test starts the AppIHOP multiple times varying setting of MaxHeapSize, + * IHOP and amount of memory to allocate. Then the test parses the GC log from + * the app to check that Concurrent Mark Cycle was initiated only if needed + * and at the right moment, defined by IHOP setting. + */ +public class TestIHOPStatic { + + final static long YOUNG_SIZE = 8 * 1024 * 1024; + + private final static String[] COMMON_OPTIONS = { + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=1m", + "-XX:-G1UseAdaptiveIHOP", + "-XX:NewSize=" + YOUNG_SIZE, + "-XX:MaxNewSize=" + YOUNG_SIZE, + "-Xlog:gc+ihop+ergo=debug,gc*=debug" + }; + + public static void main(String[] args) throws Throwable { + + // Test case: + // IHOP value, heap occupancy, heap size, expectation of message + // Test cases for occupancy is greater than IHOP + runTest(30, 35, 64, true); + runTest(50, 55, 256, true); + runTest(60, 65, 64, true); + runTest(70, 75, 512, true); + + // Test cases for big difference between occupancy and IHOP + runTest(30, 50, 256, true); + runTest(30, 70, 512, true); + runTest(50, 70, 256, true); + + // Test cases for occupancy is less than IHOP + runTest(30, 25, 64, false); + runTest(50, 45, 256, false); + runTest(70, 65, 64, false); + runTest(70, 65, 512, false); + + // Test cases for big difference between occupancy and IHOP + runTest(50, 30, 300, false); + runTest(70, 50, 160, false); + + // Cases for 0 and 100 IHOP. + runTest(0, 50, 256, true); + runTest(0, 95, 512, true); + runTest(100, 20, 64, false); + runTest(100, 100, 512, false); + } + + /** + * Runs the test case. + * + * @param ihop IHOP value + * @param pctToFill heap percentage to be filled + * @param heapSize heap size for test + * @param expectInitiationMessage + * true - concurrent cycle initiation message is expected + * false - message is not expected + * + * @throws Throwable + */ + private static void runTest(int ihop, long pctToFill, long heapSize, boolean expectInitiationMessage) throws Throwable { + System.out.println(""); + System.out.println("IHOP test:"); + System.out.println(" InitiatingHeapOccupancyPercent : " + ihop); + System.out.println(" Part of heap to fill (percentage) : " + pctToFill); + System.out.println(" MaxHeapSize : " + heapSize); + System.out.println(" Expect for concurrent cycle initiation message : " + expectInitiationMessage); + List options = new ArrayList<>(); + Collections.addAll(options, Utils.getTestJavaOpts()); + Collections.addAll(options, + "-XX:InitiatingHeapOccupancyPercent=" + ihop, + "-Dmemory.fill=" + (heapSize * 1024 * 1024 * pctToFill / 100), + "-XX:MaxHeapSize=" + heapSize + "M", + "-XX:InitialHeapSize=" + heapSize + "M" + ); + Collections.addAll(options, COMMON_OPTIONS); + options.add(AppIHOP.class.getName()); + + OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); + + if (out.getExitValue() != 0) { + System.out.println(out.getOutput()); + throw new RuntimeException("IhopTest failed with exit code " + out.getExitValue()); + } + + checkResult(out, expectInitiationMessage); + } + + /** + * Checks execution results to ensure that concurrent cycle was initiated or + * was not. + * + * @param out + * @param expectInitiationMessage true - test expects for concurrent cycle initiation. + * false - test does not expect for concurrent cycle initiation + */ + private static void checkResult(OutputAnalyzer out, boolean expectInitiationMessage) { + // Find expected messages + List logItems = IhopUtils.getErgoInitiationMessages(out); + + // Concurrent cycle was not initiated but was expected. + if (logItems.isEmpty() && expectInitiationMessage) { + System.out.println(out.getOutput()); + throw new RuntimeException("Concurrent cycle was not initiated."); + } + IhopUtils.checkIhopLogValues(out); + } + + static class AppIHOP { + + /** + * Simple class which fills part of memory and initiates GC. + * To be executed in separate VM. + * Expect next VM properties to be set: + * memory.fill - amount of garbage to be created. + */ + private static final long MEMORY_TO_FILL = Integer.getInteger("memory.fill"); + private final static int CHUNK_SIZE = 10000; + + public final static ArrayList STORAGE = new ArrayList<>(); + + public static void main(String[] args) throws InterruptedException { + + // Calculate part of heap to be filled to achieve expected occupancy. + System.out.println("Mem to fill:" + MEMORY_TO_FILL); + if (MEMORY_TO_FILL <= 0) { + throw new RuntimeException("Wrong memory size: " + MEMORY_TO_FILL); + } + try { + createGarbage(MEMORY_TO_FILL); + } catch (OutOfMemoryError oome) { + return; + } + // Concurrent cycle initiation should start at end of Young GC cycle. + // Will fill entire young gen with garbage to guarantee that Young GC was initiated. + try { + createGarbage(TestIHOPStatic.YOUNG_SIZE); + } catch (OutOfMemoryError oome) { + } + } + + private static void createGarbage(long memToFill) { + for (long i = 0; i < memToFill / CHUNK_SIZE; i++) { + STORAGE.add(new byte[CHUNK_SIZE]); + } + } + } +} diff --git a/hotspot/test/gc/g1/ihop/lib/IhopUtils.java b/hotspot/test/gc/g1/ihop/lib/IhopUtils.java new file mode 100644 index 00000000000..0ca571b2a12 --- /dev/null +++ b/hotspot/test/gc/g1/ihop/lib/IhopUtils.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package gc.g1.ihop.lib; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.test.lib.OutputAnalyzer; + + +/** + * Utility class to extract IHOP related information from the GC log. + * The class provides a number of static method to be used from tests. + */ +public class IhopUtils { + + // Examples of GC log for IHOP: + // [0.402s][debug][gc,ergo,ihop] GC(9) Do not request concurrent cycle initiation (still doing mixed collections) occupancy: 66060288B allocation request: 0B threshold: 59230757B (88.26) source: end of GC + // [0.466s][debug][gc,ergo,ihop] GC(18) Request concurrent cycle initiation (occupancy higher than threshold) occupancy: 52428800B allocation request: 0B threshold: 0B (0.00) source: end of GC + + /** + * Patterns are used for extracting occupancy and threshold from GC log. + */ + private final static Pattern OCCUPANCY = Pattern.compile("occupancy: (\\d+)B"); + private final static Pattern THRESHOLD = Pattern.compile("threshold: (\\d+)B"); + + /** + * Messages related to concurrent cycle initiation. + */ + private final static String CYCLE_INITIATION_MESSAGE = "Request concurrent cycle initiation (occupancy higher than threshold)"; + private final static String CYCLE_INITIATION_MESSAGE_FALSE = "Do not request concurrent cycle initiation (still doing mixed collections)"; + private final static String ADAPTIVE_IHOP_PREDICTION_ACTIVE_MESSAGE = "prediction active: true"; + + /** + * Finds strings which contains patterns for finding. + * + * @param outputAnalyzer List of string for IHOP messages extraction + * @param stringsToFind Strings which is checked for matching with OutputAnalyzer content + * @return List of strings which were matched. + */ + private static List findInLog(OutputAnalyzer outputAnalyzer, String... stringsToFind) { + return outputAnalyzer.asLines().stream() + .filter(string -> { + return Stream.of(stringsToFind) + .filter(find -> string.contains(find)) + .findAny() + .isPresent(); + }) + .collect(Collectors.toList()); + } + + /** + * Checks that memory occupancy is greater or equal to the threshold. + * This methods searches for occupancy and threshold in the GC log corresponding Conc Mark Cycle initiation + * and compare their values.If no CMC initiation happens, does nothing. + * @param outputAnalyzer OutputAnalyzer which contains GC log to be checked + * @throw RuntimeException If check fails + */ + public static void checkIhopLogValues(OutputAnalyzer outputAnalyzer) { + // Concurrent cycle was initiated but was not expected. + // Checks occupancy should be greater than threshold. + List logItems = IhopUtils.getErgoMessages(outputAnalyzer); + logItems.stream() + .forEach(item -> { + long occupancy = IhopUtils.getLongByPattern(item, IhopUtils.OCCUPANCY); + long threshold = IhopUtils.getLongByPattern(item, IhopUtils.THRESHOLD); + if (occupancy < threshold) { + System.out.println(outputAnalyzer.getOutput()); + throw new RuntimeException("Concurrent cycle initiation is unexpected. Occupancy (" + occupancy + ") is less then threshold (" + threshold + ")"); + } + System.out.printf("Concurrent cycle was initiated with occupancy = %d and threshold = %d%n", occupancy, threshold); + }); + } + + private static Long getLongByPattern(String line, Pattern pattern) { + Matcher number = pattern.matcher(line); + if (number.find()) { + return Long.parseLong(number.group(1)); + } + System.out.println(line); + throw new RuntimeException("Cannot find Long in string."); + } + + /** + * Finds concurrent cycle initiation messages. + * @param outputAnalyzer OutputAnalyzer + * @return List with messages which were found. + */ + public static List getErgoInitiationMessages(OutputAnalyzer outputAnalyzer) { + return IhopUtils.findInLog(outputAnalyzer, CYCLE_INITIATION_MESSAGE); + } + + /** + * Gets IHOP ergo messages from GC log. + * @param outputAnalyzer + * @return List with found messages + */ + private static List getErgoMessages(OutputAnalyzer outputAnalyzer) { + return IhopUtils.findInLog(outputAnalyzer, CYCLE_INITIATION_MESSAGE, CYCLE_INITIATION_MESSAGE_FALSE); + } + + /** + * Checks that GC log contains expected ergonomic messages + * @param outputAnalyzer OutputAnalyer with GC log for checking + * @throws RuntimeException If no IHOP ergo messages were not found + */ + public static void checkErgoMessagesExist(OutputAnalyzer outputAnalyzer) { + String output = outputAnalyzer.getOutput(); + if (!(output.contains(CYCLE_INITIATION_MESSAGE) | output.contains(CYCLE_INITIATION_MESSAGE_FALSE))) { + throw new RuntimeException("Cannot find expected IHOP ergonomics messages"); + } + } + + /** + * Checks that adaptive IHOP was activated + * @param outputAnalyzer OutputAnalyer with GC log for checking + * @throws RuntimeException If IHOP message was not found. + */ + public static void checkAdaptiveIHOPWasActivated(OutputAnalyzer outputAnalyzer) { + outputAnalyzer.shouldContain(ADAPTIVE_IHOP_PREDICTION_ACTIVE_MESSAGE); + } +} diff --git a/hotspot/test/gc/g1/plab/TestPLABPromotion.java b/hotspot/test/gc/g1/plab/TestPLABPromotion.java index ec17191f1b0..7af09694dfa 100644 --- a/hotspot/test/gc/g1/plab/TestPLABPromotion.java +++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java @@ -41,17 +41,16 @@ package gc.g1.plab; import java.util.List; -import java.util.Map; import java.util.Arrays; import java.io.PrintStream; import gc.g1.plab.lib.AppPLABPromotion; import gc.g1.plab.lib.LogParser; import gc.g1.plab.lib.PLABUtils; +import gc.g1.plab.lib.PlabInfo; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.ProcessTools; -import jdk.test.lib.Platform; /** * Test checks PLAB promotion of different size objects. @@ -63,6 +62,12 @@ public class TestPLABPromotion { // GC ID with old PLAB statistics private final static long GC_ID_OLD_STATS = 2l; + private final static String PLAB_USED_FIELD_NAME = "used"; + private final static String PLAB_DIRECT_ALLOCATED_FIELD_NAME = "direct allocated"; + private final static List FIELDS_TO_EXTRACT = Arrays.asList(PLAB_USED_FIELD_NAME, PLAB_DIRECT_ALLOCATED_FIELD_NAME); + + private static String output; + // Allowable difference for memory consumption (percentage) private final static long MEM_DIFFERENCE_PCT = 5; @@ -120,11 +125,12 @@ public class TestPLABPromotion { System.out.println(out.getOutput()); throw new RuntimeException("Expect exit code 0."); } - checkResults(out.getOutput(), testCase); + output = out.getOutput(); + checkResults(testCase); } } - private static void checkResults(String output, TestCase testCase) { + private static void checkResults(TestCase testCase) { long plabAllocatedSurvivor; long directAllocatedSurvivor; long plabAllocatedOld; @@ -132,65 +138,89 @@ public class TestPLABPromotion { long memAllocated = testCase.getMemToFill(); LogParser logParser = new LogParser(output); - Map survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS); - Map oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS); + PlabInfo survivorPlabInfo = logParser.getSpecifiedStats(GC_ID_SURVIVOR_STATS, LogParser.ReportType.SURVIVOR_STATS, FIELDS_TO_EXTRACT); + PlabInfo oldPlabInfo = logParser.getSpecifiedStats(GC_ID_OLD_STATS, LogParser.ReportType.OLD_STATS, FIELDS_TO_EXTRACT); - plabAllocatedSurvivor = survivorStats.get("used"); - directAllocatedSurvivor = survivorStats.get("direct allocated"); - plabAllocatedOld = oldStats.get("used"); - directAllocatedOld = oldStats.get("direct allocated"); + checkFields(survivorPlabInfo); + checkFields(oldPlabInfo); + + plabAllocatedSurvivor = survivorPlabInfo.get(PLAB_USED_FIELD_NAME); + directAllocatedSurvivor = survivorPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME); + plabAllocatedOld = oldPlabInfo.get(PLAB_USED_FIELD_NAME); + directAllocatedOld = oldPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME); System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated); // Unreachable objects case if (testCase.isDeadObjectCase()) { - // No dead objects should be promoted - if (!(checkRatio(plabAllocatedSurvivor, memAllocated) && checkRatio(directAllocatedSurvivor, memAllocated))) { - System.out.println(output); - throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Survivor"); - } - if (!(checkRatio(plabAllocatedOld, memAllocated) && checkRatio(directAllocatedOld, memAllocated))) { - System.out.println(output); - throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Old"); - } + checkDeadObjectsPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); + checkDeadObjectsPromotion(plabAllocatedOld, directAllocatedOld, memAllocated); + } else { // Live objects case if (testCase.isPromotedByPLAB()) { - // All live small objects should be promoted using PLAB - if (!checkDifferenceRatio(plabAllocatedSurvivor, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Expect that Survivor PLAB allocation are similar to all mem consumed"); - } - if (!checkDifferenceRatio(plabAllocatedOld, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Expect that Old PLAB allocation are similar to all mem consumed"); - } + checkLiveObjectsPromotion(plabAllocatedSurvivor, memAllocated, "Expect that Survivor PLAB allocation are similar to all mem consumed"); + checkLiveObjectsPromotion(plabAllocatedOld, memAllocated, "Expect that Old PLAB allocation are similar to all mem consumed"); } else { // All big objects should be directly allocated - if (!checkDifferenceRatio(directAllocatedSurvivor, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Test fails. Expect that Survivor direct allocation are similar to all mem consumed"); - } - if (!checkDifferenceRatio(directAllocatedOld, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Test fails. Expect that Old direct allocation are similar to all mem consumed"); - } + checkLiveObjectsPromotion(directAllocatedSurvivor, memAllocated, "Expect that Survivor direct allocation are similar to all mem consumed"); + checkLiveObjectsPromotion(directAllocatedOld, memAllocated, "Expect that Old direct allocation are similar to all mem consumed"); } - // All promoted objects size should be similar to all consumed memory - if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Test fails. Expect that Survivor gen total allocation are similar to all mem consumed"); - } - if (!checkDifferenceRatio(plabAllocatedOld + directAllocatedOld, memAllocated)) { - System.out.println(output); - throw new RuntimeException("Test fails. Expect that Old gen total allocation are similar to all mem consumed"); - } + checkTotalPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated, "Expect that Survivor gen total allocation are similar to all mem consumed"); + checkTotalPromotion(plabAllocatedOld, directAllocatedOld, memAllocated, "Expect that Old gen total allocation are similar to all mem consumed"); } System.out.println("Test passed!"); } + private static void checkTotalPromotion(long plabAllocatedSurvivor, long directAllocatedSurvivor, long memAllocated, String exceptionMessage) { + // All promoted objects size should be similar to all consumed memory + if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) { + System.out.println(output); + throw new RuntimeException(exceptionMessage); + } + } + + /** + * Checks that live objects were promoted as expected. + * @param plabAllocated + * @param totalMemAllocated + * @param exceptionMessage + */ + private static void checkLiveObjectsPromotion(long plabAllocated, long totalMemAllocated, String exceptionMessage) { + // All live small objects should be promoted using PLAB + if (!checkDifferenceRatio(plabAllocated, totalMemAllocated)) { + System.out.println(output); + throw new RuntimeException(exceptionMessage); + } + } + + /** + * Checks that dead objects are not promoted. + * @param plabPromoted promoted by PLAB + * @param directlyPromoted + * @param memoryAllocated total memory allocated + */ + private static void checkDeadObjectsPromotion(long plabPromoted, long directlyPromoted, long memoryAllocated) { + // No dead objects should be promoted + if (!(checkRatio(plabPromoted, memoryAllocated) && checkRatio(directlyPromoted, memoryAllocated))) { + System.out.println(output); + throw new RuntimeException("Unreachable objects should not be allocated using PLAB or directly allocated to Survivor/Old"); + } + } + + /** + * Checks that PLAB statistics contains expected fields. + * @param info + */ + private static void checkFields(PlabInfo info) { + if (!info.checkFields(FIELDS_TO_EXTRACT)) { + System.out.println(output); + throw new RuntimeException("PLAB log does not contain expected fields"); + } + } + /** * Returns true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue. * @@ -215,14 +245,6 @@ public class TestPLABPromotion { return (Math.abs(checkedValue - controlValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT; } - private static Map getPlabStats(LogParser logParser, LogParser.ReportType type, long gc_id) { - - Map survivorStats = logParser.getEntries() - .get(gc_id) - .get(type); - return survivorStats; - } - /** * Description of one test case. */ diff --git a/hotspot/test/gc/g1/plab/TestPLABResize.java b/hotspot/test/gc/g1/plab/TestPLABResize.java index 1dc81b810af..71e00bbae8e 100644 --- a/hotspot/test/gc/g1/plab/TestPLABResize.java +++ b/hotspot/test/gc/g1/plab/TestPLABResize.java @@ -35,23 +35,21 @@ * gc.g1.plab.lib.MemoryConsumer * gc.g1.plab.lib.PLABUtils * gc.g1.plab.lib.AppPLABResize - * @ignore 8150183 * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main gc.g1.plab.TestPLABResize */ package gc.g1.plab; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import java.io.PrintStream; import gc.g1.plab.lib.LogParser; import gc.g1.plab.lib.PLABUtils; import gc.g1.plab.lib.AppPLABResize; +import gc.g1.plab.lib.PlabReport; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.ProcessTools; @@ -75,6 +73,8 @@ public class TestPLABResize { private static final int ITERATIONS_MEDIUM = 5; private static final int ITERATIONS_HIGH = 8; + private static final String PLAB_SIZE_FIELD_NAME = "actual"; + private final static TestCase[] TEST_CASES = { new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_SMALL, GC_NUM_SMALL, ITERATIONS_MEDIUM), new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_HIGH, ITERATIONS_SMALL), @@ -110,41 +110,33 @@ public class TestPLABResize { */ private static void checkResults(String output, TestCase testCase) { final LogParser log = new LogParser(output); - final Map>> entries = log.getEntries(); + final PlabReport report = log.getEntries(); - final ArrayList plabSizes = entries.entrySet() - .stream() - .map(item -> { - return item.getValue() - .get(LogParser.ReportType.SURVIVOR_STATS) - .get("actual"); - }) - .collect(Collectors.toCollection(ArrayList::new)); + final List plabSizes = report.entryStream() + .map(item -> item.getValue() + .get(LogParser.ReportType.SURVIVOR_STATS) + .get(PLAB_SIZE_FIELD_NAME) + ) + .collect(Collectors.toList()); // Check that desired plab size was changed during iterations. - // It should decrease during first half of iterations - // and increase after. - List decreasedPlabs = plabSizes.subList(testCase.getIterations(), testCase.getIterations() * 2); - List increasedPlabs = plabSizes.subList(testCase.getIterations() * 2, testCase.getIterations() * 3); + // The test case does 3 rounds of allocations. The second round of N allocations and GC's + // has a decreasing size of allocations so that iterations N to 2*N -1 will be of decreasing size. + // The third round with iterations 2*N to 3*N -1 has increasing sizes of allocation. + long startDesiredPLABSize = plabSizes.get(testCase.getIterations()); + long endDesiredPLABSize = plabSizes.get(testCase.getIterations() * 2 - 1); - Long prev = decreasedPlabs.get(0); - for (int index = 1; index < decreasedPlabs.size(); ++index) { - Long current = decreasedPlabs.get(index); - if (prev < current) { - System.out.println(output); - throw new RuntimeException("Test failed! Expect that previous PLAB size should be greater than current. Prev.size: " + prev + " Current size:" + current); - } - prev = current; + if (startDesiredPLABSize < endDesiredPLABSize) { + System.out.println(output); + throw new RuntimeException("Test failed! Expect that initial PLAB size should be greater than checked. Initial size: " + startDesiredPLABSize + " Checked size:" + endDesiredPLABSize); } - prev = increasedPlabs.get(0); - for (int index = 1; index < increasedPlabs.size(); ++index) { - Long current = increasedPlabs.get(index); - if (prev > current) { - System.out.println(output); - throw new RuntimeException("Test failed! Expect that previous PLAB size should be less than current. Prev.size: " + prev + " Current size:" + current); - } - prev = current; + startDesiredPLABSize = plabSizes.get(testCase.getIterations() * 2); + endDesiredPLABSize = plabSizes.get(testCase.getIterations() * 3 - 1); + + if (startDesiredPLABSize > endDesiredPLABSize) { + System.out.println(output); + throw new RuntimeException("Test failed! Expect that initial PLAB size should be less than checked. Initial size: " + startDesiredPLABSize + " Checked size:" + endDesiredPLABSize); } System.out.println("Test passed!"); @@ -195,7 +187,6 @@ public class TestPLABResize { return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads, "-XX:ParallelGCBufferWastePct=" + wastePct, "-XX:+ResizePLAB", - "-Dthreads=" + parGCThreads, "-Dchunk.size=" + chunkSize, "-Diterations=" + iterations, "-XX:NewSize=16m", diff --git a/hotspot/test/gc/g1/plab/lib/AppPLABResize.java b/hotspot/test/gc/g1/plab/lib/AppPLABResize.java index 58bbe5c8a25..b6221d760ae 100644 --- a/hotspot/test/gc/g1/plab/lib/AppPLABResize.java +++ b/hotspot/test/gc/g1/plab/lib/AppPLABResize.java @@ -38,7 +38,6 @@ import sun.hotspot.WhiteBox; * Expects the following properties to be set: * - iterations - amount of iteration per cycle. * - chunk.size - size of objects to be allocated - * - threads - number of gc threads (-XX:ParallelGCThreads) to calculate PLAB sizes. */ final public class AppPLABResize { @@ -47,7 +46,6 @@ final public class AppPLABResize { // Defined by properties. private static final int ITERATIONS = Integer.getInteger("iterations"); private static final long CHUNK = Long.getLong("chunk.size"); - private static final int GC_THREADS = Integer.getInteger("threads"); private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -59,13 +57,13 @@ final public class AppPLABResize { */ public static void main(String[] args) { - if (ITERATIONS == 0 || CHUNK == 0 || GC_THREADS == 0) { + if (ITERATIONS == 0 || CHUNK == 0) { throw new IllegalArgumentException("Properties should be set"); } long wordSize = Platform.is32bit() ? 4l : 8l; // PLAB size is shared between threads. - long initialMemorySize = wordSize * GC_THREADS * MEM_ALLOC_WORDS; + long initialMemorySize = wordSize * MEM_ALLOC_WORDS; // Expect changing memory to half during all iterations. long memChangeStep = initialMemorySize / 2 / ITERATIONS; diff --git a/hotspot/test/gc/g1/plab/lib/LogParser.java b/hotspot/test/gc/g1/plab/lib/LogParser.java index 2bf933edabd..8b70c20573f 100644 --- a/hotspot/test/gc/g1/plab/lib/LogParser.java +++ b/hotspot/test/gc/g1/plab/lib/LogParser.java @@ -22,13 +22,15 @@ */ package gc.g1.plab.lib; -import java.util.EnumMap; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * LogParser class parses VM output to get PLAB and ConsumptionStats values. @@ -44,9 +46,6 @@ import java.util.regex.Pattern; */ final public class LogParser { - // Name for GC ID field in report. - public final static String GC_ID = "gc_id"; - /** * Type of parsed log element. */ @@ -57,7 +56,8 @@ final public class LogParser { private final String log; - private final Map>> reportHolder; + // Contains Map of PLAB statistics for given log. + private final PlabReport report; // GC ID private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); @@ -65,7 +65,7 @@ final public class LogParser { private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+"); /** - * Construct LogParser Object + * Construct LogParser object, parse log file with PLAB statistics and store it into report. * * @param log - VM Output */ @@ -74,71 +74,123 @@ final public class LogParser { throw new IllegalArgumentException("Parameter log should not be null."); } this.log = log; - reportHolder = parseLines(); + report = parseLines(); } /** - * @return log which is being processed + * @return log which was processed */ public String getLog() { return log; } /** - * Returns list of log entries. + * Returns the GC log entries for Survivor and Old stats. + * The entries are represented as a map of gcID to the StatMap. * - * @return list of Pair with ReportType and Map of parameters/values. + * @return The log entries for the Survivor and Old stats. */ - public Map>> getEntries() { - return reportHolder; + public PlabReport getEntries() { + return report; } - private Map>> parseLines() throws NumberFormatException { + private PlabReport parseLines() throws NumberFormatException { Scanner lineScanner = new Scanner(log); - Map>> allocationStatistics = new HashMap<>(); + PlabReport plabReport = new PlabReport(); Optional gc_id; while (lineScanner.hasNextLine()) { String line = lineScanner.nextLine(); - gc_id = getGcId(line); - if ( gc_id.isPresent() ) { + gc_id = getGcId(line, GC_ID_PATTERN); + if (gc_id.isPresent()) { Matcher matcher = PAIRS_PATTERN.matcher(line); if (matcher.find()) { - Map> oneReportItem; - ReportType reportType; - - if (!allocationStatistics.containsKey(gc_id.get())) { - allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class)); + if (!plabReport.containsKey(gc_id.get())) { + plabReport.put(gc_id.get(), new PlabGCStatistics()); } + ReportType reportType = line.contains("Young") ? ReportType.SURVIVOR_STATS : ReportType.OLD_STATS; - if ( line.contains("Young") ) { - reportType = ReportType.SURVIVOR_STATS; - } else { - reportType = ReportType.OLD_STATS; - } - - oneReportItem = allocationStatistics.get(gc_id.get()); - if (!oneReportItem.containsKey(reportType)) { - oneReportItem.put(reportType,new HashMap()); + PlabGCStatistics gcStat = plabReport.get(gc_id.get()); + if (!gcStat.containsKey(reportType)) { + gcStat.put(reportType, new PlabInfo()); } // Extract all pairs from log. - Map plabStats = oneReportItem.get(reportType); + PlabInfo plabInfo = gcStat.get(reportType); do { String pair = matcher.group(); String[] nameValue = pair.replaceAll(": ", ":").split(":"); - plabStats.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); + plabInfo.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); } while (matcher.find()); } } } - return allocationStatistics; + return plabReport; } - private Optional getGcId(String line) { - Matcher number = GC_ID_PATTERN.matcher(line); + private static Optional getGcId(String line, Pattern pattern) { + Matcher number = pattern.matcher(line); if (number.find()) { return Optional.of(Long.parseLong(number.group(1))); } return Optional.empty(); } + + /** + * Extracts GC ID from log. + * + * @param line - one line of log. + * @return GC ID + */ + public static Long getGcIdFromLine(String line, Pattern pattern) { + Optional gcId = getGcId(line, pattern); + if (!gcId.isPresent()) { + System.out.println(line); + throw new RuntimeException("Cannot find GC ID in log."); + } + return gcId.get(); + } + + /** + * Returns Map which contains specified statistics for specified gc ids. + * @param specifiedGcId gc id to get + * @param type PLAB type + * @param fieldsName name of fields in PlabStatistics + * @return + **/ + public Map getSpecifiedStats(List specifiedGcId, LogParser.ReportType type, List fieldsName) { + return getSpecifiedStats(specifiedGcId, type, fieldsName, true); + } + + /** + * Returns PlabStatistics for specified GC ID. + * @param specifiedGcId + * @param type type of statistics + * @param fieldsName name of fields in PlabStatistics + * @return + **/ + public PlabInfo getSpecifiedStats(long specifiedGcId, LogParser.ReportType type, List fieldsName) { + return getSpecifiedStats(Arrays.asList(specifiedGcId), type, fieldsName, true).get(specifiedGcId); + } + + /** + * Returns Map which contains specified statistics. Filters out specified gc ids. + * @param specifiedGcIdForExclude + * @param type + * @param fieldsName + * @return + **/ + public Map getExcludedSpecifiedStats(List specifiedGcIdForExclude, LogParser.ReportType type, List fieldsName) { + return getSpecifiedStats(specifiedGcIdForExclude, type, fieldsName, false); + } + + private Map getSpecifiedStats(List gcIds, LogParser.ReportType type, List fieldNames, boolean extractId) { + return new HashMap<>( + getEntries().entryStream() + .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey())) + .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(), + gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames) + ) + ) + ); + } } diff --git a/hotspot/test/gc/g1/plab/lib/PlabGCStatistics.java b/hotspot/test/gc/g1/plab/lib/PlabGCStatistics.java new file mode 100644 index 00000000000..f409409a986 --- /dev/null +++ b/hotspot/test/gc/g1/plab/lib/PlabGCStatistics.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package gc.g1.plab.lib; + +import java.util.EnumMap; +import java.util.Map; + +import gc.g1.plab.lib.LogParser.ReportType; + +/** + * Class that represents PLAB statistics for a single GC. + * It includes both Survivor and Old PLAB statistics. + */ +public class PlabGCStatistics { + + private final Map plabGCStatistics; + + public PlabGCStatistics() { + plabGCStatistics = new EnumMap<>(ReportType.class); + } + + /** + * Checks if the statistics contains the requested type. + * @param reportType + * @returns true, if contains, false otherwise + */ + public boolean containsKey(ReportType reportType) { + return plabGCStatistics.containsKey(reportType); + } + + /** + * Put pair of ReportType and PlabInfo to statistics. + * @param reportType + * @param plabInfo + */ + public void put(ReportType reportType, PlabInfo plabInfo) { + plabGCStatistics.put(reportType, plabInfo); + } + + /** + * Returns PlabInfo of specified type + * @param reportType + * @return + */ + public PlabInfo get(ReportType reportType) { + return plabGCStatistics.get(reportType); + } +} diff --git a/hotspot/test/gc/g1/plab/lib/PlabInfo.java b/hotspot/test/gc/g1/plab/lib/PlabInfo.java new file mode 100644 index 00000000000..6532e4bede8 --- /dev/null +++ b/hotspot/test/gc/g1/plab/lib/PlabInfo.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package gc.g1.plab.lib; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PlabInfo { + + private final Map plabInfo; + + public PlabInfo() { + plabInfo = new HashMap<>(); + } + + private PlabInfo(Map map) { + plabInfo = new HashMap<>(map); + } + + /** + * Add key and value to underlying Map. + * @param key PLAB info field name + * @param value PLAB info value for field + */ + public void put(String key, long value) { + plabInfo.put(key, value); + } + + /** + * Get stream of Map.Entry representing underlying Map with PLAB information. + */ + public Stream> entryStream() { + return plabInfo.entrySet().stream(); + } + + /** + * Returns the PlabInfo narrowed for the given fields only + * @param fields + * @return PlabInfo + */ + public PlabInfo filter(List fields) { + return new PlabInfo(entryStream() + .filter(field -> fields.contains(field.getKey())) + .collect(Collectors.toMap( + item -> item.getKey(), + item -> item.getValue()) + ) + ); + } + + /** + * Checks if statistic contains expected fields. + * @param fields fields which should be in statistic + * @return true if all fields are in statistic, false otherwise + */ + public boolean checkFields(List fields) { + for (String key : fields) { + if (!plabInfo.containsKey(key)) { + return false; + } + } + return true; + } + + /** + * Return a collection of the values. + * @return collection of values + */ + public Collection values() { + return plabInfo.values(); + } + + /** + * Get value for specified field. + * @param field + * @return long value which is contained in specified field + */ + public long get(String field) { + return plabInfo.get(field); + } +} diff --git a/hotspot/test/gc/g1/plab/lib/PlabReport.java b/hotspot/test/gc/g1/plab/lib/PlabReport.java new file mode 100644 index 00000000000..ae8b0287388 --- /dev/null +++ b/hotspot/test/gc/g1/plab/lib/PlabReport.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package gc.g1.plab.lib; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +/** + * Class contains representation of GC PLAB log. + */ +public class PlabReport { + + private final Map report = new HashMap<>(); + + public PlabReport() { + } + + /** + * Checks if underlying Map contains requested GC ID. + */ + public boolean containsKey(Long gcId) { + return report.containsKey(gcId); + } + + /** + * Puts GC ID and PlabGCStatistics to underlying Map. + */ + public void put(Long gcId, PlabGCStatistics plabStat) { + report.put(gcId, plabStat); + } + + /** + * Returns PlabGCStatistics for specified GC ID. + */ + public PlabGCStatistics get(Long gcId) { + return report.get(gcId); + } + + /** + * Returns Stream of Map.Entry of underlying Map. + */ + public Stream> entryStream() { + return report.entrySet().stream(); + } +} diff --git a/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java b/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java index 042f7660657..f76d457a004 100644 --- a/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java +++ b/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java @@ -37,7 +37,6 @@ import static jdk.test.lib.Asserts.*; * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8151460 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseG1GC TestMetaspacePerfCounters @@ -85,6 +84,9 @@ public class TestMetaspacePerfCounters { } private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception { + // Need to ensure that used is up to date and that all unreachable + // classes are unloaded before doing this check. + System.gc(); long before = getUsed(ns); fooClass = compileAndLoad("Foo", "public class Foo { }"); System.gc(); diff --git a/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java b/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java index e85b172190f..7a5e8c7da2c 100644 --- a/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java +++ b/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java @@ -36,15 +36,14 @@ import static jdk.test.lib.Asserts.*; * @modules java.base/jdk.internal.misc * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8151460 - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools */ public class TestPerfCountersAndMemoryPools { public static void main(String[] args) throws Exception { checkMemoryUsage("Metaspace", "sun.gc.metaspace"); - if (InputArguments.contains("-XX:+UseCompressedKlassPointers") && Platform.is64bit()) { + if (InputArguments.contains("-XX:+UseCompressedClassPointers") && Platform.is64bit()) { checkMemoryUsage("Compressed Class Space", "sun.gc.compressedclassspace"); } } @@ -72,13 +71,17 @@ public class TestPerfCountersAndMemoryPools { pool.getUsage().getInit(); pool.getUsage().getUsed(); pool.getUsage().getCommitted(); - assertEQ(1L, 1L); + assertEQ(1L, 1L, "Make assert load"); // Must do a GC to update performance counters System.gc(); - assertEQ(getMinCapacity(perfNS), pool.getUsage().getInit()); - assertEQ(getUsed(perfNS), pool.getUsage().getUsed()); - assertEQ(getCapacity(perfNS), pool.getUsage().getCommitted()); + assertEQ(getMinCapacity(perfNS), pool.getUsage().getInit(), "MinCapacity out of sync"); + + // Adding a second GC due to metadata allocations caused by getting the + // initial size from the pool. This is needed when running with -Xcomp. + System.gc(); + assertEQ(getUsed(perfNS), pool.getUsage().getUsed(), "Used out of sync"); + assertEQ(getCapacity(perfNS), pool.getUsage().getCommitted(), "Committed out of sync"); } private static long getMinCapacity(String ns) throws Exception { diff --git a/hotspot/test/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java b/hotspot/test/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java new file mode 100644 index 00000000000..397b6474895 --- /dev/null +++ b/hotspot/test/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8060463 + * @summary Verify that objects promoted from eden space to survivor space + * with large values for SurvivorAlignmentInBytes succeed. + * @requires vm.opt.ExplicitGCInvokesConcurrent != true + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=8 -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=16 -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=512 -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=1k -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=4k -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + * @run main/othervm -Xmx128m + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=16k -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB + * TestPromotionLABLargeSurvivorAlignment + */ +public class TestPromotionLABLargeSurvivorAlignment { + public static void main(String args[]) { + Object garbage[] = new Object[1000000]; + for (int i = 0; i < garbage.length; i++) { + garbage[i] = new byte[0]; + } + for (int i = 0; i < 2; i++) { + System.gc(); + } + } +} + diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index a67ff42e46c..e6ec4c5ea8d 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -89,6 +89,13 @@ public class TestOptionsWithRanges { */ excludeTestMaxRange("CICompilerCount"); + /* + * JDK-8153340 + * Temporary exclude AllocatePrefetchDistance option from testing + */ + excludeTestRange("AllocatePrefetchDistance"); + + /* * JDK-8136766 * Temporarily remove ThreadStackSize from testing because Windows can set it to 0 @@ -96,15 +103,6 @@ public class TestOptionsWithRanges { */ excludeTestRange("ThreadStackSize"); - /* - * JDK-8143958 - * Temporarily exclude testing of max range for Shared* flags - */ - excludeTestMaxRange("SharedReadWriteSize"); - excludeTestMaxRange("SharedReadOnlySize"); - excludeTestMaxRange("SharedMiscDataSize"); - excludeTestMaxRange("SharedMiscCodeSize"); - /* * Remove the flag controlling the size of the stack because the * flag has direct influence on the physical memory usage of diff --git a/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java b/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java index 04f7a57af3c..bdffccbc33f 100644 --- a/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java +++ b/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ public class TraceExceptionsTest { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-Xlog:exceptions=info", "NoClassFound"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain(""); + output.shouldContain(""); output.shouldNotContain(""); output.shouldHaveExitValue(1); } diff --git a/hotspot/test/runtime/SelectionResolution/AbstractMethodErrorTest.java b/hotspot/test/runtime/SelectionResolution/AbstractMethodErrorTest.java new file mode 100644 index 00000000000..0c2d98c5273 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/AbstractMethodErrorTest.java @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate AbstractMethodErrorTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies AbstractMethodErrorTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class AbstractMethodErrorTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.AME); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokevirtual tests */ + /* Group 63: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 64: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 65: callsite = methodref = resolved, possibly + * skip different package in selection. + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionPackageSkipNoOverride), + /* Group 66: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsIface), + /* Group 67: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 68: callsite :> methodref, methodref = expected, + * possibly skip different package in selection. + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionPackageSkipNoOverride), + /* Group 69: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 70: callsite :> methodref, methodref != expected, + * possibly skip different package in selection + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionPackageSkipNoOverride), + /* Group 71: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsIface), + /* Group 72: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 73: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionPackageSkipNoOverride), + /* Group 74: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 75: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionPackageSkipNoOverride), + /* Group 76: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsIface), + /* Group 77: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 78: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsIface), + /* Group 79: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + + /* Group 80: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 81: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsIface), + /* Group 82: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 83: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 84: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsIface), + + /* Reabstraction during selection */ + /* Group 85: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED, + MethodData.Access.PACKAGE, + MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteEqualsMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 86: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 87: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteEqualsMethodref, + Template.ReabstractMethodrefResolvedIface), + /* Group 88: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 89: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 90: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedIface), + /* Group 91: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 92: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 93: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedIface), + /* Group 94: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 95: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteEqualsMethodref, + Template.ReabstractMethodrefResolvedIface), + /* Group 96: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedClass), + + /* Group 97: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 98: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteSubclassMethodref, + Template.ReabstractMethodrefResolvedIface), + /* Group 99: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 100: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedClass), + /* Group 101: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractMethodrefResolvedIface), + + /* invokeinterface */ + /* Group 102: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelection), + /* Group 103: callsite = methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelection), + /* Group 104: callsite :> methodref, methodref = expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelection), + /* Group 105: callsite :> methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelection), + /* Group 106: callsite unrelated to methodref, methodref = expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelection), + /* Group 107: callsite unrelated to methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.ReabstractExpectedIface, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelection), + + /* Reabstraction during selection */ + /* Group 108: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteEqualsMethodref, + Template.ReabstractIfaceMethodrefResolved), + /* Group 109: callsite = methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.CallsiteEqualsMethodref, + Template.ReabstractIfaceMethodrefResolved), + /* Group 110: callsite :> methodref, methodref = expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.ReabstractIfaceMethodrefResolved), + /* Group 111: callsite :> methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.ReabstractIfaceMethodrefResolved), + /* Group 112: callsite unrelated to methodref, methodref = expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractIfaceMethodrefResolved), + /* Group 113: callsite unrelated to methodref, methodref != expected, + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.ReabstractIfaceMethodrefResolved), + + /* invokespecial tests */ + /* Group 114: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 115: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 116: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 117: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 118: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 119: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 120: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 121: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 122: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + + /* Group 123: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.ReabstractExpectedClass, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 124: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.ReabstractExpectedIface, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite) + ); + + private AbstractMethodErrorTest() { + super(testgroups); + } + + public static void main(final String... args) { + new AbstractMethodErrorTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/IllegalAccessErrorTest.java b/hotspot/test/runtime/SelectionResolution/IllegalAccessErrorTest.java new file mode 100644 index 00000000000..7bc2350ddb1 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/IllegalAccessErrorTest.java @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate IllegalAccessErrorTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies IllegalAccessErrorTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class IllegalAccessErrorTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.IAE); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokestatic tests */ + /* Group 125 : callsite = methodref, methodref != + * expected, expected is class + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.TrivialObjectref), + /* Group 126: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 127: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 128: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 129: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 130: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.TrivialObjectref), + /* Group 131: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 132: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 133: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE, + MethodData.Access.PROTECTED, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 134: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE, + MethodData.Access.PROTECTED, + MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + + /* invokevirtual tests */ + /* Group 135: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 136: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 137: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 138: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 139: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 140: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 141: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 142: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 143: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + // protected causes verifier error. + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + /* Group 144: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + // protected causes verifier error. + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass), + + /* invokeinterface tests */ + /* Group 145: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + /* Group 146: callsite = methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + /* Group 147: callsite :> methodref, methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + /* Group 148: callsite :> methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + /* Group 149: callsite unrelated to methodref, methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + /* Group 150: callsite unrelated to methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelectionOverrideNonPublic), + + /* invokespecial tests */ + /* Group 151: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 152: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 153: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 154: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 155: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite), + /* Group 156: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefExactSubclassOfCallsite) + ); + + private IllegalAccessErrorTest() { + super(testgroups); + } + + public static void main(final String... args) { + new IllegalAccessErrorTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeInterfaceICCE.java b/hotspot/test/runtime/SelectionResolution/InvokeInterfaceICCE.java new file mode 100644 index 00000000000..b3bafc6b6b7 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeInterfaceICCE.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate IncompatibleClassChangeError + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm/timeout=500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceICCE + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeInterfaceICCE extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.ICCE); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokeinterface tests */ + + /* resolved method is static*/ + /* Group 168: methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefSelection), + /* Group 169: methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefSelection), + + /* methodref is a class */ + /* Group 170: methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsClass), + /* Group 171: methodref != expected, expected is class */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsClass), + /* Group 172: methodref != expected expected is interface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsIface), + /* Group 173: ambiguous resolution */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefAmbiguous, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefSelectionNoOverride), + /* Group 174: ambiguous selection */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefAmbiguousResolvedIsIface), + + /* Group 175: private method in interface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelection) + ); + + private InvokeInterfaceICCE() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeInterfaceICCE().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java b/hotspot/test/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java new file mode 100644 index 00000000000..a4246742387 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate InvokeInterfaceSuccessTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceSuccessTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeInterfaceSuccessTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.invoke = SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE; + } + + private static final Collection testgroups = + Arrays.asList( + /* invokeinterface tests */ + + /* Group 40: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract), + /* Group 41: callsite = methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract), + /* Group 42: callsite :> methodref, methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract), + /* Group 43: callsite :> methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract), + /* Group 44: callsite unrelated to methodref, methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract), + /* Group 45: callsite unrelated to methodref, methodref != expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.IfaceMethodrefSelection, + Template.SelectionOverrideAbstract) + ); + + private InvokeInterfaceSuccessTest() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeInterfaceSuccessTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeSpecialICCE.java b/hotspot/test/runtime/SelectionResolution/InvokeSpecialICCE.java new file mode 100644 index 00000000000..9086689451e --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeSpecialICCE.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate IncompatibleClassChangeError + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeSpecialICCE + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeSpecialICCE extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.ICCE); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokespecial tests */ + /* resolved method is static*/ + /* Group 170: methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.InvokespecialCallsiteCases, + Template.ObjectrefAssignableToCallsite), + /* Group 171: methodref != expected, expected is class */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.InvokespecialCallsiteCases, + Template.ObjectrefAssignableToCallsite), + /* Group 172: methodref != expected, expected is interface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.InvokespecialCallsiteCases, + Template.ObjectrefAssignableToCallsite), + + /* Group 173: Ambiguous resolution */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefAmbiguous, + Template.IgnoredAbstract, + Template.InvokespecialCallsiteCases, + Template.ObjectrefAssignableToCallsite) + ); + + private InvokeSpecialICCE() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeSpecialICCE().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeSpecialSuccessTest.java b/hotspot/test/runtime/SelectionResolution/InvokeSpecialSuccessTest.java new file mode 100644 index 00000000000..71f266c2f0f --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeSpecialSuccessTest.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate InvokeSpecialSuccessTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeSpecialSuccessTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeSpecialSuccessTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.invoke = SelectionResolutionTestCase.InvokeInstruction.INVOKESPECIAL; + } + + private static final Collection testgroups = + Arrays.asList( + /* Group 46: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 47: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 48: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 49: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 50: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 51: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 52: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 53: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 54: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + + /* Group 55: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 56: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + + /* Funny cases */ + /* Group 57: callsite = methodref, methodref = + * expected expected is interface, expected and + * callsite in a different package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefEqualsOrExactSubclassOfCallsite), + /* Group 58: callsite = methodref, methodref \!= + * expected expected is interface, expected and + * callsite in a different package */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.ObjectrefEqualsOrExactSubclassOfCallsite), + /* Group 59: callsite subclass methodref, methodref = + * expected expected is interface, expected and + * callsite in a different package */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefEqualsOrExactSubclassOfCallsite), + /* Group 60: callsite subclass methodref, methodref + * \!= expected expected is interface, expected and + * callsite in a different package */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefEqualsOrExactSubclassOfCallsite), + + /* Methodref is an interface */ + /* Group 61: callsite :> methodref, methodref = expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite), + /* Group 62: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.ObjectrefAssignableToCallsite) + ); + + private InvokeSpecialSuccessTest() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeSpecialSuccessTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeStaticICCE.java b/hotspot/test/runtime/SelectionResolution/InvokeStaticICCE.java new file mode 100644 index 00000000000..54ce64154bd --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeStaticICCE.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of invokestatic method selection and resolution cases that + * generate IncompatibleClassChangeError + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeStaticICCE + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeStaticICCE extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.ICCE); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokestatic tests */ + /* Group 157: methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.AllCallsiteCases, + Template.TrivialObjectref), + /* Group 158: methodref = expected, expected is interface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.AllCallsiteCases, + Template.TrivialObjectref), + /* Group 159: methodref != expected, expected is class + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.AllCallsiteCases, + Template.TrivialObjectref), + /* Group 160: methodref = expected, expected is interface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.AllCallsiteCases, + Template.TrivialObjectref) + ); + + private InvokeStaticICCE() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeStaticICCE().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeStaticSuccessTest.java b/hotspot/test/runtime/SelectionResolution/InvokeStaticSuccessTest.java new file mode 100644 index 00000000000..367816961b4 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeStaticSuccessTest.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate InvokeStaticSuccessTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main InvokeStaticSuccessTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeStaticSuccessTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.invoke = SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC; + } + + private static final Collection testgroups = + Arrays.asList( + /* invokestatic tests */ + /* Group 1: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteEqualsMethodref, + Template.TrivialObjectref), + /* Group 2: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.TrivialObjectref), + /* Group 3: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 4: callsite :> methodref, methodref = expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 5: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 6: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 7: callsite unrelated to methodref, methodref = expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 8: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 9: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteEqualsMethodref, + Template.TrivialObjectref), + /* Group 10: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 11: callsite :> methodref, methodref = expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 12: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteSubclassMethodref, + Template.TrivialObjectref), + /* Group 13: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 14: callsite unrelated to methodref, methodref = expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefEqualsExpected, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref), + /* Group 15: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedClass, + Template.CallsiteUnrelatedToMethodref, + Template.TrivialObjectref) + ); + + private InvokeStaticSuccessTest() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeStaticSuccessTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeVirtualICCE.java b/hotspot/test/runtime/SelectionResolution/InvokeVirtualICCE.java new file mode 100644 index 00000000000..8dbe06e498b --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeVirtualICCE.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate IncompatibleClassChangeError + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm/timeout=1200 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualICCE + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeVirtualICCE extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.ICCE); + } + + private static final Collection testgroups = + Arrays.asList( + /* invokevirtual tests */ + + /* resolved method is static*/ + /* Group 161: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsClass), + /* Group 162: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PACKAGE, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsClass), + /* Group 163: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.STATIC), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsIface), + + /* methodref is an interface */ + /* Group 164: callsite = methodref = expected */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefSelection), + /* Group 165: callsite = methodref, methodref != expected, + * expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PRIVATE), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.IfaceMethodrefNotEqualsExpected, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.IfaceMethodrefSelection), + + /* Group 166: Ambiguous resolution tests */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefAmbiguous, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefSelectionResolvedIsIfaceNoOverride), + /* Group 167: ambiguous selection */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.AllCallsiteCases, + Template.MethodrefAmbiguousResolvedIsIface) + ); + + private InvokeVirtualICCE() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeVirtualICCE().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/InvokeVirtualSuccessTest.java b/hotspot/test/runtime/SelectionResolution/InvokeVirtualSuccessTest.java new file mode 100644 index 00000000000..2b4deab2073 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/InvokeVirtualSuccessTest.java @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate InvokeVirtualSuccessTest + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main/othervm/timeout=400 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualSuccessTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class InvokeVirtualSuccessTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.invoke = SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL; + } + + private static final Collection testgroups = + Arrays.asList( + /* invokevirtual tests */ + /* Group 16: callsite = methodref = expected, no override */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClassNoOverride), + /* Group 17: callsite = methodref = expected, override allowed */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PROTECTED, + MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 18: callsite = methodref = resolved, possibly + * skip different package in selection. + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 19: callsite = methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 20: callsite = methodref, methodref \!= + * expected, possibly skip different package in + * selection. + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 21: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract), + /* Group 22: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 23: callsite :>, methodref = expected, + * possibly skip different package in selection + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 24: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 25: callsite :>, methodref = expected, + * possibly skip different package in selection + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 26: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract), + /* Group 27: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 28: callsite unrelated to methodref, + * methodref = expected, possibly skip different + * package in selection + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 29: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 30: callsite unrelated to methodref, + * methodref \!= expected, possibly skip different + * package in selection + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PACKAGE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionPackageSkip, + Template.SelectionOverrideAbstract), + /* Group 31: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract), + /* Group 32: callsite = methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC, + MethodData.Access.PROTECTED), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 33: callsite = methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteEqualsMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract), + /* Group 34: callsite :> methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + + /* Group 35: callsite :> methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 36: callsite :> methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteSubclassMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract), + /* Group 37: callsite unrelated to methodref, methodref = expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefEqualsExpected, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 38: callsite unrelated to methodref, methodref != expected, + * expected is class, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.CLASS), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedClass, + Template.MethodrefNotEqualsExpectedClass, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsClass, + Template.SelectionOverrideAbstract), + /* Group 39: callsite unrelated to methodref, methodref != expected, + * expected is interface, expected and callsite not in the same package + */ + new TestGroup.Simple(initBuilder, + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.DIFFERENT)), + Template.OverrideAbstractExpectedIface, + Template.MethodrefNotEqualsExpectedIface, + Template.IgnoredAbstract, + Template.CallsiteUnrelatedToMethodref, + Template.MethodrefSelectionResolvedIsIface, + Template.SelectionOverrideAbstract) + ); + + private InvokeVirtualSuccessTest() { + super(testgroups); + } + + public static void main(final String... args) { + new InvokeVirtualSuccessTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/NoSuchMethodErrorTest.java b/hotspot/test/runtime/SelectionResolution/NoSuchMethodErrorTest.java new file mode 100644 index 00000000000..ec239639db0 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/NoSuchMethodErrorTest.java @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test of method selection and resolution cases that + * generate NoSuchMethodError + * @modules java.base/jdk.internal.org.objectweb.asm + * @library /runtime/SelectionResolution/classes + * @build selectionresolution.* + * @run main NoSuchMethodErrorTest + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import selectionresolution.ClassData; +import selectionresolution.MethodData; +import selectionresolution.Result; +import selectionresolution.SelectionResolutionTest; +import selectionresolution.SelectionResolutionTestCase; +import selectionresolution.Template; + +public class NoSuchMethodErrorTest extends SelectionResolutionTest { + + private static final SelectionResolutionTestCase.Builder initBuilder = + new SelectionResolutionTestCase.Builder(); + + static { + initBuilder.setResult(Result.NSME); + } + + private static final MethodData concreteMethod = + new MethodData(MethodData.Access.PUBLIC, MethodData.Context.INSTANCE); + + private static final MethodData staticMethod = + new MethodData(MethodData.Access.PUBLIC, MethodData.Context.STATIC); + + private static final MethodData privateMethod = + new MethodData(MethodData.Access.PRIVATE, MethodData.Context.INSTANCE); + + private static final ClassData withDef = + new ClassData(ClassData.Package.SAME, concreteMethod); + + private static final ClassData withStaticDef = + new ClassData(ClassData.Package.SAME, staticMethod); + + private static final ClassData withPrivateDef = + new ClassData(ClassData.Package.SAME, staticMethod); + + private static final Template NoMethodResolutionTemplateClassBottom = + new Template("NoMethodResolutionTemplate", + /* Empty single class + * + * C[]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + builder.methodref = C; + }, + /* Class bottom, inherit empty class + * + * C2[]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Class bottom, inherit empty interface + * + * I[]() + * C[I]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C, I); + builder.methodref = C; + }, + /* Class bottom, inherit empty class and interface + * + * C2[](), I[]() + * C1[C2,I]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.methodref = C1; + }, + /* Class bottom, unrelated class defines + * + * C20[](con) + * C1[]() + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + builder.addClass(withDef); + builder.methodref = C; + }, + /* Class bottom, interface defines static + * + * I[](stat) + * C[]() + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(withStaticDef); + builder.hier.addInherit(C, I); + builder.methodref = C; + }, + /* Class bottom, interface defines private + * + * I[](priv) + * C[]() + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(withPrivateDef); + builder.hier.addInherit(C, I); + builder.methodref = C; + }); + + private static final Template NoMethodResolutionTemplateIfaceBottom = + new Template("NoMethodResolutionTemplate", + /* Empty single interface + * + * I[]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.methodref = I; + }, + /* Interface bottom, inherit empty interface + * + * I2[]() + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I1 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + final int I2 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(I1, I2); + builder.methodref = I1; + }, + /* Interface bottom, unrelated class defines + * + * C0[](con) + * I[]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.addClass(withDef); + builder.methodref = I; + }, + /* Interface bottom, interface defines static + * + * I2[](stat) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I1 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + final int I2 = builder.addInterface(withStaticDef); + builder.hier.addInherit(I1, I2); + builder.methodref = I1; + }, + /* Interface bottom, interface defines private + * + * I2[](stat) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I1 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + final int I2 = builder.addInterface(withPrivateDef); + builder.hier.addInherit(I1, I2); + builder.methodref = I1; + }); + + private static final Template NoMethodSelectionTemplateClassMethodref = + new Template("NoMethodSelectionTemplate", + /* objectref = methodref + * + * C[]() = mref = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + builder.objectref = builder.methodref; + }, + /* Inherit methodref + * + * C2[]() = mref + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.methodref; + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Inherit methodref and interface + * + * C2[]() = mref, I[]() + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C2 = builder.methodref; + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }, + /* objectref = methodref, unrelated class defines + * + * C0[](def) + * C[]() = mref = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + builder.addClass(withDef); + builder.objectref = builder.methodref; + }, + /* Inherit methodref, unrelated class defines + * + * C0[](def) + * C2[]() = mref + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.methodref; + builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Inherit methodref and interface, unrelated class defines. + * + * C0[](def) + * C2[]() = mref, I[]() + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C2 = builder.methodref; + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }, + /* objectref = methodref, unrelated interface defines + * + * I0[](def) + * C[]() = mref = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + builder.addInterface(withDef); + builder.objectref = builder.methodref; + }, + /* Inherit methodref, interface defines static + * + * C2[]() = mref, I0[](stat) + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.methodref; + final int I0 = builder.addInterface(withStaticDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I0); + builder.objectref = C1; + }, + /* Inherit methodref, interface defines private + * + * C2[]() = mref, I0[](stat) + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C1 = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int C2 = builder.methodref; + final int I0 = builder.addInterface(withPrivateDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I0); + builder.objectref = C1; + }); + + private static final Template NoMethodSelectionTemplateIfaceMethodref = + new Template("NoMethodSelectionTemplate", + /* Inherit methodref + * + * I[]() = mref + * C[I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.methodref; + builder.hier.addInherit(C, I); + builder.objectref = C; + }, + /* Inherit methodref and interface + * + * I1[]() = mref, I2[]() + * C[T,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I1 = builder.methodref; + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I2 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.objectref = C; + }, + /* Inherit methodref, unrelated class defines + * + * C0[](def) + * I[]() = mref + * C[I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.methodref; + builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + }, + /* Inherit methodref and interface, unrelated class defines + * + * C0[](def) + * I1[]() = mref, I2[]() + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int I1 = builder.methodref; + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I2 = builder.addInterface(Template.emptyClass(ClassData.Package.SAME)); + builder.addClass(withDef); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.objectref = C; + }, + /* Inherit methodref, interface defines static + * + * I[]() = mref, I0[](stat) + * C[I,I0]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.methodref; + final int I0 = builder.addInterface(withStaticDef); + builder.hier.addInherit(C, I); + builder.hier.addInherit(C, I0); + builder.objectref = C; + }, + /* Inherit methodref, unrelated class defines private + * + * I[]() = mref, I0[](priv) + * C[I,I0]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C = builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + final int I = builder.methodref; + final int I0 = builder.addInterface(withPrivateDef); + builder.hier.addInherit(C, I); + builder.hier.addInherit(C, I0); + builder.objectref = C; + }); + + private static final Collection testgroups = + Arrays.asList( + /* invokestatic tests */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + NoMethodResolutionTemplateClassBottom, + Template.AllCallsiteCases, + Template.TrivialObjectref), + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKESTATIC), + NoMethodResolutionTemplateIfaceBottom, + Template.CallsiteNotEqualsMethodref, + Template.TrivialObjectref), + /* invokevirtual tests */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + NoMethodResolutionTemplateClassBottom, + Template.AllCallsiteCases, + NoMethodSelectionTemplateClassMethodref), + /* invokeinterface tests */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + NoMethodResolutionTemplateIfaceBottom, + Template.CallsiteNotEqualsMethodref, + NoMethodSelectionTemplateIfaceMethodref), + + /* Hiding of private interface methods */ + /* invokevirtual */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEVIRTUAL), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.MethodrefNotEqualsExpectedIface, + Template.AllCallsiteCases, + Template.TrivialObjectref), + /* invokeinterface */ + new TestGroup.Simple(initBuilder, + Template.SetInvoke(SelectionResolutionTestCase.InvokeInstruction.INVOKEINTERFACE), + Template.ResultCombo(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PRIVATE), + EnumSet.of(MethodData.Context.INSTANCE, + MethodData.Context.ABSTRACT), + EnumSet.of(ClassData.Package.SAME, + ClassData.Package.DIFFERENT)), + Template.IfaceMethodrefNotEqualsExpected, + Template.AllCallsiteCases, + Template.TrivialObjectrefNotEqualMethodref) + ); + + private NoSuchMethodErrorTest() { + super(testgroups); + } + + public static void main(final String... args) { + new NoSuchMethodErrorTest().run(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Builder.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Builder.java new file mode 100644 index 00000000000..dbaebf7a9f0 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Builder.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import java.util.HashMap; + +abstract class Builder { + protected final SelectionResolutionTestCase testcase; + protected final HierarchyShape hier; + protected final HashMap classdata; + + public Builder(SelectionResolutionTestCase testcase) { + this.testcase = testcase; + this.hier = testcase.hier; + this.classdata = testcase.classdata; + } + + protected String getName(int id) { + StringBuilder name = new StringBuilder(); + + name.append(getPackageName(classdata.get(id).packageId.ordinal())); + + // Name classes C and interfaces I + name.append(getClassName(id)); + + return name.toString(); + } + + protected String getPackageName(int packageId) { + return "P" + packageId + "/"; + } + + protected String getClassName(int id) { + // Name classes C and interfaces I + if (isClass(id)) { + return "C" + id; + } else { + return "I" + id; + } + } + + protected boolean isClass(int id) { + return hier.isClass(id); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ByteCodeClassLoader.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ByteCodeClassLoader.java new file mode 100644 index 00000000000..15c0fd3d735 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ByteCodeClassLoader.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + + +public class ByteCodeClassLoader extends ClassLoader { + ArrayList classes = new ArrayList<>(); + HashMap loadedClasses = new HashMap<>(); + + public void addClasses(ClassConstruct... classes) { + this.classes.addAll(Arrays.asList(classes)); + } + + public void loadAll() throws ClassNotFoundException { + for (ClassConstruct clazz : classes) { + findClass(clazz.getDottedName()); + } + } + + + @Override + public Class findClass(String name) throws ClassNotFoundException { + + Class cls = loadedClasses.get(name); + + if (cls != null) { + return cls; + } + + for (ClassConstruct clazz : classes) { + if (clazz.getDottedName().equals(name)) { + return load(clazz); + } + } + + throw new ClassNotFoundException(name); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + try { + return findClass(name); + } catch (ClassNotFoundException e) { + return super.loadClass(name); + } + } + + private Class load(ClassConstruct clazz) { + byte[] bytecode = clazz.generateBytes(); + Class loadedClass = defineClass(clazz.getDottedName(), bytecode, 0, bytecode.length); + loadedClasses.put(clazz.getDottedName(), loadedClass); + return loadedClass; + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java new file mode 100644 index 00000000000..817b04fc1b1 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import java.util.ArrayList; +import java.util.Iterator; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PROTECTED; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; + +/** + * Constructs classes and interfaces based on the information from a + * DefaultMethodTestCase + * + */ +public class ClassBuilder extends Builder { + private final ArrayList classes; + + // Add a class in every package to be able to instantiate package + // private classes from outside the package + private final Clazz[] helpers = new Clazz[4]; + private ClassConstruct callsiteClass; + + public enum ExecutionMode { DIRECT, INDY, MH_INVOKE_EXACT, MH_INVOKE_GENERIC} + private final ExecutionMode execMode; + + public ClassBuilder(SelectionResolutionTestCase testcase, + ExecutionMode execMode) { + super(testcase); + this.classes = new ArrayList<>(); + this.execMode = execMode; + } + + public ClassConstruct[] build() throws Exception { + buildClassConstructs(); + return classes.toArray(new ClassConstruct[0]); + } + + public ClassConstruct getCallsiteClass() { + return callsiteClass; + } + + private void buildClassConstructs() throws Exception { + TestBuilder tb = new TestBuilder(testcase.methodref, testcase); + + classes.add(new Clazz("Test", ACC_PUBLIC, -1)); + + for (int classId = 0; classId < classdata.size(); classId++) { + ClassConstruct C; + String[] interfaces = getInterfaces(classId); + ClassData data = classdata.get(classId); + + if (isClass(classId)) { + C = new Clazz(getName(classId), + getExtending(classId), + getClassModifiers(data), + classId, + interfaces); + + addHelperMethod(classId); + + } else { + C = new Interface(getName(classId), + getAccessibility(data.access), + classId, interfaces); + } + + // Add a method "m()LTestObject;" if applicable + if (containsMethod(data)) { + // Method will either be abstract or concrete depending on the + // abstract modifier + C.addTestMethod(getMethodModifiers(data)); + } + + if (classId == testcase.callsite) { + // Add test() method + tb.addTest(C, execMode); + callsiteClass = C; + } + + classes.add(C); + } + classes.add(tb.getMainTestClass()); + + } + + private void addHelperMethod(int classId) { + int packageId = classdata.get(classId).packageId.ordinal(); + Clazz C = helpers[packageId]; + if (C == null) { + C = new Clazz(getPackageName(packageId) + "Helper", -1, ACC_PUBLIC); + helpers[packageId] = C; + classes.add(C); + } + + Method m = C.addMethod("get" + getClassName(classId), + "()L" + getName(classId) + ";", + ACC_PUBLIC + ACC_STATIC); + m.makeInstantiateMethod(getName(classId)); + } + + private String[] getInterfaces(int classId) { + ArrayList interfaces = new ArrayList<>(); + + // Figure out if we're extending/implementing an interface + for (final int intf : hier.interfaces()) { + if (hier.inherits(classId, intf)) { + interfaces.add(getName(intf)); + } + } + return interfaces.toArray(new String[0]); + } + + private String getExtending(int classId) { + int extending = -1; + + // See if we're extending another class + for (final int extendsClass : hier.classes()) { + if (hier.inherits(classId, extendsClass)) { + // Sanity check that we haven't already found an extending class + if (extending != -1) { + throw new RuntimeException("Multiple extending classes"); + } + extending = extendsClass; + } + } + + return extending == -1 ? null : getName(extending); + } + + /** + * Returns modifiers for a Class + * @param cd ClassData for the Class + * @return ASM modifiers for a Class + */ + private int getClassModifiers(ClassData cd) { + // For Classes we only care about accessibility (public, private etc) + return getAccessibility(cd.access) | getAbstraction(cd.abstraction); + } + + /** + * Returns modifiers for Method type + * @param cd ClassData for the Class or Interface where the Method resides + * @return ASM modifiers for the Method + */ + private int getMethodModifiers(ClassData cd) { + int mod = 0; + + // For methods we want everything + mod += getAccessibility(cd.methoddata.access); + mod += getAbstraction(cd.methoddata.context); + mod += getContext(cd.methoddata.context); + mod += getExtensibility(); + return mod; + } + + + /** + * Convert ClassData access type to ASM + * @param access + * @return ASM version of accessibility (public / private / protected) + */ + private int getAccessibility(MethodData.Access access) { + switch(access) { + case PACKAGE: + //TODO: Do I need to set this or will this be the default? + return 0; + case PRIVATE: + return ACC_PRIVATE; + case PROTECTED: + return ACC_PROTECTED; + case PUBLIC: + return ACC_PUBLIC; + default: + throw new RuntimeException("Illegal accessibility modifier: " + access); + } + } + + /** + * Convert ClassData abstraction type to ASM + * @param abstraction + * @return ASM version of abstraction (abstract / non-abstract) + */ + private int getAbstraction(MethodData.Context context) { + return context == MethodData.Context.ABSTRACT ? ACC_ABSTRACT : 0; + } + + /** + * Convert ClassData context type to ASM + * @param context + * @return ASM version of context (static / non-static) + */ + private int getContext(MethodData.Context context) { + return context == MethodData.Context.STATIC ? ACC_STATIC : 0; + } + + /** + * Convert ClassData extensibility type to ASM + * @param extensibility + * @return ASM version of extensibility (final / non-final) + */ + private int getExtensibility() { + return 0; + } + + /** + * Determine if we need a method at all, abstraction is set to null if this + * Class/Interface should not have a test method + * @param cd + * @return + */ + private boolean containsMethod(ClassData cd) { + return cd.methoddata != null; + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassConstruct.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassConstruct.java new file mode 100644 index 00000000000..240c0f3223c --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassConstruct.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import java.io.File; +import java.io.FileOutputStream; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + +public abstract class ClassConstruct { + private final ClassWriter cw; + private final String name; + private final boolean isInterface; + private final int index; + + /** + * Base constructor for building a Class or Interface + * @param name Name of Class/Interface, including package name + * @param extending Name of extending Class if any + * @param access Access for Class/Interface + * @param classFileVersion Class file version + * @param interfaces Interface implemented + */ + public ClassConstruct(String name, + String extending, + int access, + int classFileVersion, + int index, + String... interfaces) { + this.name = name; + isInterface = (access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE; + cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(classFileVersion, access, name, null, extending, interfaces == null ? new String[] { } : interfaces); + this.index = index; + } + + /** + * Get full Class/Interface name including package name, as it + * should appear in a classfile. + * + * @return The full Class/Interface name including package name + */ + public String getName() { + return name; + } + + /** + * Get the name of the class, including package as it would appear + * in Java source. + * + * @return The name of the class as it would appear in Java source. + */ + public String getDottedName() { + return name.replace("/", "."); + } + + public String getPackageName() { + final int idx = name.lastIndexOf('/'); + if (idx != -1) { + return name.substring(0, name.indexOf('/')); + } else { + return null; + } + } + + public String getClassName() { + final int idx = name.lastIndexOf('/'); + if (idx != -1) { + return name.substring(name.indexOf('/')); + } else { + return name; + } + } + + /** + * Add a method, no code associated with it yet + * @param name Name of method + * @param descriptor Descriptor for method + * @param access Access for the method + * @return Method object that can be used for constructing a method body + */ + public Method addMethod(String name, + String descriptor, + int access) { + return addMethod(name, descriptor, access, null); + } + + /** + * Add a method, no code associated with it yet + * @param name Name of method + * @param descriptor Descriptor for method + * @param access Access for the method + * @param execMode The execution mode for the method. + * @return Method object that can be used for constructing a method body + */ + public Method addMethod(String name, + String descriptor, + int access, + ClassBuilder.ExecutionMode execMode) { + return new Method(this, cw, name, descriptor, access, execMode); + } + + /** + * Adds a m()LTestObject; method which returns null unless the method is abstract + * @param access Access for the method + */ + public void addTestMethod(int access) { + Method m = new Method(this, cw, Method.defaultMethodName, Method.defaultMethodDescriptor, access, null); + if ((access & Opcodes.ACC_ABSTRACT) != Opcodes.ACC_ABSTRACT) { + m.makeDefaultMethod(); + } + } + + /** + * Construct the class to a byte[] + * @return byte[] with class file + */ + public byte[] generateBytes() { + cw.visitEnd(); + return cw.toByteArray(); + } + + /** + * Write out a class to a file in the specified directory. + * + * @param dir Directory to which to write out the file. + */ + public void writeClass(final File dir) throws Exception { + final String pkgname = getPackageName(); + final File pkgdir = pkgname != null ? new File(dir, getPackageName()) : dir; + pkgdir.mkdirs(); + final File out = new File(pkgdir, getClassName() + ".class"); + out.createNewFile(); + try (final FileOutputStream fos = new FileOutputStream(out)) { + fos.write(generateBytes()); + } + } + + public boolean isInterface() { + return isInterface; + } + + public Integer getIndex() { + return index; + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassData.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassData.java new file mode 100644 index 00000000000..4d3c09ee72e --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/ClassData.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package selectionresolution; + +/** + * A representation of information about a class. Note that classes + * here define only one method. + */ +public class ClassData { + + public enum Package { + /** + * Same package as the callsite. + */ + SAME, + /** + * Different package from the callsite. + */ + DIFFERENT, + /** + * Same as DIFFERENT, and also implies that the class access + * is package-private. + */ + INACCESSIBLE, + /** + * Different from everything else. Used in selection only, to + * test skipping package-private definitions. + */ + OTHER, + /** + * Placeholder, used solely by the template dumper for + * printing out the effects of templates. Don't use for + * anything else. + */ + PLACEHOLDER; + } + + /** + * The package ID for the class. + */ + public final Package packageId; + + /** + * The method data for the method definition. If there is no + * method definition, this will be null. + */ + public final MethodData methoddata; + + /** + * The class access. Note that this is controlled by the packageId. + */ + public final MethodData.Access access; + + // This is a hardwired value necessary for ClassBuilder + public final MethodData.Context abstraction = MethodData.Context.INSTANCE; + + public ClassData(final Package packageId, + final MethodData methoddata) { + this.packageId = packageId; + this.methoddata = methoddata; + + if (packageId == Package.INACCESSIBLE) + access = MethodData.Access.PACKAGE; + else + access = MethodData.Access.PUBLIC; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(" { "); + + if (methoddata != null) { + sb.append(methoddata); + } + + sb.append(" }\n\n"); + + return sb.toString(); + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Clazz.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Clazz.java new file mode 100644 index 00000000000..42b96b6b0d4 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Clazz.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 selectionresolution; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; + + +class Clazz extends ClassConstruct { + + /** + * Construct a Class + * @param name Name of Class + * @param access Access for the Class + */ + public Clazz(String name, int access, int index) { + this(name, null, access, V1_8, index, new String[] { }); + } + + /** + * Construct a Class + * @param name Name of Class + * @param extending Class being extended + * @param access Access for the Class + */ + public Clazz(String name, String extending, int access, int index) { + this(name, extending, access, V1_8, index, new String[] { }); + } + + /** + * Construct a Class + * @param name Name of Class + * @param extending Class being extended + * @param access access for the Class + * @param implementing Interfaces implemented + */ + public Clazz(String name, String extending, int access, int index, String... implementing) { + this(name, extending, access, V1_8, index, implementing); + } + + /** + * Construct a Class + * @param name Name of Class + * @param extending Class being extended + * @param access Access for the Class + * @param classFileVersion Class file version + * @param implementing Interfaces implemented + */ + public Clazz(String name, String extending, int access, int classFileVersion, int index, String... implementing) { + super(name, extending == null ? "java/lang/Object" : extending, access + ACC_SUPER, classFileVersion, index, implementing); + // Add the default constructor + addMethod("", "()V", ACC_PUBLIC).makeConstructor(extending); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/HierarchyShape.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/HierarchyShape.java new file mode 100644 index 00000000000..0689c89e649 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/HierarchyShape.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.Map; + +/** + * A representation of a class/interface hierarchy graph (just the + * graph; the class data is represented elsewhere). + */ +public class HierarchyShape { + public static final int OBJECT_CLASS = -1; + + protected int maxId; + + /** + * The names of all the classes. + */ + private final HashSet classes; + + /** + * The names of all the interfaces. + */ + private final HashSet interfaces; + private final HashMap> extensions; + + /** + * Create an empty hierarchy shape. + */ + public HierarchyShape() { + this(0, new HashSet<>(), new HashSet<>(), new HashMap<>()); + } + + private HierarchyShape(final int maxId, + final HashSet classes, + final HashSet interfaces, + final HashMap> extensions) { + this.maxId = maxId; + this.classes = classes; + this.interfaces = interfaces; + this.extensions = extensions; + } + + /** + * Make a copy of this hierarchy shape. + */ + public HierarchyShape copy() { + final HashMap> newextensions = new HashMap<>(); + + for(final Map.Entry> entry : + extensions.entrySet()) { + newextensions.put(entry.getKey(), + (HashSet)entry.getValue().clone()); + } + + return new HierarchyShape(maxId, (HashSet) classes.clone(), + (HashSet) interfaces.clone(), + newextensions); + } + + /** + * Add a class, and return its id. + * + * @return The new class id. + */ + public int addClass() { + final int id = maxId++; + classes.add(id); + return id; + } + + /** + * Add an interface, and return its id. + * + * @return The new interface id. + */ + public int addInterface() { + final int id = maxId++; + interfaces.add(id); + return id; + } + + /** + * Add an inheritance. + * + * @param sub The sub class/interface. + * @param sup The super class/interface + */ + public void addInherit(final int sub, + final int sup) { + HashSet ext = extensions.get(sub); + + if (ext == null) { + ext = new HashSet<>(); + extensions.put(sub, ext); + } + + ext.add(sup); + } + + @Override + public String toString() { + String out = ""; + for(int i = maxId - 1; i >= 0; i--) { + out += i + ": "; + for(int j = 0; j < maxId; j++) { + out += "[" + (inherits(i, j) ? "1" : "0") + "]"; + } + out += "\n"; + } + return out; + } + + /** + * Indicate whether the first class inherits from the second. + * + * @param sub The possible subtype. + * @param sup The possible supertype. + * @return Whether or not {@code sub} inherits from {@code sup}. + */ + public boolean inherits(final int sub, final int sup) { + final Set ext = extensions.get(sub); + if (ext != null) { + return ext.contains(sup); + } else { + return false; + } + } + + /** + * Indicate whether a given type name is a class. + * + * @param id The type in question. + * @return Whether or not the type is a class. + */ + public boolean isClass(final int id) { + if (id == OBJECT_CLASS) { + return true; + } + return classes.contains(id); + } + + /** + * Indicate whether a given type name is an interface. + * + * @param id The type in question. + * @return Whether or not the type is an interface. + */ + public boolean isInterface(final int id) { + if (id == OBJECT_CLASS) { + return false; + } + return interfaces.contains(id); + } + + /** + * Get an iterator over the classes. + * + * @return An iterator over classes. + */ + public Collection classes() { + return classes; + } + + /** + * Get an iterator over the interfaces. + * + * @return An iterator over interfaces. + */ + public Collection interfaces() { + return interfaces; + } + + /** + * Get an iterator over all types. + * + * @return An iterator over all types. + */ + public Collection types() { + final Set combined = new HashSet(classes); + combined.addAll(interfaces); + return combined; + } + + public int numClasses() { + return classes.size(); + } + + public int numInterfaces() { + return interfaces.size(); + } + + public int numTypes() { + return numClasses() + numInterfaces(); + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Interface.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Interface.java new file mode 100644 index 00000000000..ef3b51626c1 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Interface.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; + +class Interface extends ClassConstruct { + + public Interface(String name, int access, int index) { + this(name, V1_8, access, index, (String)null); + } + + public Interface(String name, int index) { + this(name, V1_8, index, (String)null); + } + + + public Interface(String name, int access, int index, String... extending) { + this(name, V1_8, access, index, extending); + } + + public Interface(String name, int classFileVersion, int access, int index, String... extending) { + super(name, "java/lang/Object", access + ACC_ABSTRACT + ACC_INTERFACE, classFileVersion, index, extending); + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Method.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Method.java new file mode 100644 index 00000000000..c09ce0fcc7d --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Method.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP; +import static jdk.internal.org.objectweb.asm.Opcodes.POP; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; +import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; +import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEINTERFACE; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; + +class Method { + public static final String defaultMethodName = "m"; + public static final String defaultMethodDescriptor = "()Ljava/lang/Integer;"; + public static final String methodDescriptorTemplate = "(L%s;)Ljava/lang/Integer;"; + private final ClassConstruct ownerClass; + private final String ownerClassName; + private final ClassVisitor cv; + private final MethodVisitor mv; + private final boolean isInterface; + private final ClassBuilder.ExecutionMode execMode; + + public Method(ClassConstruct ownerClass, ClassVisitor cv, String name, String descriptor, int access, + ClassBuilder.ExecutionMode execMode) { + this.ownerClassName = ownerClass.getName(); + this.ownerClass = ownerClass; + this.isInterface = ownerClass.isInterface(); + this.execMode = execMode; + this.cv = cv; + mv = cv.visitMethod(access, name, descriptor, null, null); + mv.visitCode(); + } + /** + * Add code for the m()Ljava/lang/Integer; method, always returns null + */ + public void makeDefaultMethod() { + mv.visitTypeInsn(NEW, "java/lang/Integer"); + mv.visitInsn(DUP); + mv.visitLdcInsn(ownerClass.getIndex()); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "", "(I)V"); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void makePrivateCallMethod(String className) { + makeSuperCallMethod(INVOKESPECIAL, className); + } + + public void makeSuperCallMethod(int invokeInstruction, String className) { + mv.visitVarInsn(ALOAD, 0); + makeCall(invokeInstruction, className); + mv.visitInsn(POP); + done(); + } + + public void defaultInvoke(int instr, String className, String objectRef) { + switch (instr) { + case INVOKEVIRTUAL: + defaultInvokeVirtual(className, objectRef); + break; + case INVOKEINTERFACE: + defaultInvokeInterface(className, objectRef); + break; + case INVOKESTATIC: + defaultInvokeStatic(className); + break; + case INVOKESPECIAL: + defaultInvokeSpecial(className, objectRef); + break; + default: + break; + } + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void defaultInvokeVirtual(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKEVIRTUAL, className, false); + } + + public void defaultInvokeInterface(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKEINTERFACE, className, true); + } + + public void defaultInvokeSpecial(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKESPECIAL, className, false); + } + + public void defaultInvokeStatic(String className) { + makeCall(INVOKESTATIC, className); + } + + private Method makeCall(int invokeInstruction, String className) { + return makeCall(invokeInstruction, className, isInterface); + } + + private Method makeCall(int invokeInstruction, String className, boolean isInterface) { + switch(execMode) { + case DIRECT: { + mv.visitMethodInsn(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor, isInterface); + break; + } + case INDY: { + Handle m = convertToHandle(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor); + Handle bsm = generateBootstrapMethod(m); + mv.visitInvokeDynamicInsn(defaultMethodName, defaultMethodDescriptor, bsm); + break; + } + case MH_INVOKE_EXACT: + case MH_INVOKE_GENERIC: { + String invokerName = execMode == ClassBuilder.ExecutionMode.MH_INVOKE_GENERIC + ? "invoke" : "invokeExact"; + + Handle m = convertToHandle(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor); + mv.visitLdcInsn(m); + mv.visitInsn(SWAP); + mv.visitMethodInsn(INVOKEVIRTUAL, + "java/lang/invoke/MethodHandle", + invokerName, + String.format(methodDescriptorTemplate, className), + false); + break; + } + default: + throw new Error("Unknown execution mode: " + execMode); + + } + return this; + } + + private Handle generateBootstrapMethod(Handle h) { + String bootstrapName = "bootstrapMethod"; + MethodType bootstrapType = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); + + MethodVisitor bmv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, bootstrapName, bootstrapType.toMethodDescriptorString(), null, null); + bmv.visitCode(); + + String constCallSite = "java/lang/invoke/ConstantCallSite"; + bmv.visitTypeInsn(NEW, constCallSite); + bmv.visitInsn(DUP); + + bmv.visitLdcInsn(h); + + bmv.visitMethodInsn(INVOKESPECIAL, constCallSite, "", "(Ljava/lang/invoke/MethodHandle;)V", false); + bmv.visitInsn(ARETURN); + + bmv.visitMaxs(0,0); + bmv.visitEnd(); + + return new Handle(H_INVOKESTATIC, ownerClassName, bootstrapName, bootstrapType.toMethodDescriptorString()); + } + + + private static Handle convertToHandle(int invokeInstruction, String className, String methodName, String methodDesc) { + int tag; + switch (invokeInstruction) { + case INVOKEVIRTUAL: tag = H_INVOKEVIRTUAL; break; + case INVOKEINTERFACE: tag = H_INVOKEINTERFACE; break; + case INVOKESPECIAL: tag = H_INVOKESPECIAL; break; + case INVOKESTATIC: tag = H_INVOKESTATIC; break; + default: + throw new Error("Unknown invoke instruction: "+invokeInstruction); + } + + return new Handle(tag, className, methodName, methodDesc); + } + + private void makeNewObject(String objectRef, String objectRefPackageName) { + String className = objectRef.substring(objectRef.lastIndexOf("/") + 1); + makeStaticCall( objectRefPackageName + "/Helper", + "get" + className, + "()L" + objectRef + ";"); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + } + + public void makeTestCall(String className) { + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, className, "test", "()Ljava/lang/Integer;", false); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + public Method makeStaticCall(String classname, String method, String descriptor) { + mv.visitMethodInsn(INVOKESTATIC, classname, method, descriptor, isInterface); + return this; + } + + public void makeConstructor(String extending) { + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, extending == null ? "java/lang/Object" : extending, "", "()V", isInterface); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void makeInstantiateMethod(String className) { + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void done() { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/MethodData.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/MethodData.java new file mode 100644 index 00000000000..bc65931920b --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/MethodData.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +/** + * A representation of a method definition. + */ +public class MethodData { + + public enum Access { + PUBLIC(1), + PACKAGE(0), + PROTECTED(4), + PRIVATE(2), + /** + * Placeholder, used solely for printing out the effects of + * templates. Don't use. + */ + PLACEHOLDER(-1); + + public final int flag; + + Access(int flag) { + this.flag = flag; + } + } + + public enum Context { + ABSTRACT, + INSTANCE, + STATIC, + /** + * Placeholder, used solely for printing out the effects of + * templates. Don't use. + */ + PLACEHOLDER; + }; + + /** + * Access for the method. + */ + public final Access access; + + /** + * Context (static, instance, abstract) for the method. + */ + public final Context context; + + /** + * Create method data. + */ + public MethodData(final Access access, + final Context context) { + + this.access = access; + this.context = context; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + switch (access) { + case PUBLIC: sb.append("public"); break; + case PACKAGE: sb.append("package"); break; + case PROTECTED: sb.append("protected"); break; + case PRIVATE: sb.append("private"); break; + case PLACEHOLDER: sb.append(" _"); break; + default: throw new RuntimeException("Impossible case"); + } + + switch (context) { + case STATIC: sb.append(" static"); break; + case INSTANCE: sb.append(" instance"); break; + case ABSTRACT: sb.append(" abstract"); break; + case PLACEHOLDER: sb.append(" _"); break; + default: throw new RuntimeException("Impossible case"); + } + sb.append(" Integer m();"); + + return sb.toString(); + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Result.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Result.java new file mode 100644 index 00000000000..6f27153221b --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Result.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package selectionresolution; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * Representation of an expected result. + */ +public interface Result { + public static final Result ICCE = new Exception(IncompatibleClassChangeError.class); + public static final Result IAE = new Exception(IllegalAccessError.class); + public static final Result NSME = new Exception(NoSuchMethodError.class); + public static final Result AME = new Exception(AbstractMethodError.class); + + // Factories + + /** + * Create a result that expects the given class. + */ + public static Result is(int id) { + return new Single(id); + } + + /** + * Create a result that expects the given classes. + */ + public static Result is(int... multiple) { + assert multiple.length > 0; + + if (multiple.length == 1) { + return new Single(multiple[0]); + } else { + return new Any(multiple); + } + } + + /** + * Create a result that expects the given exception to be thrown. + */ + public static Result is(Class exType) { + return new Exception(exType); + } + + /** + * Create a result that expects the given exception to be thrown. + */ + public static Result is(Throwable ex) { + return Result.is(ex.getClass()); + } + + public static final Result EMPTY = new Empty(); + + /** + * Create an empty Result. + */ + public static Result empty() { + return EMPTY; + } + + + public boolean complyWith(int i); + public boolean complyWith(Throwable e); + public boolean complyWith(Result r); + + static class Empty implements Result { + @Override + public boolean complyWith(int i) { + return false; + } + + @Override + public boolean complyWith(Throwable e) { + return false; + } + + @Override + public boolean complyWith(Result r) { + return false; + } + } + + static class Single implements Result { + public int id; + + public Single(int id) { + this.id = id; + } + + @Override + public boolean complyWith(int i) { + return id == i; + } + + @Override + public boolean complyWith(Throwable e) { + return false; + } + + @Override + public boolean complyWith(Result r) { + if (r instanceof Single) { + return complyWith(((Single)r).id); + } else if (r instanceof Any) { + return r.complyWith(this); + } + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Single)) return false; + + Single single = (Single) o; + + return (id == single.id); + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Result=Single{"); + sb.append("id=").append(id); + sb.append('}'); + return sb.toString(); + } + } + + static class Any implements Result { + public int[] ids; + public Any(int[] ids) { + this.ids = ids; + } + + @Override + public boolean complyWith(int i) { + return Arrays.stream(ids) + .anyMatch(j -> j == i); + } + + @Override + public boolean complyWith(Throwable e) { + return false; + } + + @Override + public boolean complyWith(Result r) { + if (r instanceof Single) { + return complyWith(((Single)r).id); + } + if (r instanceof Any) { + return Arrays.equals(ids, ((Any) r).ids); + } + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Any any = (Any) o; + + return Arrays.equals(ids, any.ids); + } + + @Override + public int hashCode() { + return Arrays.hashCode(ids); + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Result=Any{"); + sb.append("ids="); + if (ids == null) sb.append("null"); + else { + sb.append('['); + for (int i = 0; i < ids.length; ++i) + sb.append(i == 0 ? "" : ", ").append(ids[i]); + sb.append(']'); + } + sb.append('}'); + return sb.toString(); + } + } + + static class Exception implements Result { + public Class exc; + public Exception(Class e) { + this.exc = e; + } + + @Override + public boolean complyWith(int i) { + return false; + } + + @Override + public boolean complyWith(Throwable e) { + return exc.isAssignableFrom(e.getClass()); + } + + @Override + public boolean complyWith(Result r) { + if (r instanceof Exception) { + return exc.isAssignableFrom(((Exception) r).exc); + } + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Exception)) return false; + + Exception exception = (Exception) o; + + return exc.equals(exception.exc); + } + + @Override + public int hashCode() { + return exc.hashCode(); + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Result=Exception{"); + sb.append("exc=").append(exc); + sb.append('}'); + return sb.toString(); + } + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTest.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTest.java new file mode 100644 index 00000000000..4b101caf879 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package selectionresolution; + +import java.util.function.Consumer; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +/** + * A master superclass for all selection/resolution tests. Contains a + * couple of standard definitions that make writing these tests + * easier. + */ +public abstract class SelectionResolutionTest { + + /** + * A unified output function, to ensure that all output goes to + * the right string (System.err). + * + * @param str The line to print. + */ + protected void println(final String str) { + System.err.println(str); + } + + /** + * A test group is a generator for a set of tests that should + * share common characteristics. The Simple class provides a + * default implementation that should work for most purposes. + */ + public static interface TestGroup { + /** + * Given an action that runs a given test case, generate and + * run all cases in this test group. + */ + public void runCases(Consumer runner); + + /** + * The basic implementation of TestGroup. Produces one case + * for every possible combination of cases from each of its + * templates, by running them in order on an empty + * SelectionResolutionTestCase.Builder. This should be good + * enough for writing most tests. + */ + public static class Simple implements TestGroup { + private final Template[] templates; + private final SelectionResolutionTestCase.Builder initBuilder; + + public Simple(final SelectionResolutionTestCase.Builder initBuilder, + final Template... templates) { + this.templates = templates; + this.initBuilder = initBuilder; + } + + @Override + public void runCases(final Consumer runner) { + Consumer curr = (builder) -> { + runner.accept(builder.build()); + }; + + for(int i = templates.length - 1; i >= 0; i--) { + final Consumer next = curr; + final Template template = templates[i]; + curr = (builder) -> { + template.runCases(next, builder); + }; + } + + curr.accept(initBuilder); + } + } + } + + private final List errs = new LinkedList(); + + private final Collection testGroups; + + private int testcount = 0; + + /** + * Create a test from a set of test groups. Most actual tests can + * just define the test groups and pass them into this + * constructor, then call run. + */ + protected SelectionResolutionTest(final Collection testGroups) { + this.testGroups = testGroups; + } + + /** + * Run all the tests, report errors if they happen. + */ + protected void run() { + testGroups.stream().forEach( + (group) -> { + group.runCases((final SelectionResolutionTestCase testcase) -> { + testcount++; + final String err = testcase.run(); + + if (err != null) { + errs.add(err); + } + }); + }); + + println("Ran " + testcount + " cases"); + + if(!errs.isEmpty()) { + println("Errors occurred in test:"); + for(final String err : errs) { + println(err); + } + throw new RuntimeException("Errors occurred in test"); + } else { + println("All test cases succeeded"); + } + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTestCase.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTestCase.java new file mode 100644 index 00000000000..c1250d572ba --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/SelectionResolutionTestCase.java @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package selectionresolution; + +import java.io.File; +import java.io.FileWriter; +import java.util.HashMap; + +/** + * One individual test case. This class also defines a builder, which + * can be used to build up cases. + */ +public class SelectionResolutionTestCase { + + public enum InvokeInstruction { + INVOKESTATIC, + INVOKESPECIAL, + INVOKEINTERFACE, + INVOKEVIRTUAL; + } + + /** + * The class data (includes interface data). + */ + public final HashMap classdata; + /** + * The hierarchy shape. + */ + public final HierarchyShape hier; + /** + * The invoke instruction to use. + */ + public final InvokeInstruction invoke; + /** + * Which class is the methodref (or interface methodref). + */ + public final int methodref; + /** + * Which class is the objectref. + */ + public final int objectref; + /** + * Which class is the callsite (this must be a class, not an interface. + */ + public final int callsite; + /** + * The expected result. + */ + public final Result result; + + private SelectionResolutionTestCase(final HashMap classdata, + final HierarchyShape hier, + final InvokeInstruction invoke, + final int methodref, + final int objectref, + final int callsite, + final int expected) { + this.classdata = classdata; + this.hier = hier; + this.invoke = invoke; + this.methodref = methodref; + this.objectref = objectref; + this.callsite = callsite; + this.result = Result.is(expected); + } + + private SelectionResolutionTestCase(final HashMap classdata, + final HierarchyShape hier, + final InvokeInstruction invoke, + final int methodref, + final int objectref, + final int callsite, + final Result result) { + this.classdata = classdata; + this.hier = hier; + this.invoke = invoke; + this.methodref = methodref; + this.objectref = objectref; + this.callsite = callsite; + this.result = result; + } + + private static int currError = 0; + + private String dumpClasses(final ClassConstruct[] classes) + throws Exception { + final String errorDirName = "error_" + currError++; + final File errorDir = new File(errorDirName); + errorDir.mkdirs(); + for (int i = 0; i < classes.length; i++) { + classes[i].writeClass(errorDir); + } + try (final FileWriter fos = + new FileWriter(new File(errorDir, "description.txt"))) { + fos.write(this.toString()); + } + return errorDirName; + } + + /** + * Run this case, return an error message, or null. + * + * @return An error message, or null if the case succeeded. + */ + public String run() { + /* Uncomment this line to print EVERY case */ + //System.err.println("Running\n" + this); + final ClassBuilder builder = + new ClassBuilder(this, ClassBuilder.ExecutionMode.DIRECT); + try { + final ByteCodeClassLoader bcl = new ByteCodeClassLoader(); + final ClassConstruct[] classes = builder.build(); + + try { + bcl.addClasses(classes); + bcl.loadAll(); + + // Grab the callsite class. + final Class testclass = + bcl.findClass(builder.getCallsiteClass().getDottedName()); + + // Get the 'test' method out of it and call it. The + // return value tess which class that got selected. + final java.lang.reflect.Method method = + testclass.getDeclaredMethod("test"); + final int actual = (Integer) method.invoke(null); + // Check the result. + if (!result.complyWith(actual)) { + final String dump = dumpClasses(classes); + return "Failed:\n" + this + "\nExpected " + result + " got " + actual + "\nClasses written to " + dump; + } + } catch (Throwable t) { + // This catch block is handling exceptions that we + // might expect to see. + final Throwable actual = t.getCause(); + if (actual == null) { + final String dump = dumpClasses(classes); + System.err.println("Unexpected exception in test\n" + this + "\nClasses written to " + dump); + throw t; + } else if (result == null) { + final String dump = dumpClasses(classes); + return "Failed:\n" + this + "\nUnexpected exception " + actual + "\nClasses written to " + dump; + } else if (!result.complyWith(actual)) { + final String dump = dumpClasses(classes); + return "Failed:\n" + this + "\nExpected " + this.result + " got " + actual + "\nClasses written to " + dump; + } + } + } catch(Throwable e) { + throw new RuntimeException(e); + } + return null; + } + + private static void addPackage(final StringBuilder sb, + final ClassData cd) { + switch (cd.packageId) { + case SAME: sb.append("Same."); break; + case DIFFERENT: sb.append("Different."); break; + case OTHER: sb.append("Other."); break; + case PLACEHOLDER: sb.append("_."); break; + default: throw new RuntimeException("Impossible case"); + } + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + //sb.append("hierarchy:\n" + hier + "\n"); + sb.append("invoke: " + invoke + "\n"); + if (methodref != -1) { + if (hier.isClass(methodref)) { + sb.append("methodref: C" + methodref + "\n"); + } else { + sb.append("methodref: I" + methodref + "\n"); + } + } + if (objectref != -1) { + if (hier.isClass(objectref)) { + sb.append("objectref: C" + objectref + "\n"); + } else { + sb.append("objectref: I" + objectref + "\n"); + } + } + if (callsite != -1) { + if (hier.isClass(callsite)) { + sb.append("callsite: C" + callsite + "\n"); + } else { + sb.append("callsite: I" + callsite + "\n"); + } + } + sb.append("result: " + result + "\n"); + sb.append("classes:\n\n"); + + for(int i = 0; classdata.containsKey(i); i++) { + final ClassData cd = classdata.get(i); + + if (hier.isClass(i)) { + sb.append("class "); + addPackage(sb, cd); + sb.append("C" + i); + } else { + sb.append("interface "); + addPackage(sb, cd); + sb.append("I" + i); + } + + boolean first = true; + for(final int j : hier.classes()) { + if (hier.inherits(i, j)) { + if (first) { + sb.append(" extends C" + j); + } else { + sb.append(", C" + j); + } + } + } + + first = true; + for(final int j : hier.interfaces()) { + if (hier.inherits(i, j)) { + if (first) { + sb.append(" implements I" + j); + } else { + sb.append(", I" + j); + } + } + } + + sb.append(cd); + } + + return sb.toString(); + } + + /** + * A builder, facilitating building up test cases. + */ + public static class Builder { + /** + * A map from class (or interface) id's to ClassDatas + */ + public final HashMap classdata; + /** + * The hierarchy shape. + */ + public final HierarchyShape hier; + /** + * Which invoke instruction to use. + */ + public InvokeInstruction invoke; + /** + * The id of the methodref (or interface methodref). + */ + public int methodref = -1; + /** + * The id of the object ref. Note that for the generator + * framework to work, this must be set to something. If an + * objectref isn't used, just set it to the methodref. + */ + public int objectref = -1; + /** + * The id of the callsite. + */ + public int callsite = -1; + /** + * The id of the expected result. This is used to store the + * expected resolution result. + */ + public int expected; + /** + * The expected result. This needs to be set before the final + * test case is built. + */ + public Result result; + + /** + * Create an empty Builder object. + */ + public Builder() { + classdata = new HashMap<>(); + hier = new HierarchyShape(); + } + + private Builder(final HashMap classdata, + final HierarchyShape hier, + final InvokeInstruction invoke, + final int methodref, + final int objectref, + final int callsite, + final int expected, + final Result result) { + this.classdata = classdata; + this.hier = hier; + this.invoke = invoke; + this.methodref = methodref; + this.objectref = objectref; + this.callsite = callsite; + this.expected = expected; + this.result = result; + } + + private Builder(final Builder other) { + this((HashMap) other.classdata.clone(), + other.hier.copy(), other.invoke, other.methodref, other.objectref, + other.callsite, other.expected, other.result); + } + + public SelectionResolutionTestCase build() { + if (result != null) { + return new SelectionResolutionTestCase(classdata, hier, invoke, + methodref, objectref, + callsite, result); + } else { + return new SelectionResolutionTestCase(classdata, hier, invoke, + methodref, objectref, + callsite, expected); + } + } + + /** + * Set the expected result. + */ + public void setResult(final Result result) { + this.result = result; + } + + /** + * Add a class, and return its id. + * + * @return The new class' id. + */ + public int addClass(final ClassData data) { + final int id = hier.addClass(); + classdata.put(id, data); + return id; + } + + /** + * Add an interface, and return its id. + * + * @return The new class' id. + */ + public int addInterface(final ClassData data) { + final int id = hier.addInterface(); + classdata.put(id, data); + return id; + } + + /** + * Make a copy of this builder. + */ + public Builder copy() { + return new Builder(this); + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + //sb.append("hierarchy:\n" + hier + "\n"); + sb.append("invoke: " + invoke + "\n"); + if (methodref != -1) { + if (hier.isClass(methodref)) { + sb.append("methodref: C" + methodref + "\n"); + } else { + sb.append("methodref: I" + methodref + "\n"); + } + } + if (objectref != -1) { + if (hier.isClass(objectref)) { + sb.append("objectref: C" + objectref + "\n"); + } else { + sb.append("objectref: I" + objectref + "\n"); + } + } + if (callsite != -1) { + if (hier.isClass(callsite)) { + sb.append("callsite: C" + callsite + "\n"); + } else { + sb.append("callsite: I" + callsite + "\n"); + } + } + if (expected != -1) { + if (hier.isClass(expected)) { + sb.append("expected: C" + expected + "\n"); + } else { + sb.append("expected: I" + expected + "\n"); + } + } + sb.append("result: " + result + "\n"); + sb.append("classes:\n\n"); + + for(int i = 0; classdata.containsKey(i); i++) { + final ClassData cd = classdata.get(i); + + if (hier.isClass(i)) { + sb.append("class "); + addPackage(sb, cd); + sb.append("C" + i); + } else { + sb.append("interface "); + addPackage(sb, cd); + sb.append("I" + i); + } + + boolean first = true; + for(final int j : hier.classes()) { + if (hier.inherits(i, j)) { + if (first) { + sb.append(" extends C" + j); + } else { + sb.append(", C" + j); + } + } + } + + first = true; + for(final int j : hier.interfaces()) { + if (hier.inherits(i, j)) { + if (first) { + sb.append(" implements I" + j); + } else { + sb.append(", I" + j); + } + } + } + + sb.append(cd); + } + + return sb.toString(); + } + } +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Template.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Template.java new file mode 100644 index 00000000000..28e66666a50 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/Template.java @@ -0,0 +1,5005 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package selectionresolution; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedList; + +/** + * Templates are sets of transformations that are applied to a + * SelectionResolutionTestCase.Builder as part of building up a test + * case. Templates should contain a collection of different + * transforms, all of which represent an "interesting" case in a + * general category of cases. + * + */ +public class Template { + + public enum Kind { CLASS, INTERFACE; } + + public final Collection> cases; + public final String name; + + /** + * Create a template from a collection of lambdas that modify a Builder. + * + * @param name The name of the template. + * @param cases The cases in the template. + */ + public Template(final String name, + final Collection> cases) { + this.cases = cases; + this.name = name; + } + + /** + * Build a template out of a set of lambdas that modify a Builder. + * + * @param name The name of the template. + * @param cases The cases in the template. + */ + public Template(final String name, + final Consumer... cases) { + this(name, Arrays.asList(cases)); + } + + /** + * Build a template out of a set of lambdas that modify a Builder. + * Also include all cases from another template. + * + * @param name The name of the template. + * @param include Include all cases from this template. + * @param cases The cases in the template. + */ + public Template(final String name, + final Template include, + final Consumer... cases) { + this(name, new LinkedList(include.cases)); + this.cases.addAll(Arrays.asList(cases)); + } + + /** + * Build a template out of a set of lambdas that modify a Builder. + * Also include all cases from another template. + * + * @param name The name of the template. + * @param include Include all cases from this template. + * @param cases The cases in the template. + */ + public Template(final String name, + final Template... others) { + this(name, new LinkedList()); + + for(final Template template : others) { + cases.addAll(template.cases); + } + } + + /** + * Run all cases in the template. This will run each action in + * the template and then call the next action on a separate copy + * of the builder parameter. + * + * @param The next action to perform of the Builder. + * @param The Builder to modify. + */ + public void runCases(final Consumer next, + final SelectionResolutionTestCase.Builder builder) { + for(final Consumer thiscase : cases) { + final SelectionResolutionTestCase.Builder localbuilder = builder.copy(); + thiscase.accept(localbuilder); + next.accept(localbuilder); + } + } + + public void printCases(final SelectionResolutionTestCase.Builder builder) { + int i = 1; + System.err.println("Template " + name + ":\n"); + for(final Consumer thiscase : cases) { + final SelectionResolutionTestCase.Builder localbuilder = builder.copy(); + thiscase.accept(localbuilder); + System.err.println("Case " + i++); + System.err.println(localbuilder); + } + } + + /* Create an empty class in the given package */ + public static final ClassData emptyClass(final ClassData.Package pck) { + return new ClassData(pck, null); + } + + /* These are functions that are used to build callsite templates */ + public static void callsiteIsMethodref(final SelectionResolutionTestCase.Builder builder) { + builder.callsite = builder.methodref; + } + + public static void callsiteSubclassMethodref(final SelectionResolutionTestCase.Builder builder) { + final int callsite = + builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(callsite, builder.methodref); + builder.callsite = callsite; + } + + public static void callsiteUnrelatedMethodref(final SelectionResolutionTestCase.Builder builder) { + final int callsite = + builder.addClass(Template.emptyClass(ClassData.Package.SAME)); + builder.callsite = callsite; + } + + public static void methodrefIsExpected(final SelectionResolutionTestCase.Builder builder) { + builder.methodref = builder.expected; + } + + public static final Template MethodrefEqualsExpected = + new Template("MethodrefEqualsExpected", + Template::methodrefIsExpected); + + /***************************** + * Set Invoke Template * + *****************************/ + + public static final Template SetInvoke(final SelectionResolutionTestCase.InvokeInstruction invoke) { + return new Template("SetInvoke(" + invoke + ")", + Collections.singleton((builder) -> { + builder.invoke = invoke; + })); + } + + /***************************** + * Result Combo Template * + *****************************/ + public static Template ResultCombo(final EnumSet kinds, + final EnumSet accesses, + final EnumSet contexts, + final EnumSet packages) { + final LinkedList> cases = + new LinkedList<>(); + + for (final Kind kind : kinds) { + for (final MethodData.Access acc : accesses) { + for (final MethodData.Context ctx : contexts) { + if (!(acc == MethodData.Access.PRIVATE && + ctx == MethodData.Context.ABSTRACT)) { + for (final ClassData.Package pck : packages) { + cases.add((builder) -> { + final MethodData meth = new MethodData(acc, ctx); + final ClassData cls = new ClassData(pck, meth); + switch(kind) { + case CLASS: + builder.expected = builder.addClass(cls); + break; + case INTERFACE: + builder.expected = builder.addInterface(cls); + break; + } + }); + } + } + } + } + } + + return new Template("ResultCombo", cases); + } + + public static Template ResolutionOverride(final EnumSet kinds, + final EnumSet accesses, + final EnumSet contexts, + final EnumSet packages) { + final LinkedList> cases = + new LinkedList<>(); + + for (final Kind kind : kinds) { + for (final MethodData.Access acc : accesses) { + for (final MethodData.Context ctx : contexts) { + if (!(acc == MethodData.Access.PRIVATE && + ctx == MethodData.Context.ABSTRACT)) { + for (final ClassData.Package pck : packages) { + cases.add((builder) -> { + final MethodData meth = new MethodData(acc, ctx); + final ClassData cls = new ClassData(pck, meth); + int override = -1; + switch(kind) { + case CLASS: + override = builder.addClass(cls); + break; + case INTERFACE: + override = builder.addInterface(cls); + break; + } + builder.hier.addInherit(override, builder.expected); + }); + } + } + } + } + } + + return new Template("ResultCombo", cases); + } + + /****************************** + * Resolution Templates * + ******************************/ + + private static MethodData getMethodData(final MethodData.Access acc, + final MethodData.Context ctx) { + if (!(acc == MethodData.Access.PUBLIC || + acc == MethodData.Access.PLACEHOLDER) && + ctx != MethodData.Context.STATIC) { + return null; + } else { + return new MethodData(MethodData.Access.PUBLIC, ctx); + } + } + + public static final Template MethodrefNotEqualsExpectedClass = + new Template("MethodrefNotEqualsExpectedClass", + /* Case 1: Inherit from super. + * + * C2[](res) + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final int C2 = builder.expected; + final int C1 = builder.addClass(emptyClass(ClassData.Package.SAME)); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 2: Inherit from super. + * + * C2[](res), I[](def) + * C1[C2,I]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.expected; + final int C1 = builder.addClass(emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.methodref = C1; + }, + /* Case 3: Inherit from super's super. + * + * C3[](res) + * C2[](), I[](def) + * C1[C2,I]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int C3 = builder.expected; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(ClassData.Package.SAME)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.methodref = C1; + }); + + public static final Template IfaceMethodrefNotEqualsExpected = + new Template("IfaceMethodrefNotEqualsExpected", + /* Case 1: Inherit from super. + * + * I2[](res) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.methodref = I1; + }, + /* Case 2: Inherit from super, skip private. + * + * I2[](res) + * I2[I3](priv) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.methodref = I1; + }, + /* Case 3: Inherit from super, skip static. + * + * I2[](res) + * I2[I3](stat) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.methodref = I1; + }, + /* Case 4: Maximally-specific. + * + * I3[](def) + * I2[I3](res) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.methodref = I1; + }, + /* Case 5: Diamond, expected at top. + * + * I4[](res) + * I2[I4](), I3[I4]() + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I4 = builder.expected; + final int I3 = builder.addInterface(emptyClass(pck)); + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }, + /* Case 6: Diamond, skip private. + * + * I4[](res) + * I2[I4](priv), I3[I4]() + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I4 = builder.expected; + final int I3 = builder.addInterface(emptyClass(pck)); + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }, + /* Case 7: Diamond, skip static. + * + * I4[](res) + * I2[I4](stat), I3[I4]() + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I4 = builder.expected; + final int I3 = builder.addInterface(emptyClass(pck)); + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }, + /* Case 8: Diamond, maximally-specific. + * + * I4[](def) + * I2[I4](res), I3[I4]() + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I4 = builder.addInterface(withDef); + final int I3 = builder.addInterface(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }, + /* Case 9: Diamond, maximally-specific, skipping private. + * + * I4[](def) + * I2[I4](res), I3[I4](priv) + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I4 = builder.addInterface(withDef); + final int I3 = builder.addInterface(withPrivDef); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }, + /* Case 10: Diamond, maximally-specific, skipping static. + * + * I4[](def) + * I2[I4](res), I3[I4](stat) + * I1[I2,I3]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I4 = builder.addInterface(withDef); + final int I3 = builder.addInterface(withStatDef); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I4); + builder.hier.addInherit(I3, I4); + builder.methodref = I1; + }); + + public static final Template MethodrefNotEqualsExpectedIface = + new Template("MethodrefNotEqualsExpectedIface", + /* Case 1: Inherit from superinterface. + * + * I[](res) + * C[I]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I = builder.expected; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I); + builder.methodref = C; + }, + /* Case 2: Diamond, expected at top. + * + * I3[](res) + * I1[I3](), I2[I3]() + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 3: Diamond, skipping private. + * + * I3[](def) + * I1[I3](priv), I2[I3]() + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(withPrivDef); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 4: Diamond, skipping static. + * + * I3[](def) + * I1[I3](stat), I2[I3]() + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(withStatDef); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 5: Diamond, maximally-specific. + * + * I3[](def) + * I1[I3](res), I2[I3]() + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.expected; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 6: Diamond, maximally-specific, skipping private. + * + * I3[](def) + * I1[I3](res), I2[I3](priv) + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.expected; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 7: Diamond, maximally-specific, skipping static. + * + * I3[](def) + * I1[I3](res), I2[I3](stat) + * C[I1,I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.expected; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.methodref = C; + }, + /* Case 8: Diamond, with superclass, expected at top. + * + * I2[](res) + * C2[I2](), I1[I2]() + * C1[I1,C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addInterface(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.methodref = C1; + }, + /* Case 9: Diamond with superclass, maximally-specific. + * + * I2[](def) + * C2[I2](), I1[I2](res), + * C1[I1,C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I2 = builder.addInterface(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int I1 = builder.expected; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.methodref = C1; + }, + /* Case 10: Inherit through superclass. + * + * I[](res) + * C2[I]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I = builder.expected; + final int C2 = builder.addInterface(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.methodref = C1; + }, + /* Case 11: Diamond, inherit through superclass, + * expected at top. + * + * I3[](res) + * I1[I3](), I2[I3]() + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 12: Diamond through superclass, skip private. + * + * I3[](res) + * I1[I3](priv), I2[I3]() + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(withPrivDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 13: Diamond through superclass, skip static. + * + * I3[](def) + * I1[I3](stat), I2[I3]() + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(withStatDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 14: Diamond through superclass, maximally-specific. + * + * I3[](def) + * I1[I3](res), I2[I3]() + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.expected; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 15: Diamond through superclass, + * maximally-specific, skip private. + * + * I3[](def) + * I1[I3](res), I2[I3](priv) + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.expected; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 16: Diamond through superclass, + * maximally-specific, skip static. + * + * I3[](pub) + * I1[I3](res), I2[I3](stat) + * C2[I1,I2]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.addInterface(withDef); + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.expected; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 17: Diamond, with superclass, inherit through + * superclass, expected at top. + * + * I2[](res) + * C3[I2](), I1[I2]() + * C2[I1,C3]() + * C1[C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C3 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C3, I2); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }, + /* Case 18: Diamond, with superclass, inherit through + * superclass, maximally-specific. + * + * I2[](def) + * C3[I2](), I1[I2](res), + * C2[I1,C3]() + * C1[I1,C2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I2 = builder.addInterface(withDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int I1 = builder.expected; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C3, I2); + builder.hier.addInherit(C1, C2); + builder.methodref = C1; + }); + + public static final Template IfaceMethodrefAmbiguous = + new Template("IfaceMethodrefAmbiguous", + /* Ambiguous. + * + * I2[](def), I3[](def) + * I1[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData expected = + builder.classdata.get(builder.expected); + final int I3 = builder.addInterface(expected); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I1, I3); + builder.methodref = I1; + }); + + public static final Template MethodrefAmbiguous = + new Template("MethodrefAmbiguous", + /* Ambiguous. + * + * I1[](def), I2[](def) + * C[I2]() = mref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData expected = + builder.classdata.get(builder.expected); + final int I1 = builder.addInterface(expected); + final int I2 = builder.expected; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(C, I1); + builder.methodref = C; + }); + + /****************************** + * Callsite Templates * + ******************************/ + + public static final Template AllCallsiteCases = + new Template("AllCallsiteCases", + Template::callsiteIsMethodref, + Template::callsiteSubclassMethodref, + Template::callsiteUnrelatedMethodref); + + public static final Template InvokespecialCallsiteCases = + new Template("InvokespecialCallsiteCases", + Template::callsiteIsMethodref, + Template::callsiteSubclassMethodref); + + public static final Template CallsiteEqualsMethodref = + new Template("CallsiteEqualsMethodref", + Template::callsiteIsMethodref); + + public static final Template CallsiteSubclassMethodref = + new Template("CallsiteSubclassMethodref", + Template::callsiteSubclassMethodref); + + public static final Template CallsiteUnrelatedToMethodref = + new Template("CallsiteUnrelatedToMethodref", + Template::callsiteUnrelatedMethodref); + + public static final Template CallsiteNotEqualsMethodref = + new Template("CallsiteNotEqualsMethodref", + Template::callsiteSubclassMethodref, + Template::callsiteUnrelatedMethodref); + + /********************************* + * AbstractMethodError Templates * + *********************************/ + + public static final Template ReabstractExpectedIface = + new Template("ReabstractExpectedIface", + (builder) -> {}, + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData expected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = expected.packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = + getMethodData(acc, MethodData.Context.STATIC); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.addInterface(withDef); + final int C1 = builder.expected; + builder.hier.addInherit(C1, C2); + }, + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData expected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = expected.packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = + getMethodData(acc, MethodData.Context.INSTANCE); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.addInterface(withDef); + final int C1 = builder.expected; + builder.hier.addInherit(C1, C2); + }); + + public static final Template ReabstractExpectedClass = + new Template("ReabstractExpectedClass", + ReabstractExpectedIface, + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData expected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = expected.packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = + getMethodData(acc, MethodData.Context.STATIC); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.addClass(withDef); + final int C1 = builder.expected; + builder.hier.addInherit(C1, C2); + }, + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData expected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = expected.packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = + getMethodData(acc, MethodData.Context.INSTANCE); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.addClass(withDef); + final int C1 = builder.expected; + builder.hier.addInherit(C1, C2); + }); + + public static final Template ReabstractMethodrefResolvedClass = + new Template("ReabstractMethodrefResolvedClass", + /* Case 1: Objectref overrides. + * + * C2[](*) = mref + * C1[C2](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 2: Objectref's super overrides. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 3: Objectref's super overrides, skip private. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 4: Objectref's super overrides, skip static. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }); + + public static final Template ReabstractMethodrefResolvedIface = + new Template("ReabstractMethodrefResolvedIface", + /* Case 1: Objectref overrides. + * + * C2[](*) = mref + * C1[C2](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 2: Objectref's super overrides. + * + * C3[](*) = mref + * C2[C3](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 3: Objectref's super overrides, skip private. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 4: Objectref's super overrides, skip static. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 5: Overlapping with new interface overriding. + * + * I2[*](def) = old expected + * C2[*](*) = mref, I1[I2](res) = expected + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 6: Overlapping with new interface, skip private. + * + * I2[*](def) = old expected + * C2[*](*) = mref, I1[I2](res) = expected + * C1[C2,I2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 7: Overlapping with new interface, skip static. + * + * I2[*](def) = old expected + * C2[*](*) = mref, I1[I2](res) = expected + * C1[C2,I2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 8: Overlap with objectref's super with new + * interface overriding, inherit through class. + * + * I2[*](def) = old expected + * C3[](*) = mref, I1[I2](res) = expected + * C2[C3,I1]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 9: Overlap with objectref's super with new + * interface double diamond, overriding. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](def) + * C2[C3,I2](), I1[I2](res) = expected + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 10: Overlap with objectref's super with new + * interface double diamond, skip private. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](res) = expected + * C2[C3,I2](), I1[I2](priv) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withPrivDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 11: Overlap with objectref's super with new + * interface double diamond, skip static. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](res) = expected + * C2[C3,I2](), I1[I2](stat) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 12: Objectref's super overrides, skip interface below. + * + * C3[](*) = mref + * C2[C3](res) = expected, I[](def) + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 13: Objectref's super overrides, skip interface above. + * + * C3[](*) = mref, I[](def) + * C2[C3,I](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + builder.expected = C2; + }); + + public static final Template ReabstractIfaceMethodrefResolved = + new Template("ReabstractIfaceMethodrefResolved", + /* Case 1: Objectref overrides. + * + * I[](*) = mref + * C[I](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I = builder.methodref; + final int C = builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + builder.expected = C; + }, + /* Case 2: Diamond, methodref at top, overriding. + * + * I3[](*) = mref + * I1[I3](), I2[I3](res) = expected + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + builder.expected = I2; + }, + /* Case 3: Diamond, methodref at top, skip static. + * + * I3[](*) = mref + * I1[I3](), I2[I3](res) = expected + * C[I1,I2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(withStatDef); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + builder.expected = I2; + }, + /* Case 4: Diamond, with superclass, methodref at top, + * class overriding. + * + * I2[](*) = mref + * C2[I2](res) = expected, I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 5: Diamond, with superclass, methodref at top, + * class overriding, skip static. + * + * I2[](*) = mref + * C2[I2](res) = expected, I1[I2]() + * C1[I1,C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 6: Diamond, with superclass, expected at top, + * interface overriding + * + * I2[](*) = mref + * C2[I2](), I1[I2](res) = expected + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 7: Diamond, with superclass, expected at top, + * interface skip static + * + * I2[](*) = mref + * C2[I2](), I1[I2](res) = expected + * C1[I1,C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 8: Y, with superclass, overlaping, expected + * at top, class overrides + * + * C2[I2](res) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 9: Diamond, with superclass, overlaping, expected + * at top, class overrides + * + * I2[](def) = old expected + * C2[I2](res) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 10: Diamond, with superclass, overlaping, expected + * at top, class overrides, skipping static + * + * I2[](def) = old expected + * C2[I2](res) = expected, I1[](*) = mref + * C1[I1,C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 11: Superclass overrides. + * + * I[](*) = mref + * C2[I](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + }, + /* Case 12: Superclass overrides, skipping static. + * + * I[](*) = mref + * C2[I](res) = expected + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + }, + /* Case 13: Double diamond, with superclass, inherit through + * superclass, expected at top. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](res) = expected + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 14: Double diamond, with superclass, inherit through + * superclass, expected at top. + * + * I3[](def) = mref + * C3[I3](), I2[*](*) = expected + * C2[I2,C3](), I1[I2](priv) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withPrivDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 15: Double diamond, with superclass, inherit through + * superclass, expected at top. + * + * I3[](def) = mref + * C3[I3](), I2[*](*) = expected + * C2[I2,C3](), I1[I2](stat) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final ClassData withDef = + new ClassData(pck, new MethodData(acc, MethodData.Context.ABSTRACT)); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withStatDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + builder.expected = I2; + }); + + /****************************** + * Abstract Overrides * + ******************************/ + + public static final Template OverrideAbstractExpectedIface = + Template.ResolutionOverride(EnumSet.of(Template.Kind.INTERFACE), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME)); + + public static final Template OverrideAbstractExpectedClass = + Template.ResolutionOverride(EnumSet.allOf(Template.Kind.class), + EnumSet.of(MethodData.Access.PUBLIC), + EnumSet.allOf(MethodData.Context.class), + EnumSet.of(ClassData.Package.SAME)); + + public static final Template SelectionOverrideAbstract = + new Template("SelectionOverrideAbstract", + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData expected = + builder.classdata.get(builder.expected); + final MethodData olddef = + expected.methoddata; + if (MethodData.Context.ABSTRACT == olddef.context) { + final ClassData.Package pck = expected.packageId; + final MethodData.Access acc = olddef.access; + final MethodData mdata = + getMethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.objectref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + } + }); + + + /****************************** + * Ignored Abstract Templates * + ******************************/ + + public static final Template IgnoredAbstract = + new Template("IgnoredAbstract", + (builder) -> {}, + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData methodref = + builder.classdata.get(builder.methodref); + final ClassData.Package pck = methodref.packageId; + final MethodData mdata = + getMethodData(MethodData.Access.PUBLIC, + MethodData.Context.ABSTRACT); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.addInterface(withDef); + final int C1 = builder.methodref; + builder.hier.addInherit(C1, C2); + }); + + /****************************** + * Selection Templates * + ******************************/ + + + + public static final Template TrivialObjectref = + new Template("TrivialObjectref", + Collections.singleton((builder) -> { + builder.objectref = builder.methodref; + })); + + public static final Template TrivialObjectrefNotEqualMethodref = + new Template("TrivialObjectrefNotEqualMethodref", + Collections.singleton( + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = oldexpected.packageId; + final int C2 = builder.methodref; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + })); + + public static final Template MethodrefSelectionResolvedIsClassNoOverride = + new Template("MethodrefSelectionResolvedIsClassNoOverride", + /* Trivial. + * + * C[](*) = mref = oref + */ + (builder) -> { + builder.objectref = builder.methodref; + }, + /* Case 1: Inherit from super. + * + * C2[](*) = mref + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C2 = builder.methodref; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 2: Objectref has private def. + * + * C2[](*) = mref + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 3: Objectref has static def. + * + * C2[](*) = mref + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 4: Skip inherit from interface. + * + * C2[](*) = mref, I[](def) + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = oldexpected.packageId; + final MethodData.Context ctx = + builder.classdata.get(builder.expected).methoddata.context; + final MethodData.Access acc = + builder.classdata.get(builder.expected).methoddata.access; + final MethodData mdata = getMethodData(acc, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.methodref; + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }, + /* Case 5: Objectref's super has a private def. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 6: Objectref's super has a static def. + * + * C3[*](*) = mref + * C2[C3](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + public static final Template MethodrefSelectionResolvedIsClassOverride = + new Template("MethodrefSelectionResolvedIsClassOverride", + /* Case 7: Objectref overrides. + * + * C2[](*) = mref + * C1[C2](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 8: Objectref's super overrides. + * + * C3[*](*) = mref + * C2[C3](res) + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 9: Objectref's super overrides, + * objectref has a private def. + * + * C3[*](*) = mref + * C2[C3](res) + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 10: Objectref's super overrides, + * objectref has a static def. + * + * C3[*](*) = mref + * C2[C3](res) + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }); + + public static final Template MethodrefSelectionResolvedIsClass = + new Template("MethodrefSelectionResolvedIsClass", + MethodrefSelectionResolvedIsClassNoOverride, + MethodrefSelectionResolvedIsClassOverride); + + public static final Template MethodrefSelectionPackageSkipNoOverride = + new Template("MethodrefSelectionPackageSkipNoOverride", + MethodrefSelectionResolvedIsClass, + /* Case 11: Objectref has public def in other package. + * + * C2[](*) = mref + * Other.C1[C2](pub) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 12: Objectref has package private def in other package. + * + * C2[](*) = mref + * Other.C1[C2](pack) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 13: Objectref has protected def in other package. + * + * C2[](*) = mref + * Other.C1[C2](prot) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 14: Objectref's super has a public def in other package. + * + * C3[*](*) = mref + * Other.C2[C3](pub) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 15: Objectref's super has a package + * private def in other package. + * + * C3[*](*) = mref + * Other.C2[C3](pack) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 16: Objectref's super has a protected def + * in other package. + * + * C3[*](*) = mref + * Other.C2[C3](pack) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 18: Objectref's has a public def in other + * package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](priv) + * C1[C2](pub) = oref, expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withPrivDef); + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 19: Objectref's has a package private def in other + * package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](priv) + * C1[C2](pack) = oref, expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withPrivDef); + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 20: Objectref's has a protected def in other + * package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](priv) + * C1[C2](pro) = oref, expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withPrivDef); + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 21: Objectref's super has a public def in other + * package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](pub) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 22: Objectref's superhas a package private + * def in other package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](pack) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 23: Objectref's super has a protected def + * in other package, skip private. + * + * C3[*](*) = mref + * Other.C2[C3](pro) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(ClassData.Package.OTHER, meth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withPrivDef); + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + public static final Template MethodrefSelectionPackageSkip = + new Template("MethodrefSelectionPackageSkip", + MethodrefSelectionPackageSkipNoOverride, + /* Case 17: Transitive override. + * + * C3[*](*) = mref + * C2[C3](pub) + * Other.C1[C2](pack) = oref, expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final MethodData packmeth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withPubDef = new ClassData(pck, meth); + final ClassData withPackDef = + new ClassData(ClassData.Package.OTHER, packmeth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withPubDef); + final int C1 = builder.addClass(withPackDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 24: Transitive override, skip private in between. + * + * C4[*](*) = mref + * C3[C4](pub) + * C2[C3](priv) + * Other.C1[C2](pack) = oref, expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final MethodData packmeth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withPubDef = new ClassData(pck, meth); + final ClassData withPackDef = + new ClassData(ClassData.Package.OTHER, packmeth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C4 = builder.methodref; + final int C3 = builder.addClass(withPubDef); + final int C2 = builder.addClass(withPrivDef); + final int C1 = builder.addClass(withPackDef); + builder.hier.addInherit(C3, C4); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 25: Transitive override, skip private in between. + * + * C4[*](*) = mref + * C3[C4](pub) + * Other.C2[C3](pack) = expected + * C1[C2](pack) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.INSTANCE); + final MethodData packmeth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withPubDef = new ClassData(pck, meth); + final ClassData withPackDef = + new ClassData(ClassData.Package.OTHER, packmeth); + final MethodData privmeth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, privmeth); + final int C4 = builder.methodref; + final int C3 = builder.addClass(withPubDef); + final int C2 = builder.addClass(withPackDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C3, C4); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C2; + builder.expected = C2; + }); + + public static final Template MethodrefSelectionResolvedIsIfaceNoOverride = + new Template("MethodrefSelectionResolvedIsIfaceNoOverride", + /* Trivial objectref. + * + * C[](*) = mref = oref + */ + (builder) -> { + builder.objectref = builder.methodref; + }, + /* Case 1: Inherit from super. + * + * C2[](*) = mref + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C2 = builder.methodref; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 2: Objectref has private def. + * + * C2[](*) = mref + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 3: Objectref has static def. + * + * C2[](*) = mref + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withDef = new ClassData(pck, meth); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 4: Overlapping. + * + * I[*](res) = expected + * C2[*](*) = mref + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C2 = builder.methodref; + final int I = builder.expected; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }, + /* Case 5: Overlapping with new interface. + * + * I2[*](res) = expected + * C2[*](*) = mref, I1[I2]() + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 6: Overlapping with new interface with private def. + * + * I2[*](res) = expected + * C2[*](*) = mref, I1[I2](priv) + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withPrivDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 7: Overlapping with new interface with static def. + * + * I2[*](res) = expected + * C2[*](*) = mref, I1[I2](stat) + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 8: Objectref's super has a private def. + * + * C3[*](*) = mref + * C2[C3](priv) + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 9: Objectref's super has a static def. + * + * C3[*](*) = mref + * C2[C3](stat) + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 10: Overlap with objectref's super. + * + * I[*](res) = expected + * C3[](*) = mref + * C2[C3,I]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I = builder.expected; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + }, + /* Case 11: Overlap with objectref's super with new interface. + * + * I2[*](res) = expected + * C3[](*) = mref, I1[I2]() + * C2[C3,I1]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 12: Overlap with objectref's super with new + * interface with private def. + * + * I2[*](res) = expected + * C3[](*) = mref, I1[I2](priv) + * C2[C3,I1]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(withPrivDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 13: Overlap with objectref's super with new + * interface with static def. + * + * I2[*](res) = expected + * C3[](*) = mref, I1[I2](stat) + * C2[C3,I1]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 14: Overlap with objectref's super with new + * interface double diamond. + * + * I3[*](res) = expected + * C3[](*) = mref, I2[I3]() + * C2[C3,I2](), I1[I2]() + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + }, + /* Case 15: Overlapping with new interface with private def. + * + * C2[*](*) = mref, I1[](priv) + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I1 = builder.addInterface(withPrivDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }, + /* Case 16: Overlapping with new interface with static def. + * + * C2[*](*) = mref, I1[](stat) + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int C2 = builder.methodref; + final int I1 = builder.addInterface(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }); + + public static final Template MethodrefSelectionResolvedIsIface = + new Template("MethodrefSelectionResolvedIsIface", + MethodrefSelectionResolvedIsIfaceNoOverride, + /* Case 17: Objectref overrides. + * + * C2[](*) = mref + * C1[C2](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C2 = builder.methodref; + final int C1 = builder.addClass(withDef); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C1; + }, + /* Case 18: Overlapping with new interface overriding. + * + * I2[*](def) = old expected + * C2[*](*) = mref, I1[I2](res) = expected + * C1[C2,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C2 = builder.methodref; + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 19: Objectref's super overrides. + * + * C3[](*) = mref + * C2[C3](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 20: Overlap with objectref's super with + * new interface overriding. + * + * I2[*](def) = old expected + * C3[](*) = mref, I1[I2](res) = expected + * C2[C3,I1]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I2 = builder.expected; + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(I1, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 21: Overlap with objectref's super with new + * interface double diamond, overriding. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](def) + * C2[C3,I2](), I1[I2](res) = expected + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 22: Objectref's super overrides, skip private. + * + * C3[](*) = mref + * C2[C3](res) = expected + * C1[C2](priv) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withPrivDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 23: Objectref's super overrides, skip static. + * + * C3[](*) = mref + * C2[C3](res) = expected + * C1[C2](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(withStatDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 24: Overlap with objectref's super with new + * interface double diamond, overriding, skip private. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](res) = expected + * C2[C3,I2](), I1[I2](priv) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withPrivDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 25: Overlap with objectref's super with new + * interface double diamond, overriding, skip static. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](res) = expected + * C2[C3,I2](), I1[I2](stat) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int C3 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 26: Skip interface method after class overrides. + * + * C3[](*) = mref + * C2[C3](res) = expected, I[](def) + * C1[C2, I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 27: Skip interface method after class overrides. + * + * C3[](*) = mref, I[](def) + * C2[C3,I](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 28: Overlap with objectref's super with new + * interface double diamond, overriding. + * + * I3[*](def) = old expected + * C3[](*) = mref, I2[I3](def) + * C2[C3,I2](res) = expected, I1[I2](def) = expected + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int C3 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int I3 = builder.expected; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(I2, I3); + builder.objectref = C1; + builder.expected = C2; + }); + + public static final Template IfaceMethodrefSelectionNoOverride = + new Template("IfaceMethodrefSelectionNoOverride", + /* Case 1: Inherit from super. + * + * I[](*) = mref + * C[I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final int I = builder.methodref; + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I); + builder.objectref = C; + }, + /* Case 2: Objectref has static def + * + * I[](*) = mref + * C[I](stat) = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C = builder.addClass(withStatDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + }, + /* Case 3: Diamond, methodref at top. + * + * I3[](*) = mref + * I1[I3](), I2[I3]() + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.methodref; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + }, + /* Case 4: Diamond, methodref at top, skip private def + * + * I3[](*) = mref + * I1[I3](), I2[I3](priv) + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + }, + /* Case 5: Diamond, methodref at top, skip static def + * + * I3[](*) = mref + * I1[I3](), I2[I3](stat) + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + }, + /* Case 6: Diamond, overlap with resolution. + * + * I3[](res) = expected + * I1[I3](), I2[](*) = mref + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.objectref = C; + }, + /* Case 7: Diamond, with superclass, expected at top. + * + * I2[](*) = mref + * C2[I2](), I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 8: Diamond, with superclass, expected at top, + * class has static def. + * + * I2[](*) = mref + * C2[I2](stat), I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 9: Diamond, with superclass, expected at top, + * interface has private def + * + * I2[](*) = mref + * C2[I2](), I1[I2](priv) + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withPrivDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 10: Diamond, with superclass, expected at top, + * interface has static def + * + * I2[](*) = mref + * C2[I2](), I1[I2](stat) + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withPrivDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 11: Y, with superclass, expected + * at top. + * + * C2[](), I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I1 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 12: Y, with superclass, expected + * at top, class has static def + * + * C2[](stat), I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I1 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 13: Diamond, with superclass, overlapping, expected + * at top. + * + * I2[](res) = expected + * C2[I2](), I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 14: Diamond, with superclass, overlapping, expected + * at top, class has static def + * + * I2[](def) = expected + * C2[I2](stat), I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + }, + /* Case 15: Inherit through superclass. + * + * I[](*) = mref + * C2[I]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I = builder.methodref; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + }, + /* Case 16: Superclass has static def. + * + * I[](*) = mref + * C2[I](stat) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C2 = builder.addClass(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.objectref = C1; + }, + /* Case 17: Diamond, inherit through superclass, + * methodref at top. + * + * I3[](*) = mref + * I1[I3](), I2[I3]() + * C2[I1,I2]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.methodref; + final int I2 = builder.addInterface(emptyClass(pck)); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 18: Diamond, with superclass, inherit through + * superclass, methodref at top. + * + * I2[](*) = mref + * C3[I2](), I1[I2]() + * C2[I1,C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C3, I2); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 19: Diamond, inherit through superclass, + * expected at top, skip private. + * + * I3[](*) = mref + * I1[I3](), I2[I3](priv) + * C2[I1,I2]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withPrivDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 20: Diamond, inherit through superclass, + * expected at top, skip static. + * + * I3[](*) = mref + * I1[I3](), I2[I3](stat) + * C2[I1,I2]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withStatDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 21: Diamond, inherit through superclass, + * overlapping, expected at top. + * + * I3[](res) = expected + * I1[I3](), I2[*](*) = mref + * C2[I1,I2]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 22: Y, with superclass, inherit through + * superclass, expected at top. + * + * C3[](), I1[*](*) = mref + * C2[I1,C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I1 = builder.methodref; + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 23: Diamond, with superclass, inherit through + * superclass, overlapping, expected at top. + * + * I2[](res) = expected + * C3[I2](), I1[*](*) = mref + * C2[I1,C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I2); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }, + /* Case 24: Double diamond, with superclass, inherit through + * superclass, overlapping expected at top. + * + * I3[](res) = expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2]() + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }, + /* Case 25: Double diamond, with superclass, inherit through + * superclass, skip private. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](priv) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withPrivDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }, + /* Case 26: Double diamond, with superclass, inherit through + * superclass, skip static. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](stat) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withStatDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }); + + public static final Template IfaceMethodrefSelection = + new Template("IfaceMethodrefSelection", + IfaceMethodrefSelectionNoOverride, + /* Case 27: Objectref overrides. + * + * I[](*) = mref + * C[I](res) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I = builder.methodref; + final int C = builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + builder.expected = C; + }, + /* Case 28: Diamond, methodref at top, overriding. + * + * I3[](*) = mref + * I1[I3](), I2[I3](res) = expected + * C[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.objectref = C; + builder.expected = I2; + }, + /* Case 29: Diamond, with superclass, expected at top, + * class overriding. + * + * I2[](*) = mref + * C2[I2](res) = expected, I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 30: Diamond, with superclass, expected at top, + * interface overriding + * + * I2[](*) = mref + * C2[I2](), I1[I2](res) = expected + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 31: Y, with superclass, overlaping, expected + * at top, class overrides + * + * C2[](res) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 32: Diamond, with superclass, overlaping, expected + * at top, class overrides + * + * I2[](def) = old expected + * C2[I2](res) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 33: Superclass overrides. + * + * I[](*) = mref + * C2[I](res) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.expected = C2; + builder.objectref = C1; + }, + /* Case 34: Diamond, inherit through superclass, + * expected at top, override. + * + * I3[](*) = mref + * I1[I3](), I2[I3](res) = expected + * C2[I1,I2]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I3 = builder.methodref; + final int I2 = builder.addInterface(withDef); + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(I1, I3); + builder.hier.addInherit(I2, I3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = I2; + }, + /* Case 35: Y, with superclass, inherit through + * superclass, overlapping, expected at top. + * + * C3[](res) = expected, I1[*](*) = mref + * C2[I1,C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I1 = builder.methodref; + final int C3 = builder.addClass(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C3; + }, + /* Case 36: Diamond, with superclass, inherit through + * superclass, overlapping, expected at top. + * + * I2[](*) = oldexpected + * C3[I2](res) = expected, I1[*](*) = mref + * C2[I1,C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C3 = builder.addClass(withDef); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I1); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I2); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C3; + }, + /* Case 37: Double diamond, with superclass, inherit through + * superclass, overriding. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](res) = expected + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + builder.expected = I1; + }, + /* Case 38: Double diamond, with superclass, inherit through + * superclass, skip private. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](priv) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withPrivDef = + new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withPrivDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }, + /* Case 39: Double diamond, with superclass, inherit through + * superclass, skip static. + * + * I3[](def) = old expected + * C3[I3](), I2[*](*) = mref + * C2[I2,C3](), I1[I2](stat) + * C1[C2,I1]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I3 = builder.expected; + final int I2 = builder.methodref; + final int I1 = builder.addInterface(withStatDef); + final int C3 = builder.addClass(emptyClass(pck)); + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, I2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C3, I3); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C1, I1); + builder.objectref = C1; + }, + /* Case 40: Superclass overrides. + * + * I[](*) = mref + * C3[I](res) = expected + * C2[C3](stat) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData withDef = + new ClassData(pck, oldexpected.methoddata); + final MethodData meth = + new MethodData(MethodData.Access.PUBLIC, + MethodData.Context.STATIC); + final ClassData withStatDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C3 = builder.addClass(withDef); + final int C2 = builder.addClass(withStatDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C2, I); + builder.expected = C3; + builder.objectref = C1; + }); + + public static final Template IfaceMethodrefSelectionOverrideNonPublic = + new Template("IfaceMethodrefSelection", + /* Case 1: Objectref overrides. + * + * I[](*) = mref + * C[I](priv) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C = builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + builder.expected = C; + }, + /* Case 2: Objectref overrides. + * + * I[](*) = mref + * C[I](prot) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C = builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + builder.expected = C; + }, + /* Case 3: Objectref overrides package private. + * + * I[](*) = mref + * C[I](pack) = oref = expected + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.methodref).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C = builder.addClass(withDef); + builder.hier.addInherit(C, I); + builder.objectref = C; + builder.expected = C; + }, + /* Case 4: Diamond, with superclass, expected at top, + * class overriding with private. + * + * I2[](*) = mref + * C2[I2](priv) = expected, I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 5: Diamond, with superclass, expected at top, + * class overriding with package private. + * + * I2[](*) = mref + * C2[I2](pack) = expected, I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 6: Diamond, with superclass, expected at top, + * class overriding with protected. + * + * I2[](*) = mref + * C2[I2](prot) = expected, I1[I2]() + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.methodref; + final int I1 = builder.addInterface(emptyClass(pck)); + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(I1, I2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 7: Y, with superclass, overlaping, expected + * at top, class overrides + * + * C2[](priv) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 8: Y, with superclass, overlaping, expected + * at top, class overrides + * + * C2[](prot) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 9: Y, with superclass, overlaping, expected + * at top, class overrides + * + * C2[](pack) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 10: Diamond, with superclass, overlaping, expected + * at top, class overrides + * + * I2[](def) = old expected + * C2[I2](priv) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 11: Diamond, with superclass, overlaping, expected + * at top, class overrides + * + * I2[](def) = old expected + * C2[I2](pack) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 12: Diamond, with superclass, overlaping, expected + * at top, class overrides + * + * I2[](def) = old expected + * C2[I2](prot) = expected, I1[](*) = mref + * C1[I1,C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I2 = builder.expected; + final int I1 = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I1); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I2); + builder.objectref = C1; + builder.expected = C2; + }, + /* Case 13: Superclass overrides. + * + * I[](*) = mref + * C2[I](priv) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PRIVATE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.expected = C2; + builder.objectref = C1; + }, + /* Case 14: Superclass overrides. + * + * I[](*) = mref + * C2[I](prot) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PROTECTED, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.expected = C2; + builder.objectref = C1; + }, + /* Case 15: Superclass overrides. + * + * I[](*) = mref + * C2[I](pack) = expected + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.expected).packageId; + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final MethodData meth = + new MethodData(MethodData.Access.PACKAGE, + MethodData.Context.INSTANCE); + final ClassData withDef = + new ClassData(pck, meth); + final int I = builder.methodref; + final int C2 = builder.addClass(withDef); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, I); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C2, I); + builder.expected = C2; + builder.objectref = C1; + }); + + /*********************** + * Ambiguous selection * + ***********************/ + + public static final Template MethodrefAmbiguousResolvedIsIface = + new Template("MethodrefAmbiguousResolvedIsIface", + /* Inherit from interface. + * + * C2[](*) = mref, I[](any) + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = oldexpected.packageId; + final MethodData.Context ctx = oldexpected.methoddata.context; + final MethodData mdata = + new MethodData(MethodData.Access.PUBLIC, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.methodref; + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }); + + public static final Template IfaceMethodrefAmbiguousResolvedIsIface = + new Template("IfaceMethodrefAmbiguousResolvedIsIface", + /* Inherit from interface. + * + * I1[](*) = mref, I2[](any) + * C1[I1,I2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = oldexpected.packageId; + final MethodData.Context ctx = oldexpected.methoddata.context; + final MethodData mdata = + new MethodData(MethodData.Access.PUBLIC, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int I1 = builder.methodref; + final int C = builder.addClass(emptyClass(pck)); + final int I2 = builder.addInterface(withDef); + builder.hier.addInherit(C, I1); + builder.hier.addInherit(C, I2); + builder.objectref = C; + }); + + public static final Template InvokespecialAmbiguousResolvedIsIface = + new Template("InvokespecialAmbiguousResolvedIsIface", + /* Inherit from interface. + * + * C2[](*) = csite, I[](any) + * C1[C2,I]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData oldexpected = + builder.classdata.get(builder.expected); + final ClassData.Package pck = oldexpected.packageId; + final MethodData.Context ctx = oldexpected.methoddata.context; + final MethodData mdata = + new MethodData(MethodData.Access.PUBLIC, ctx); + final ClassData withDef = new ClassData(pck, mdata); + final int C2 = builder.callsite; + final int C1 = builder.addClass(emptyClass(pck)); + final int I = builder.addInterface(withDef); + builder.hier.addInherit(C1, C2); + builder.hier.addInherit(C1, I); + builder.objectref = C1; + }); + + /****************************** + * invokespecial Templates * + ******************************/ + + // Create this by taking MethodrefSelection and replacing + // methodref with callsite. + public static final Template ObjectrefAssignableToCallsite = + new Template("ObjectrefAssignableToCallsite", + /* Case 1: Objectref equals callsite + * + * C[](*) = csite = oref + */ + (builder) -> { + builder.objectref = builder.callsite; + }, + /* Case 2: Inherit from super. + * + * C2[](*) = csite + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.callsite).packageId; + final int C2 = builder.callsite; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + public static final Template ObjectrefExactSubclassOfCallsite = + new Template("ObjectrefSubclassOfCallsite", + /* Inherit from super. + * + * C2[](*) = csite + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.callsite).packageId; + final int C2 = builder.callsite; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + public static final Template ObjectrefEqualsOrExactSubclassOfCallsite = + new Template("ObjectrefEqualsOrExactSubclassOfCallsite", + (final SelectionResolutionTestCase.Builder builder) -> { + builder.objectref = builder.callsite; + }, + /* Inherit from super. + * + * C2[](*) = csite + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.callsite).packageId; + final int C2 = builder.callsite; + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + public static final Template ObjectrefEqualsCallsite = + new Template("TrivialObjectref", + Collections.singleton((builder) -> { + builder.objectref = builder.callsite; + })); + + public static final Template ObjectrefSubclassOfSubclassOfCallsite = + new Template("ObjectrefSubclassOfCallsite", + /* Inherit from super. + * + * C3[](*) = csite + * C2[C3]() + * C1[C2]() = oref + */ + (final SelectionResolutionTestCase.Builder builder) -> { + final ClassData.Package pck = + builder.classdata.get(builder.callsite).packageId; + final int C3 = builder.callsite; + final int C2 = builder.addClass(emptyClass(pck)); + final int C1 = builder.addClass(emptyClass(pck)); + builder.hier.addInherit(C2, C3); + builder.hier.addInherit(C1, C2); + builder.objectref = C1; + }); + + private static class Placeholder extends ClassData { + private final String placeholder; + + + private Placeholder(final String placeholder, + final MethodData methoddata) { + super(ClassData.Package.PLACEHOLDER, methoddata); + this.placeholder = placeholder; + } + + private Placeholder(final String placeholder) { + this(placeholder, null); + } + + public String toString() { + return " = \n\n"; + } + + public static final Placeholder objectref = new Placeholder("objectref"); + public static final Placeholder methodref = new Placeholder("methodref"); + public static final Placeholder callsite = new Placeholder("callsite"); + public static final Placeholder expected = + new Placeholder("expected", + new MethodData(MethodData.Access.PLACEHOLDER, + MethodData.Context.PLACEHOLDER)); + } + + public static void main(String... args) { + + System.err.println("*** Resolution Templates ***\n"); + final SelectionResolutionTestCase.Builder withExpectedIface = + new SelectionResolutionTestCase.Builder(); + withExpectedIface.expected = + withExpectedIface.addInterface(Placeholder.expected); + final SelectionResolutionTestCase.Builder withExpectedClass = + new SelectionResolutionTestCase.Builder(); + withExpectedClass.expected = + withExpectedClass.addClass(Placeholder.expected); + + MethodrefNotEqualsExpectedClass.printCases(withExpectedClass); + MethodrefNotEqualsExpectedIface.printCases(withExpectedIface); + IfaceMethodrefNotEqualsExpected.printCases(withExpectedIface); + MethodrefAmbiguous.printCases(withExpectedIface); + IfaceMethodrefAmbiguous.printCases(withExpectedIface); + ReabstractExpectedIface.printCases(withExpectedIface); + ReabstractExpectedClass.printCases(withExpectedClass); + + final SelectionResolutionTestCase.Builder methodrefExpectedIface = + withExpectedIface.copy(); + methodrefExpectedIface.methodref = + methodrefExpectedIface.addClass(Placeholder.methodref); + final SelectionResolutionTestCase.Builder methodrefExpectedClass = + withExpectedClass.copy(); + methodrefExpectedClass.methodref = + methodrefExpectedClass.addClass(Placeholder.methodref); + final SelectionResolutionTestCase.Builder ifaceMethodref = + withExpectedIface.copy(); + ifaceMethodref.methodref = + ifaceMethodref.addInterface(Placeholder.methodref); + + IgnoredAbstract.printCases(methodrefExpectedIface); + MethodrefSelectionResolvedIsClass.printCases(methodrefExpectedClass); + MethodrefSelectionResolvedIsIface.printCases(methodrefExpectedIface); + IfaceMethodrefSelection.printCases(ifaceMethodref); + IfaceMethodrefSelectionOverrideNonPublic.printCases(ifaceMethodref); + + } + +} diff --git a/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java new file mode 100644 index 00000000000..a24a91fe0a2 --- /dev/null +++ b/hotspot/test/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package selectionresolution; + +import jdk.internal.org.objectweb.asm.Opcodes; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; + +class TestBuilder extends Builder { + private final ClassConstruct testClass; + private final Method mainMethod; + + public TestBuilder(int classId, SelectionResolutionTestCase testcase) { + super(testcase); + + // Make a public class Test that contains all our test methods + testClass = new Clazz("Test", null, -1, ACC_PUBLIC); + + // Add a main method + mainMethod = testClass.addMethod("main", "([Ljava/lang/String;)V", ACC_PUBLIC + ACC_STATIC); + + } + + public ClassConstruct getMainTestClass() { + mainMethod.done(); + return testClass; + } + + public void addTest(ClassConstruct clazz, ClassBuilder.ExecutionMode execMode) { + Method m = clazz.addMethod("test", "()Ljava/lang/Integer;", ACC_PUBLIC + ACC_STATIC, execMode); + m.defaultInvoke(getInvokeInstruction(testcase.invoke), + getName(testcase.methodref), + getName(testcase.objectref)); + + mainMethod.makeStaticCall(clazz.getName(), "test", "()Ljava/lang/Integer;").done(); + } + + private static int getInvokeInstruction(SelectionResolutionTestCase.InvokeInstruction instr) { + switch (instr) { + case INVOKESTATIC: + return Opcodes.INVOKESTATIC; + case INVOKESPECIAL: + return Opcodes.INVOKESPECIAL; + case INVOKEINTERFACE: + return Opcodes.INVOKEINTERFACE; + case INVOKEVIRTUAL: + return Opcodes.INVOKEVIRTUAL; + default: + throw new AssertionError(instr.name()); + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java index 3b69f956465..efc95b94b83 100644 --- a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java +++ b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java @@ -27,14 +27,12 @@ * @library /testlibrary * @modules java.base/jdk.internal.misc * java.management - * jdk.jartool/sun.tools.jar * jdk.jvmstat/sun.jvmstat.monitor * @ignore 8150683 * @compile javax/sound/sampled/MyClass.jasm * @compile org/omg/CORBA/Context.jasm * @compile nonjdk/myPackage/MyClass.java - * @build jdk.test.lib.* LoadClass - * @run main ClassFileInstaller LoadClass + * @build jdk.test.lib.* LoadClass ClassFileInstaller * @run main/othervm BootAppendTests */ @@ -90,11 +88,9 @@ public class BootAppendTests { fos.close(); // build jar files - BasicJarBuilder.build(true, "app", APP_CLASS); - appJar = BasicJarBuilder.getTestJar("app.jar"); - BasicJarBuilder.build("bootAppend", + appJar = ClassFileInstaller.writeJar("app.jar", APP_CLASS); + bootAppendJar = ClassFileInstaller.writeJar("bootAppend.jar", BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS); - bootAppendJar = BasicJarBuilder.getTestJar("bootAppend.jar"); // dump ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( diff --git a/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java b/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java index 96036ec3629..ed2b3e3dbc5 100644 --- a/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java +++ b/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java @@ -32,23 +32,20 @@ * @library /testlibrary /test/lib * @modules java.base/jdk.internal.misc * java.management - * jdk.jartool/sun.tools.jar - * @build SharedStringsWb SharedStrings BasicJarBuilder sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @build SharedStringsWb SharedStrings ClassFileInstaller sun.hotspot.WhiteBox + * @run main ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox * @run main SharedStrings */ import jdk.test.lib.*; public class SharedStrings { public static void main(String[] args) throws Exception { - BasicJarBuilder.build(true, "whitebox", "sun/hotspot/WhiteBox"); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedStrings.jsa", "-XX:+PrintSharedSpaces", // Needed for bootclasspath match, for CDS to work with WhiteBox API - "-Xbootclasspath/a:" + BasicJarBuilder.getTestJar("whitebox.jar"), + "-Xbootclasspath/a:" + ClassFileInstaller.getJarPath("whitebox.jar"), "-Xshare:dump"); new OutputAnalyzer(pb.start()) @@ -62,7 +59,7 @@ public class SharedStrings { // these are required modes for shared strings "-XX:+UseCompressedOops", "-XX:+UseG1GC", // needed for access to white box test API - "-Xbootclasspath/a:" + BasicJarBuilder.getTestJar("whitebox.jar"), + "-Xbootclasspath/a:" + ClassFileInstaller.getJarPath("whitebox.jar"), "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-Xshare:on", "-showversion", "SharedStringsWb"); diff --git a/hotspot/test/runtime/Throwable/StackTraceLogging.java b/hotspot/test/runtime/Throwable/StackTraceLogging.java new file mode 100644 index 00000000000..9074ef4f709 --- /dev/null +++ b/hotspot/test/runtime/Throwable/StackTraceLogging.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 8150778 + * @summary check stacktrace logging + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @compile TestThrowable.java + * @run driver StackTraceLogging + */ + +import java.io.File; +import java.util.Map; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class StackTraceLogging { + static void updateEnvironment(ProcessBuilder pb, String environmentVariable, String value) { + Map env = pb.environment(); + env.put(environmentVariable, value); + } + + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + // These depths match the ones in TestThrowable.java + int[] depths = {10, 34, 100, 1024}; + for (int d : depths) { + output.shouldContain("java.lang.RuntimeException, " + d); + } + output.shouldHaveExitValue(0); + } + + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stacktrace=info", + "-XX:MaxJavaStackTraceDepth=1024", + "TestThrowable"); + analyzeOutputOn(pb); + } +} diff --git a/hotspot/test/runtime/Throwable/TestThrowable.java b/hotspot/test/runtime/Throwable/TestThrowable.java new file mode 100644 index 00000000000..f3cb1ad2bcc --- /dev/null +++ b/hotspot/test/runtime/Throwable/TestThrowable.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8150778 + * @summary Test exception depths, and code to get stack traces + * @library /testlibrary + * @run main/othervm -XX:MaxJavaStackTraceDepth=1024 TestThrowable + */ + +import java.lang.reflect.Field; +import jdk.test.lib.Asserts; + +public class TestThrowable { + + // Inner class that throws a lot of exceptions + static class Thrower { + static int MaxJavaStackTraceDepth = 1024; // as above + int[] depths = {10, 34, 100, 1024, 2042}; + int count = 0; + + int getDepth(Throwable t) throws Exception { + Field f = Throwable.class.getDeclaredField("depth"); + f.setAccessible(true); // it's private + return f.getInt(t); + } + + void callThrow(int depth) { + if (++count < depth) { + callThrow(depth); + } else { + throw new RuntimeException("depth tested " + depth); + } + } + void testThrow() throws Exception { + for (int d : depths) { + try { + count = getDepth(new Throwable()); + callThrow(d); + } catch(Exception e) { + e.getStackTrace(); + System.out.println(e.getMessage()); + int throwableDepth = getDepth(e); + Asserts.assertTrue(throwableDepth == d || + (d > MaxJavaStackTraceDepth && throwableDepth == MaxJavaStackTraceDepth), + "depth should return the correct value: depth tested=" + + d + " throwableDepth=" + throwableDepth); + } + } + } + } + + public static void main(String... unused) throws Exception { + Thrower t = new Thrower(); + t.testThrow(); + } +} diff --git a/hotspot/test/runtime/Unsafe/PrimitiveHostClass.java b/hotspot/test/runtime/Unsafe/PrimitiveHostClass.java new file mode 100644 index 00000000000..5405d4bce08 --- /dev/null +++ b/hotspot/test/runtime/Unsafe/PrimitiveHostClass.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Component; +import java.lang.reflect.Field; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import jdk.internal.org.objectweb.asm.*; +import sun.misc.Unsafe; + +/* + * @test PrimitiveHostClass + * @bug 8140665 + * @summary Throws IllegalArgumentException if host class is a primitive class. + * @library /testlibrary + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.misc + * @compile -XDignore.symbol.file PrimitiveHostClass.java + * @run main/othervm PrimitiveHostClass + */ + +public class PrimitiveHostClass { + + static final Unsafe U; + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + U = (Unsafe) theUnsafe.get(null); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public static void testVMAnonymousClass(Class hostClass) { + + // choose a class name in the same package as the host class + String prefix = packageName(hostClass); + if (prefix.length() > 0) + prefix = prefix.replace('.', '/') + "/"; + String className = prefix + "Anon"; + + // create the class + String superName = "java/lang/Object"; + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + className, null, superName, null); + byte[] classBytes = cw.toByteArray(); + int cpPoolSize = constantPoolSize(classBytes); + Class anonClass = + U.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]); + } + + private static String packageName(Class c) { + if (c.isArray()) { + return packageName(c.getComponentType()); + } else { + String name = c.getName(); + int dot = name.lastIndexOf('.'); + if (dot == -1) return ""; + return name.substring(0, dot); + } + } + + private static int constantPoolSize(byte[] classFile) { + return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF); + } + + public static void main(String args[]) { + testVMAnonymousClass(PrimitiveHostClass.class); + try { + testVMAnonymousClass(int.class); + throw new RuntimeException( + "Expected IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) { + // Expected + } + } +} diff --git a/hotspot/test/runtime/logging/ClassInitializationTest.java b/hotspot/test/runtime/logging/ClassInitializationTest.java index 3a5c4e3f9ba..f465ab5775d 100644 --- a/hotspot/test/runtime/logging/ClassInitializationTest.java +++ b/hotspot/test/runtime/logging/ClassInitializationTest.java @@ -62,16 +62,6 @@ public class ClassInitializationTest { out.shouldContain("[Initialized").shouldContain("without side effects]"); out.shouldHaveExitValue(0); } - // (3) Ensure that VerboseVerification still triggers appropriate messages. - pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", - "-XX:+VerboseVerification", - "-Xverify:all", - "-Xmx64m", - "BadMap50"); - out = new OutputAnalyzer(pb.start()); - out.shouldContain("End class verification for:"); - out.shouldContain("Verification for BadMap50 failed"); - out.shouldContain("Fail over class verification to old verifier for: BadMap50"); } public static class InnerClass { public static void main(String[] args) throws Exception { diff --git a/hotspot/test/runtime/logging/ClassResolutionTest.java b/hotspot/test/runtime/logging/ClassResolutionTest.java index 2a98f5ac68c..3c8d6dd7f09 100644 --- a/hotspot/test/runtime/logging/ClassResolutionTest.java +++ b/hotspot/test/runtime/logging/ClassResolutionTest.java @@ -58,13 +58,13 @@ public class ClassResolutionTest { public static void main(String... args) throws Exception { // (1) classresolve should turn on. - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=info", + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug", ClassResolutionTestMain.class.getName()); OutputAnalyzer o = new OutputAnalyzer(pb.start()); o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1"); // (2) classresolve should turn off. - pb = ProcessTools.createJavaProcessBuilder("-Xlog", + pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug", "-Xlog:classresolve=off", ClassResolutionTestMain.class.getName()); o = new OutputAnalyzer(pb.start()); @@ -77,12 +77,12 @@ public class ClassResolutionTest { o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1"); // (4) TraceClassResolution should turn off. - pb = ProcessTools.createJavaProcessBuilder("-Xlog", + pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug", "-XX:-TraceClassResolution", ClassResolutionTestMain.class.getName()); o = new OutputAnalyzer(pb.start()); o.shouldNotContain("[classresolve]"); - }; + } diff --git a/hotspot/test/runtime/logging/ExceptionsTest.java b/hotspot/test/runtime/logging/ExceptionsTest.java index 1f12e31efd4..6d2e60f2b8b 100644 --- a/hotspot/test/runtime/logging/ExceptionsTest.java +++ b/hotspot/test/runtime/logging/ExceptionsTest.java @@ -45,7 +45,7 @@ public class ExceptionsTest { static void analyzeOutputOn(ProcessBuilder pb) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain(""); + output.shouldContain(""); output.shouldContain(" thrown in interpreter method "); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/runtime/logging/LoaderConstraintsTest.java b/hotspot/test/runtime/logging/LoaderConstraintsTest.java new file mode 100644 index 00000000000..7d7fdffe87a --- /dev/null +++ b/hotspot/test/runtime/logging/LoaderConstraintsTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test LoaderConstraintsTest + * @bug 8149996 + * @library /testlibrary /runtime/testlibrary + * @library classes + * @build ClassUnloadCommon test.Empty jdk.test.lib.* jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver LoaderConstraintsTest + */ + +import jdk.test.lib.*; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LoaderConstraintsTest { + private static OutputAnalyzer out; + private static ProcessBuilder pb; + private static class ClassUnloadTestMain { + public static void main(String... args) throws Exception { + String className = "test.Empty"; + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Class c = cl.loadClass(className); + cl = null; c = null; + ClassUnloadCommon.triggerUnloading(); + } + } + + // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java + static ProcessBuilder exec(String... args) throws Exception { + List argsList = new ArrayList<>(); + Collections.addAll(argsList, args); + Collections.addAll(argsList, "-Xmn8m"); + Collections.addAll(argsList, "-Dtest.classes=" + System.getProperty("test.classes",".")); + Collections.addAll(argsList, ClassUnloadTestMain.class.getName()); + return ProcessTools.createJavaProcessBuilder(argsList.toArray(new String[argsList.size()])); + } + + public static void main(String... args) throws Exception { + + // -XX:+TraceLoaderConstraints + pb = exec("-XX:+TraceLoaderConstraints"); + out = new OutputAnalyzer(pb.start()); + out.getOutput(); + out.shouldContain("[classload,constraints] adding new constraint for name: java/lang/Class, loader[0]: jdk/internal/loader/ClassLoaders$AppClassLoader, loader[1]: "); + + // -Xlog:classload+constraints=info + pb = exec("-Xlog:classload+constraints=info"); + out = new OutputAnalyzer(pb.start()); + out.shouldContain("[classload,constraints] adding new constraint for name: java/lang/Class, loader[0]: jdk/internal/loader/ClassLoaders$AppClassLoader, loader[1]: "); + + // -XX:-TraceLoaderConstraints + pb = exec("-XX:-TraceLoaderConstraints"); + out = new OutputAnalyzer(pb.start()); + out.shouldNotContain("[classload,constraints]"); + + // -Xlog:classload+constraints=off + pb = exec("-Xlog:classload+constraints=off"); + out = new OutputAnalyzer(pb.start()); + out.shouldNotContain("[classload,constraints]"); + + } +} diff --git a/hotspot/test/runtime/logging/MonitorMismatchHelper.jasm b/hotspot/test/runtime/logging/MonitorMismatchHelper.jasm new file mode 100644 index 00000000000..405743ade38 --- /dev/null +++ b/hotspot/test/runtime/logging/MonitorMismatchHelper.jasm @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super public class MonitorMismatchHelper + version 52:0 +{ + +private Field c:I; + +public Method "":"()V" + stack 2 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + iconst_0; + putfield Field c:"I"; + return; +} + +public synchronized Method increment:"()V" + stack 3 locals 1 +{ + aload_0; + dup; + getfield Field c:"I"; + iconst_1; + iadd; + putfield Field c:"I"; + return; +} + +public synchronized Method decrement:"()V" + stack 3 locals 1 +{ + aload_0; + dup; + getfield Field c:"I"; + iconst_1; + isub; + putfield Field c:"I"; + return; +} + +public synchronized Method value:"()I" + stack 1 locals 1 +{ + aload_0; + getfield Field c:"I"; + ireturn; +} + +public static varargs Method main:"([Ljava/lang/String;)V" + stack 2 locals 4 +{ + new class MonitorMismatchHelper; + dup; + invokespecial Method "":"()V"; + astore_1; + aload_1; + dup; + astore_2; + monitorenter; + try t0; + aload_1; + invokevirtual Method increment:"()V"; + aload_1; + invokevirtual Method increment:"()V"; + aload_1; + invokevirtual Method decrement:"()V"; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload_1; + invokevirtual Method value:"()I"; + invokevirtual Method java/io/PrintStream.print:"(I)V"; + aload_2; + monitorexit; + endtry t0; + goto L44; + catch t0 #0; + catch t1 #0; + try t1; + stack_frame_type full; + locals_map class "[Ljava/lang/String;", class MonitorMismatchHelper, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + aload_2; + endtry t1; + aload_3; + athrow; + L44: stack_frame_type chop1; + return; +} + +} // end Class MonitorMismatchHelper diff --git a/hotspot/test/runtime/logging/MonitorMismatchTest.java b/hotspot/test/runtime/logging/MonitorMismatchTest.java new file mode 100644 index 00000000000..6aacb538152 --- /dev/null +++ b/hotspot/test/runtime/logging/MonitorMismatchTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test MonitorMismatchTest + * @bug 8150084 + * @library /testlibrary + * @compile MonitorMismatchHelper.jasm + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools jdk.test.lib.Platform + * @run driver MonitorMismatchTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.Platform; + +public class MonitorMismatchTest { + + public static void main(String... args) throws Exception { + if (!Platform.isEmbedded()){ + // monitormismatch should turn on. + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xcomp", + "-XX:+TieredCompilation", + "-Xlog:monitormismatch=info", + "MonitorMismatchHelper"); + OutputAnalyzer o = new OutputAnalyzer(pb.start()); + o.shouldContain("[monitormismatch] Monitor mismatch in method"); + + // monitormismatch should turn off. + pb = ProcessTools.createJavaProcessBuilder("-Xcomp", + "-XX:+TieredCompilation", + "-Xlog:monitormismatch=off", + "MonitorMismatchHelper"); + o = new OutputAnalyzer(pb.start()); + o.shouldNotContain("[monitormismatch]"); + } + }; + +} diff --git a/hotspot/test/runtime/logging/RemovedDevelopFlagsTest.java b/hotspot/test/runtime/logging/RemovedDevelopFlagsTest.java new file mode 100644 index 00000000000..a5d44d98116 --- /dev/null +++ b/hotspot/test/runtime/logging/RemovedDevelopFlagsTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test RemovedDevelopFlagsTest + * @bug 8146632 + * @library /testlibrary + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver RemovedDevelopFlagsTest + */ +import jdk.test.lib.*; + +public class RemovedDevelopFlagsTest { + public static ProcessBuilder pb; + + public static class RemovedDevelopFlagsTestMain { + public static void main(String... args) { + System.out.print("Hello!"); + } + } + + public static void exec(String flag, String value) throws Exception { + pb = ProcessTools.createJavaProcessBuilder("-XX:+"+flag, RemovedDevelopFlagsTestMain.class.getName()); + OutputAnalyzer o = new OutputAnalyzer(pb.start()); + o.shouldContain(flag+" has been removed. Please use "+value+" instead."); + o.shouldHaveExitValue(1); + } + + public static void main(String... args) throws Exception { + if (Platform.isDebugBuild()){ + exec("TraceClassInitialization", "-Xlog:classinit"); + exec("TraceClassLoaderData", "-Xlog:classloaderdata"); + exec("TraceDefaultMethods", "-Xlog:defaultmethods=debug"); + exec("TraceItables", "-Xlog:itables=debug"); + exec("TraceSafepoint", "-Xlog:safepoint=debug"); + exec("TraceStartupTime", "-Xlog:startuptime"); + exec("TraceVMOperation", "-Xlog:vmoperation=debug"); + exec("PrintVtables", "-Xlog:vtables=debug"); + exec("VerboseVerification", "-Xlog:verification"); + } + }; +} diff --git a/hotspot/test/runtime/logging/SafepointCleanupTest.java b/hotspot/test/runtime/logging/SafepointCleanupTest.java new file mode 100644 index 00000000000..efe47cb431b --- /dev/null +++ b/hotspot/test/runtime/logging/SafepointCleanupTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8149991 + * @summary safepointcleanup=info should have output from the code + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver SafepointCleanupTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class SafepointCleanupTest { + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[safepointcleanup]"); + output.shouldContain("deflating idle monitors"); + output.shouldContain("updating inline caches"); + output.shouldContain("compilation policy safepoint handler"); + output.shouldContain("mark nmethods"); + output.shouldContain("purging class loader data graph"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputOff(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[safepointcleanup]"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepointcleanup=info", + InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceSafepointCleanupTime", + InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepointcleanup=off", + InnerClass.class.getName()); + analyzeOutputOff(pb); + + pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceSafepointCleanupTime", + InnerClass.class.getName()); + analyzeOutputOff(pb); + } + + public static class InnerClass { + public static void main(String[] args) throws Exception { + System.out.println("Safepoint Cleanup test"); + } + } +} diff --git a/hotspot/test/runtime/logging/VerificationTest.java b/hotspot/test/runtime/logging/VerificationTest.java new file mode 100644 index 00000000000..d49b7b3547f --- /dev/null +++ b/hotspot/test/runtime/logging/VerificationTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8150083 + * @summary verification=info output should have output from the code + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver VerificationTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class VerificationTest { + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[verification]"); + output.shouldContain("Verifying class VerificationTest$InternalClass with new format"); + output.shouldContain("Verifying method VerificationTest$InternalClass.()V"); + output.shouldContain("End class verification for: VerificationTest$InternalClass"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputOff(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[verification]"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:verification=info", + InternalClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:verification=off", + InternalClass.class.getName()); + analyzeOutputOff(pb); + } + + public static class InternalClass { + public static void main(String[] args) throws Exception { + System.out.println("VerificationTest"); + } + } +} diff --git a/hotspot/test/serviceability/tmtools/jstack/JstackThreadTest.java b/hotspot/test/serviceability/tmtools/jstack/JstackThreadTest.java new file mode 100644 index 00000000000..b1e3ed3f2a8 --- /dev/null +++ b/hotspot/test/serviceability/tmtools/jstack/JstackThreadTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +/* + * @test JstackThreadTest + * @bug 8151442 + * @summary jstack doesn't close quotation marks properly with threads' name greater than 1996 characters + * @library /testlibrary + * @build jdk.test.lib.* + * @ignore 8153319 + * @run main JstackThreadTest + */ +public class JstackThreadTest { + static class NamedThread extends Thread { + NamedThread(String name) { + setName(name); + } + @Override + public void run() { + try { + Thread.sleep(2000); + } catch(Exception e){ + e.printStackTrace(); + } + } + } + + public static void main(String[] args) throws Exception { + StringBuilder sb = new StringBuilder(); + /*create a string more than 1996 character */ + for(int i = 0; i < 1998; i++){ + sb.append("a"); + } + testWithName(sb.toString()); + } + + private static void testWithName(String name) throws Exception { + // Start a thread with a long thread name + NamedThread thread = new NamedThread(name); + thread.start(); + ProcessBuilder processBuilder = new ProcessBuilder(); + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstack"); + launcher.addToolArg("-l"); + launcher.addToolArg(Long.toString(ProcessTools.getProcessId())); + processBuilder.command(launcher.getCommand()); + System.out.println(Arrays.toString(processBuilder.command().toArray()).replace(",", "")); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + output.shouldContain("\""+ name + "\""); + } +} diff --git a/hotspot/test/stress/gc/TestMultiThreadStressRSet.java b/hotspot/test/stress/gc/TestMultiThreadStressRSet.java new file mode 100644 index 00000000000..8947cb7237e --- /dev/null +++ b/hotspot/test/stress/gc/TestMultiThreadStressRSet.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import sun.hotspot.WhiteBox; + +/* + * @test TestMultiThreadStressRSet.java + * @key stress + * @requires vm.gc=="G1" | vm.gc=="null" + * @requires os.maxMemory > 2G + * + * @summary Stress G1 Remembered Set using multiple threads + * @library /test/lib /testlibrary + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc + * -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16 + * + * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32 + */ +public class TestMultiThreadStressRSet { + + private static final Random RND = new Random(2015 * 2016); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final int REF_SIZE = WB.getHeapOopSize(); + private static final int REGION_SIZE = WB.g1RegionSize(); + + // How many regions to use for the storage + private static final int STORAGE_REGIONS = 20; + + // Size a single obj in the storage + private static final int OBJ_SIZE = 1024; + + // How many regions of young/old gen to use in the BUFFER + private static final int BUFFER_YOUNG_REGIONS = 60; + private static final int BUFFER_OLD_REGIONS = 40; + + // Total number of objects in the storage. + private final int N; + + // The storage of byte[] + private final List STORAGE; + + // Where references to the Storage will be stored + private final List BUFFER; + + // The length of a buffer element. + // RSet deals with "cards" (areas of 512 bytes), not with single refs + // So, to affect the RSet the BUFFER refs should be allocated in different + // memory cards. + private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE); + + // Total number of objects in the young/old buffers + private final int YOUNG; + private final int OLD; + + // To cause Remembered Sets change their coarse level the test uses a window + // within STORAGE. All the BUFFER elements refer to only STORAGE objects + // from the current window. The window is defined by a range. + // The first element has got the index: 'windowStart', + // the last one: 'windowStart + windowSize - 1' + // The window is shifting periodically. + private int windowStart; + private final int windowSize; + + // Counter of created worker threads + private int counter = 0; + + private volatile String errorMessage = null; + private volatile boolean isEnough = false; + + public static void main(String args[]) { + if (args.length != 2) { + throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length); + } + long time = Long.parseLong(args[0]); + int threads = Integer.parseInt(args[1]); + new TestMultiThreadStressRSet().test(time * 1000, threads); + } + + /** + * Initiates test parameters, fills out the STORAGE and BUFFER. + */ + public TestMultiThreadStressRSet() { + + N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1; + STORAGE = new ArrayList<>(N); + int bytes = OBJ_SIZE - 20; + for (int i = 0; i < N - 1; i++) { + STORAGE.add(new byte[bytes]); + } + STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous + windowStart = 0; + windowSize = REGION_SIZE / OBJ_SIZE; + + BUFFER = new ArrayList<>(); + int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN; + OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject; + YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject; + for (int i = 0; i < OLD + YOUNG; i++) { + BUFFER.add(new Object[BUF_ARR_LEN]); + } + } + + /** + * Does the testing. Steps: + *
    + *
  • starts the Shifter thread + *
  • during the given time starts new Worker threads, keeping the number + * of live thread under limit. + *
  • stops the Shifter thread + *
+ * + * @param timeInMillis how long to stress + * @param maxThreads the maximum number of Worker thread working together. + */ + public void test(long timeInMillis, int maxThreads) { + if (timeInMillis <= 0 || maxThreads <= 0) { + throw new IllegalArgumentException("TEST BUG: be positive!"); + } + System.out.println("%% Time to work: " + timeInMillis / 1000 + "s"); + System.out.println("%% Number of threads: " + maxThreads); + long finish = System.currentTimeMillis() + timeInMillis; + Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9)); + shift.start(); + for (int i = 0; i < maxThreads; i++) { + new Worker(this, 100).start(); + } + try { + while (System.currentTimeMillis() < finish && errorMessage == null) { + Thread.sleep(100); + } + } catch (Throwable t) { + printAllStackTraces(System.err); + t.printStackTrace(System.err); + this.errorMessage = t.getMessage(); + } finally { + isEnough = true; + } + System.out.println("%% Total work cycles: " + counter); + if (errorMessage != null) { + throw new RuntimeException(errorMessage); + } + } + + /** + * Returns an element from from the BUFFER (an object array) to keep + * references to the storage. + * + * @return an Object[] from buffer. + */ + private Object[] getFromBuffer() { + int index = counter % (OLD + YOUNG); + synchronized (BUFFER) { + if (index < OLD) { + if (counter % 100 == (counter / 100) % 100) { + // need to generate garbage in the old gen to provoke mixed GC + return replaceInBuffer(index); + } else { + return BUFFER.get(index); + } + } else { + return replaceInBuffer(index); + } + } + } + + private Object[] replaceInBuffer(int index) { + Object[] objs = new Object[BUF_ARR_LEN]; + BUFFER.set(index, objs); + return objs; + } + + /** + * Returns a random object from the current window within the storage. + * A storage element with index from windowStart to windowStart+windowSize. + * + * @return a random element from the current window within the storage. + */ + private Object getRandomObject() { + int index = (windowStart + RND.nextInt(windowSize)) % N; + return STORAGE.get(index); + } + + private static void printAllStackTraces(PrintStream ps) { + Map traces = Thread.getAllStackTraces(); + for (Thread t : traces.keySet()) { + ps.println(t.toString() + " " + t.getState()); + for (StackTraceElement traceElement : traces.get(t)) { + ps.println("\tat " + traceElement); + } + } + } + + /** + * Thread to create a number of references from BUFFER to STORAGE. + */ + private static class Worker extends Thread { + + final TestMultiThreadStressRSet boss; + final int refs; // number of refs to OldGen + + /** + * @param boss the tests + * @param refsToOldGen how many references to the OldGen to create + */ + Worker(TestMultiThreadStressRSet boss, int refsToOldGen) { + this.boss = boss; + this.refs = refsToOldGen; + } + + @Override + public void run() { + try { + while (!boss.isEnough) { + Object[] objs = boss.getFromBuffer(); + int step = objs.length / refs; + for (int i = 0; i < refs; i += step) { + objs[i] = boss.getRandomObject(); + } + boss.counter++; + } + } catch (Throwable t) { + t.printStackTrace(System.out); + boss.errorMessage = t.getMessage(); + } + } + } + + /** + * Periodically shifts the current STORAGE window, removing references + * in BUFFER that refer to objects outside the window. + */ + private static class Shifter extends Thread { + + final TestMultiThreadStressRSet boss; + final int sleepTime; + final int shift; + + Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) { + this.boss = boss; + this.sleepTime = sleepTime; + this.shift = shift; + } + + @Override + public void run() { + try { + while (!boss.isEnough) { + Thread.sleep(sleepTime); + boss.windowStart += shift; + for (int i = 0; i < boss.OLD; i++) { + Object[] objs = boss.BUFFER.get(i); + for (int j = 0; j < objs.length; j++) { + objs[j] = null; + } + } + if (!WB.g1InConcurrentMark()) { + System.out.println("%% start CMC"); + WB.g1StartConcMarkCycle(); + } else { + System.out.println("%% CMC is already in progress"); + } + } + } catch (Throwable t) { + t.printStackTrace(System.out); + boss.errorMessage = t.getMessage(); + } + } + } +} + diff --git a/hotspot/test/stress/gc/TestStressIHOPMultiThread.java b/hotspot/test/stress/gc/TestStressIHOPMultiThread.java new file mode 100644 index 00000000000..b83422c0d7e --- /dev/null +++ b/hotspot/test/stress/gc/TestStressIHOPMultiThread.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test TestStressIHOPMultiThread + * @bug 8148397 + * @key stress + * @summary Stress test for IHOP + * @requires vm.gc=="G1" | vm.gc=="null" + * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1 + * -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP + * -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log + * -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80 + * -Dthreads=2 TestStressIHOPMultiThread + * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1 + * -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP + * -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log + * -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90 + * -Dthreads=3 TestStressIHOPMultiThread + * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1 + * -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP + * -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log + * -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90 + * -Dthreads=5 TestStressIHOPMultiThread + * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1 + * -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP + * -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log + * -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90 + * -Dthreads=10 TestStressIHOPMultiThread + * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1 + * -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP + * -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log + * -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90 + * -Dthreads=17 TestStressIHOPMultiThread + */ + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * Stress test for Adaptive IHOP. Starts a number of threads that fill and free + * specified amount of memory. Tests work with enabled IHOP logging. + * + */ +public class TestStressIHOPMultiThread { + + public final static List GARBAGE = new LinkedList<>(); + + private final long HEAP_SIZE; + // Amount of memory to be allocated before iterations start + private final long HEAP_PREALLOC_SIZE; + // Amount of memory to be allocated and freed during iterations + private final long HEAP_ALLOC_SIZE; + private final int CHUNK_SIZE = 100000; + + private final int TIMEOUT; + private final int THREADS; + private final int HEAP_LOW_BOUND; + private final int HEAP_HIGH_BOUND; + + private volatile boolean running = true; + private final List threads; + + public static void main(String[] args) throws InterruptedException { + new TestStressIHOPMultiThread().start(); + + } + + TestStressIHOPMultiThread() { + + TIMEOUT = Integer.getInteger("timeout") * 60; + THREADS = Integer.getInteger("threads"); + HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound"); + HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound"); + HEAP_SIZE = Runtime.getRuntime().maxMemory(); + + HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100; + HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100; + + threads = new ArrayList<>(THREADS); + } + + public void start() throws InterruptedException { + fill(); + createThreads(); + waitForStress(); + stressDone(); + waitForFinish(); + } + + /** + * Fills HEAP_PREALLOC_SIZE bytes of garbage. + */ + private void fill() { + long allocated = 0; + while (allocated < HEAP_PREALLOC_SIZE) { + GARBAGE.add(new byte[CHUNK_SIZE]); + allocated += CHUNK_SIZE; + } + } + + /** + * Creates a number of threads which will fill and free amount of memory. + */ + private void createThreads() { + for (int i = 0; i < THREADS; ++i) { + System.out.println("Create thread " + i); + AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS); + // Put reference to thread garbage into common garbage for avoiding possible optimization. + GARBAGE.add(thread.getList()); + threads.add(thread); + } + threads.forEach(t -> t.start()); + } + + /** + * Wait each thread for finishing + */ + private void waitForFinish() { + threads.forEach(thread -> { + thread.silentJoin(); + }); + } + + private boolean isRunning() { + return running; + } + + private void stressDone() { + running = false; + } + + private void waitForStress() throws InterruptedException { + Thread.sleep(TIMEOUT * 1000); + } + + private class AllocationThread extends Thread { + + private final List garbage; + + private final long amountOfGarbage; + private final int threadId; + + public AllocationThread(int id, long amount) { + super("Thread " + id); + threadId = id; + amountOfGarbage = amount; + garbage = new LinkedList<>(); + } + + /** + * Returns list of garbage. + * @return List with thread garbage. + */ + public List getList(){ + return garbage; + } + + @Override + public void run() { + System.out.println("Start the thread " + threadId); + while (TestStressIHOPMultiThread.this.isRunning()) { + allocate(amountOfGarbage); + free(); + } + } + + private void silentJoin() { + System.out.println("Join the thread " + threadId); + try { + join(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + + /** + * Allocates thread local garbage + */ + private void allocate(long amount) { + long allocated = 0; + while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) { + garbage.add(new byte[CHUNK_SIZE]); + allocated += CHUNK_SIZE; + } + } + + /** + * Frees thread local garbage + */ + private void free() { + garbage.clear(); + } + } +} diff --git a/hotspot/test/testlibrary/ClassFileInstaller.java b/hotspot/test/testlibrary/ClassFileInstaller.java index 2c1541d0457..2486bd2ef81 100644 --- a/hotspot/test/testlibrary/ClassFileInstaller.java +++ b/hotspot/test/testlibrary/ClassFileInstaller.java @@ -21,6 +21,10 @@ * questions. */ +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.ByteArrayInputStream; @@ -28,58 +32,226 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** - * Dump a class file for a class on the class path in the current directory + * Dump a class file for a class on the class path in the current directory, or + * in the specified JAR file. This class is usually used when you build a class + * from a test library, but want to use this class in a sub-process. + * + * For example, to build the following library class: + * test/lib/sun/hotspot/WhiteBox.java + * + * You would use the following tags: + * + * @library /test/lib + * @build sun.hotspot.WhiteBox + * + * JTREG would build the class file under + * ${JTWork}/classes/test/lib/sun/hotspot/WhiteBox.class + * + * With you run your main test class using "@run main MyMainClass", JTREG would setup the + * -classpath to include "${JTWork}/classes/test/lib/", so MyMainClass would be able to + * load the WhiteBox class. + * + * However, if you run a sub process, and do not wish to use the exact same -classpath, + * You can use ClassFileInstaller to ensure that WhiteBox is available in the current + * directory of your test: + * + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * + * Or, you can use the -jar option to store the class in the specified JAR file. If a relative + * path name is given, the JAR file would be relative to the current directory of + * + * @run main ClassFileInstaller -jar myjar.jar sun.hotspot.WhiteBox */ public class ClassFileInstaller { + /** + * You can enable debug tracing of ClassFileInstaller by running JTREG with + * jtreg -DClassFileInstaller.debug=true ... + */ + public static boolean DEBUG = Boolean.getBoolean("ClassFileInstaller.debug"); + /** * @param args The names of the classes to dump * @throws Exception */ public static void main(String... args) throws Exception { - for (String arg : args) { - writeClassToDisk(arg); + if (args.length > 1 && args[0].equals("-jar")) { + if (args.length < 2) { + throw new RuntimeException("Usage: ClassFileInstaller \n" + + "where possible options include:\n" + + " -jar Write to the JAR file "); + } + writeJar(args[1], null, args, 2, args.length); + } else { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing to " + System.getProperty("user.dir")); + } + for (String arg : args) { + writeClassToDisk(arg); + } } } + public static class Manifest { + private InputStream in; + + private Manifest(InputStream in) { + this.in = in; + } + + static Manifest fromSourceFile(String fileName) throws Exception { + String pathName = System.getProperty("test.src") + File.separator + fileName; + return new Manifest(new FileInputStream(pathName)); + } + + // Example: + // String manifest = "Premain-Class: RedefineClassHelper\n" + + // "Can-Redefine-Classes: true\n"; + // ClassFileInstaller.writeJar("redefineagent.jar", + // ClassFileInstaller.Manifest.fromString(manifest), + // "RedefineClassHelper"); + static Manifest fromString(String manifest) throws Exception { + return new Manifest(new ByteArrayInputStream(manifest.getBytes())); + } + + public InputStream getInputStream() { + return in; + } + } + + private static void writeJar(String jarFile, Manifest manifest, String classes[], int from, int to) throws Exception { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing to " + getJarPath(jarFile)); + } + + (new File(jarFile)).delete(); + FileOutputStream fos = new FileOutputStream(jarFile); + ZipOutputStream zos = new ZipOutputStream(fos); + + // The manifest must be the first or second entry. See comments in JarInputStream + // constructor and JDK-5046178. + if (manifest != null) { + writeToDisk(zos, "META-INF/MANIFEST.MF", manifest.getInputStream()); + } + + for (int i=from; i 0) { pathName = prependPath + "/" + pathName; } - writeToDisk(pathName, is); + writeToDisk(zos, pathName, is); } public static void writeClassToDisk(String className, byte[] bytecode) throws Exception { - writeClassToDisk(className, bytecode, ""); + writeClassToDisk(null, className, bytecode); + } + private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode) throws Exception { + writeClassToDisk(zos, className, bytecode, ""); } public static void writeClassToDisk(String className, byte[] bytecode, String prependPath) throws Exception { + writeClassToDisk(null, className, bytecode, prependPath); + } + private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode, String prependPath) throws Exception { // Convert dotted class name to a path to a class file String pathName = className.replace('.', '/').concat(".class"); if (prependPath.length() > 0) { pathName = prependPath + "/" + pathName; } - writeToDisk(pathName, new ByteArrayInputStream(bytecode)); + writeToDisk(zos, pathName, new ByteArrayInputStream(bytecode)); } - - private static void writeToDisk(String pathName, InputStream is) throws Exception { - // Create the class file's package directory - Path p = Paths.get(pathName); - if (pathName.contains("/")) { - Files.createDirectories(p.getParent()); + private static void writeToDisk(ZipOutputStream zos, String pathName, InputStream is) throws Exception { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing " + pathName); } - // Create the class file - Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + if (zos != null) { + ZipEntry ze = new ZipEntry(pathName); + zos.putNextEntry(ze); + byte[] buf = new byte[1024]; + int len; + while ((len = is.read(buf))>0){ + zos.write(buf, 0, len); + } + } else { + // Create the class file's package directory + Path p = Paths.get(pathName); + if (pathName.contains("/")) { + Files.createDirectories(p.getParent()); + } + // Create the class file + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + } + is.close(); } } diff --git a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/visitors/JavaCodeVisitor.java b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/visitors/JavaCodeVisitor.java index 037d4ab2f9b..97a045cccfc 100644 --- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/visitors/JavaCodeVisitor.java +++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/visitors/JavaCodeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,21 +164,15 @@ public class JavaCodeVisitor implements Visitor { code.append(node.getChildren().stream() .map(p -> p.accept(this)) .collect(Collectors.joining("][", "[", "]"))); - code.append(";\n") - .append(PrintingUtils.align(node.getParent().getLevel())) + code.append(";\n"); + if (!TypeList.isBuiltIn(arrayType)) { + code.append(PrintingUtils.align(node.getParent().getLevel())) .append("java.util.Arrays.fill(") .append(name) - .append(", "); - if (TypeList.find("boolean") == arrayType) { - code.append("false"); - } else if (TypeList.isBuiltIn(arrayType)) { - code.append("0"); - } else { - code.append("new ") + .append(", new ") .append(type) - .append("()"); + .append("());\n"); } - code.append(");\n"); return code.toString(); } diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 5209134ad7c..99d74713f24 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -356,3 +356,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 27a3d65e1580386d060e0aa3a68ab52c1a9ab568 jdk-9+111 36326537f929d20cc5885b93939f90c0efcc4681 jdk-9+112 28626780e245fccbfb9bad8e3b05f62357958038 jdk-9+113 +147114dd0641cd7c9fe6e81642eb993a7b9c6f0b jdk-9+114 diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java index 3aa6fc4c6ca..131d87e354f 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java @@ -52,8 +52,8 @@ final class CatalogResolverImpl implements CatalogResolver { @Override public InputSource resolveEntity(String publicId, String systemId) { //Normalize publicId and systemId - systemId = Normalizer.normalizeURI(systemId); - publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(publicId)); + systemId = Normalizer.normalizeURI(Util.getNotNullOrEmpty(systemId)); + publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(Util.getNotNullOrEmpty(publicId))); //check whether systemId is an urn if (systemId != null && systemId.startsWith("urn:publicid:")) { @@ -87,7 +87,17 @@ final class CatalogResolverImpl implements CatalogResolver { } /** - * Resolves the publicId or systemId to one specified in the catalog. + * Resolves the publicId or systemId using public or system entries in the catalog. + * + * The resolution follows the following rules determined by the prefer setting: + * + * prefer "system": attempts to resolve with a system entry; + * attempts to resolve with a public entry when only + * publicId is specified. + * + * prefer "public": attempts to resolve with a system entry; + * attempts to resolve with a public entry if no matching + * system entry is found. * @param catalog the catalog * @param publicId the publicId * @param systemId the systemId @@ -99,9 +109,14 @@ final class CatalogResolverImpl implements CatalogResolver { //search the current catalog catalog.reset(); if (systemId != null) { + /* + If a system identifier is specified, it is used no matter how + prefer is set. + */ resolvedSystemId = catalog.matchSystem(systemId); } - if (resolvedSystemId == null) { + + if (resolvedSystemId == null && publicId != null) { resolvedSystemId = catalog.matchPublic(publicId); } diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java index a4cdb4eace6..e7cb9bcf1a7 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java @@ -60,6 +60,9 @@ final class CatalogUriResolverImpl implements CatalogUriResolver { @Override public Source resolve(String href, String base) { + href = Util.getNotNullOrEmpty(href); + base = Util.getNotNullOrEmpty(base); + if (href == null) return null; CatalogImpl c = (CatalogImpl)catalog; diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java index 38f36e64d81..0ebf25e4207 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java @@ -82,6 +82,9 @@ class GroupEntry extends BaseEntry { //The length of the longest match of a suffix type int longestSuffixMatch = 0; + //Indicate whether a system entry has been searched + boolean systemEntrySearched = false; + /** * PreferType represents possible values of the prefer property */ @@ -156,6 +159,7 @@ class GroupEntry extends BaseEntry { longestRewriteMatch = 0; suffixMatch = null; longestSuffixMatch = 0; + systemEntrySearched = false; } /** * Constructs a group entry. @@ -212,6 +216,7 @@ class GroupEntry extends BaseEntry { * @return An URI string if a mapping is found, or null otherwise. */ public String matchSystem(String systemId) { + systemEntrySearched = true; String match = null; for (BaseEntry entry : entries) { switch (entry.type) { @@ -244,8 +249,10 @@ class GroupEntry extends BaseEntry { //use it if there is a match of the system type return match; } else if (grpEntry.longestRewriteMatch > longestRewriteMatch) { + longestRewriteMatch = grpEntry.longestRewriteMatch; rewriteMatch = match; } else if (grpEntry.longestSuffixMatch > longestSuffixMatch) { + longestSuffixMatch = grpEntry.longestSuffixMatch; suffixMatch = match; } break; @@ -277,11 +284,13 @@ class GroupEntry extends BaseEntry { * @return An URI string if a mapping is found, or null otherwise. */ public String matchPublic(String publicId) { - //as the specification required - if (!isPreferPublic) { + /* + When both public and system identifiers are specified, and prefer is + not public (that is, system), only system entry will be used. + */ + if (!isPreferPublic && systemEntrySearched) { return null; } - //match public entries String match = null; for (BaseEntry entry : entries) { diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java index bb9d2474fda..f0fd1fdbf33 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java @@ -122,4 +122,25 @@ class Util { } return null; } + + /** + * Checks whether the specified string is null or empty, returns the original + * string with leading and trailing spaces removed if not. + * @param test the string to be tested + * @return the original string with leading and trailing spaces removed, + * or null if it is null or empty + * + */ + static String getNotNullOrEmpty(String test) { + if (test == null) { + return test; + } else { + String temp = test.trim(); + if (temp.length() == 0) { + return null; + } else { + return temp; + } + } + } } diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java index 450521b032b..7edd6af3503 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java @@ -38,15 +38,71 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.Attributes; import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.ext.DefaultHandler2; /* - * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969 + * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969, 8151162, 8152527 * @summary Tests basic Catalog functions. */ public class CatalogTest { + /* + * @bug 8152527 + * This test is the same as the JDK test ResolveEntityTests:testMatch1. + * Verifies that the CatalogResolver resolves a publicId and/or systemId as + * expected. + */ + @Test(dataProvider = "resolveEntity") + public void testMatch1(String cfile, String prefer, String sysId, String pubId, String expectedUri, String expectedFile, String msg) { + String catalogFile = getClass().getResource(cfile).getFile(); + CatalogFeatures features = CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, prefer).build(); + CatalogResolver catalogResolver = CatalogManager.catalogResolver(features, catalogFile); + InputSource is = catalogResolver.resolveEntity(pubId, sysId); + Assert.assertNotNull(is, msg); + String expected = (expectedUri == null) ? expectedFile : expectedUri; + Assert.assertEquals(expected, is.getSystemId(), msg); + } + + /* + * @bug 8151162 + * Verifies that the Catalog matches specified publicId or systemId and returns + * results as expected. + */ + @Test(dataProvider = "matchWithPrefer") + public void matchWithPrefer(String prefer, String cfile, String publicId, String systemId, String expected) { + String catalogFile = getClass().getResource(cfile).getFile(); + Catalog c = CatalogManager.catalog(CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, prefer).build(), catalogFile); + String result; + if (publicId != null && publicId.length() > 0) { + result = c.matchPublic(publicId); + } else { + result = c.matchSystem(systemId); + } + Assert.assertEquals(expected, result); + } + + /* + * @bug 8151162 + * Verifies that the CatalogResolver resolves specified publicId or systemId + * in accordance with the prefer setting. + * prefer "system": resolves with a system entry. + * Exception: use the public entry when the catalog contains + * only public entry and only publicId is specified. + * prefer "public": attempts to resolve with a system entry; + * attempts to resolve with a public entry if no matching + * system entry is found. + */ + @Test(dataProvider = "resolveWithPrefer") + public void resolveWithPrefer(String prefer, String cfile, String publicId, String systemId, String expected) { + String catalogFile = getClass().getResource(cfile).getFile(); + CatalogFeatures f = CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, prefer).with(CatalogFeatures.Feature.RESOLVE, "ignore").build(); + CatalogResolver catalogResolver = CatalogManager.catalogResolver(f, catalogFile); + String result = catalogResolver.resolveEntity(publicId, systemId).getSystemId(); + Assert.assertEquals(expected, result); + } + /** * @bug 8150969 * Verifies that the defer attribute set in the catalog file takes precedence @@ -232,6 +288,72 @@ public class CatalogTest { } } + /* + DataProvider: used to verify CatalogResolver's resolveEntity function. + Data columns: + catalog, prefer, systemId, publicId, expectedUri, expectedFile, msg + */ + @DataProvider(name = "resolveEntity") + Object[][] getDataForMatchingBothIds() { + String expected = "http://www.groupxmlbase.com/dtds/rewrite.dtd"; + return new Object[][]{ + {"rewriteSystem_id.xml", "system", "http://www.sys00test.com/rewrite.dtd", "PUB-404", expected, expected, "Relative rewriteSystem with xml:base at group level failed"}, + }; + } + static String id = "http://openjdk.java.net/xml/catalog/dtd/system.dtd"; + /* + DataProvider: used to verify how prefer settings affect the result of the + Catalog's matching operation. + Data columns: + prefer, catalog, publicId, systemId, expected result + */ + @DataProvider(name = "matchWithPrefer") + Object[][] getDataForMatch() { + return new Object[][]{ + {"public", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"public", "sysOnly.xml", id, "", null}, + {"public", "sysAndPub.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"system", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"system", "sysOnly.xml", id, "", null}, + {"system", "sysAndPub.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"public", "pubOnly.xml", "", id, null}, + {"public", "sysOnly.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"public", "sysAndPub.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"system", "pubOnly.xml", "", id, null}, + {"system", "sysOnly.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"system", "sysAndPub.xml", "", id, "http://local/base/dtd/system.dtd"}, + }; + } + + /* + DataProvider: used to verify how prefer settings affect the result of the + CatalogResolver's resolution operation. + Data columns: + prefer, catalog, publicId, systemId, expected result + */ + @DataProvider(name = "resolveWithPrefer") + Object[][] getDataForResolve() { + return new Object[][]{ + {"system", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"system", "pubOnly.xml", "", id, null}, + {"system", "pubOnly.xml", id, id, null}, + {"public", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"public", "pubOnly.xml", "", id, null}, + {"public", "pubOnly.xml", id, id, "http://local/base/dtd/public.dtd"}, + {"system", "sysOnly.xml", id, "", null}, + {"system", "sysOnly.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"system", "sysOnly.xml", id, id, "http://local/base/dtd/system.dtd"}, + {"public", "sysOnly.xml", id, "", null}, + {"public", "sysOnly.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"public", "sysOnly.xml", id, id, "http://local/base/dtd/system.dtd"}, + {"system", "sysAndPub.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"system", "sysAndPub.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"system", "sysAndPub.xml", id, id, "http://local/base/dtd/system.dtd"}, + {"public", "sysAndPub.xml", id, "", "http://local/base/dtd/public.dtd"}, + {"public", "sysAndPub.xml", "", id, "http://local/base/dtd/system.dtd"}, + {"public", "sysAndPub.xml", id, id, "http://local/base/dtd/system.dtd"}, + }; + } /* DataProvider: catalogs that contain invalid next or delegate catalogs. The defer attribute is set to false. diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/pubOnly.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/pubOnly.xml new file mode 100644 index 00000000000..3ff20afff2b --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/pubOnly.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteSystem_id.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteSystem_id.xml new file mode 100644 index 00000000000..391950fcbfd --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteSystem_id.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/sysAndPub.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/sysAndPub.xml new file mode 100644 index 00000000000..fd896c654b0 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/sysAndPub.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/sysOnly.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/sysOnly.xml new file mode 100644 index 00000000000..8c6206bae78 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/sysOnly.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 40439011339..c0e2ef494a3 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -359,3 +359,4 @@ fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107 4d5296e0920afe7ef8d4db1939b76f0d407a3812 jdk-9+111 21274e7937bae291658d68143aca0e3ee9296db0 jdk-9+112 e980062475c10d21137051045bf95ee229db9b27 jdk-9+113 +b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114 diff --git a/jdk/.hgtags b/jdk/.hgtags index e9974a728e5..74ad9bf9055 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -357,3 +357,4 @@ b2a69d66dc65ad1d3aeb3bd362cf5bb0deba040e jdk-9+111 1565a0efe6f0ca411a6df277df1e069431c60988 jdk-9+112 68f8be44b6a6b33dfa841ec671c0ba6e4056b372 jdk-9+113 bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114 +35225b837d66582037eeadeb471c13235dfd793d jdk-9+115 diff --git a/jdk/make/data/fontconfig/windows.fontconfig.properties b/jdk/make/data/fontconfig/windows.fontconfig.properties index 9d3fa4a8315..fcfcb8f5190 100644 --- a/jdk/make/data/fontconfig/windows.fontconfig.properties +++ b/jdk/make/data/fontconfig/windows.fontconfig.properties @@ -37,6 +37,7 @@ allfonts.chinese-gb18030-extb=SimSun-ExtB allfonts.chinese-hkscs=MingLiU_HKSCS allfonts.chinese-ms950-extb=MingLiU-ExtB allfonts.devanagari=Mangal +allfonts.kannada=Tunga allfonts.dingbats=Wingdings allfonts.lucida=Lucida Sans Regular allfonts.symbol=Symbol @@ -239,11 +240,11 @@ sequence.allfonts.x-windows-874=alphabetic,thai,dingbats,symbol sequence.fallback=lucida,symbols,\ chinese-ms950,chinese-hkscs,chinese-ms936,chinese-gb18030,\ - japanese,korean,chinese-ms950-extb,chinese-ms936-extb,georgian + japanese,korean,chinese-ms950-extb,chinese-ms936-extb,georgian,kannada # Exclusion Ranges -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff +exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-20b8,20bb-20bc,20be-f8ff exclusion.chinese-gb18030=0390-03d6,2200-22ef,2701-27be exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac @@ -295,6 +296,7 @@ filename.GulimChe=gulim.TTC filename.Lucida_Sans_Regular=LucidaSansRegular.ttf filename.Mangal=MANGAL.TTF +filename.Tunga=TUNGA.TTF filename.Symbol=SYMBOL.TTF filename.Wingdings=WINGDING.TTF diff --git a/jdk/make/launcher/Launcher-jdk.rmic.gmk b/jdk/make/launcher/Launcher-jdk.rmic.gmk index b0a8b6dc81a..d60c3d9b60b 100644 --- a/jdk/make/launcher/Launcher-jdk.rmic.gmk +++ b/jdk/make/launcher/Launcher-jdk.rmic.gmk @@ -26,6 +26,6 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, rmic, \ - MAIN_CLASS := jdk.rmi.rmic.Main, \ + MAIN_CLASS := sun.rmi.rmic.Main, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ )) diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 24db66e8e29..118b0fd3ddf 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -236,32 +236,32 @@ SUNWprivate_1.1 { Java_jdk_internal_misc_Signal_findSignal0; Java_jdk_internal_misc_Signal_handle0; Java_jdk_internal_misc_Signal_raise0; - Java_sun_reflect_ConstantPool_getClassAt0; - Java_sun_reflect_ConstantPool_getClassAtIfLoaded0; - Java_sun_reflect_ConstantPool_getClassRefIndexAt0; - Java_sun_reflect_ConstantPool_getDoubleAt0; - Java_sun_reflect_ConstantPool_getFieldAt0; - Java_sun_reflect_ConstantPool_getFieldAtIfLoaded0; - Java_sun_reflect_ConstantPool_getFloatAt0; - Java_sun_reflect_ConstantPool_getIntAt0; - Java_sun_reflect_ConstantPool_getLongAt0; - Java_sun_reflect_ConstantPool_getMemberRefInfoAt0; - Java_sun_reflect_ConstantPool_getMethodAt0; - Java_sun_reflect_ConstantPool_getMethodAtIfLoaded0; - Java_sun_reflect_ConstantPool_getNameAndTypeRefIndexAt0; - Java_sun_reflect_ConstantPool_getNameAndTypeRefInfoAt0; - Java_sun_reflect_ConstantPool_getSize0; - Java_sun_reflect_ConstantPool_getStringAt0; - Java_sun_reflect_ConstantPool_getTagAt0; - Java_sun_reflect_ConstantPool_getUTF8At0; + Java_jdk_internal_reflect_ConstantPool_getClassAt0; + Java_jdk_internal_reflect_ConstantPool_getClassAtIfLoaded0; + Java_jdk_internal_reflect_ConstantPool_getClassRefIndexAt0; + Java_jdk_internal_reflect_ConstantPool_getDoubleAt0; + Java_jdk_internal_reflect_ConstantPool_getFieldAt0; + Java_jdk_internal_reflect_ConstantPool_getFieldAtIfLoaded0; + Java_jdk_internal_reflect_ConstantPool_getFloatAt0; + Java_jdk_internal_reflect_ConstantPool_getIntAt0; + Java_jdk_internal_reflect_ConstantPool_getLongAt0; + Java_jdk_internal_reflect_ConstantPool_getMemberRefInfoAt0; + Java_jdk_internal_reflect_ConstantPool_getMethodAt0; + Java_jdk_internal_reflect_ConstantPool_getMethodAtIfLoaded0; + Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefIndexAt0; + Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefInfoAt0; + Java_jdk_internal_reflect_ConstantPool_getSize0; + Java_jdk_internal_reflect_ConstantPool_getStringAt0; + Java_jdk_internal_reflect_ConstantPool_getTagAt0; + Java_jdk_internal_reflect_ConstantPool_getUTF8At0; Java_java_io_Console_istty; Java_java_io_Console_encoding; Java_java_io_Console_echo; - Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0; - Java_sun_reflect_NativeMethodAccessorImpl_invoke0; - Java_sun_reflect_Reflection_getCallerClass__; - Java_sun_reflect_Reflection_getCallerClass__I; - Java_sun_reflect_Reflection_getClassAccessFlags; + Java_jdk_internal_reflect_NativeConstructorAccessorImpl_newInstance0; + Java_jdk_internal_reflect_NativeMethodAccessorImpl_invoke0; + Java_jdk_internal_reflect_Reflection_getCallerClass__; + Java_jdk_internal_reflect_Reflection_getCallerClass__I; + Java_jdk_internal_reflect_Reflection_getClassAccessFlags; Java_jdk_internal_misc_VM_latestUserDefinedLoader; Java_jdk_internal_misc_VM_getuid; Java_jdk_internal_misc_VM_geteuid; diff --git a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java index f6abaf69d7e..8a2307d2ff6 100644 --- a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java +++ b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java @@ -102,8 +102,8 @@ public class LinuxFileSystemProvider extends UnixFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + String userHome = GetPropertyAction.getProperty("user.home"); + Path userMimeTypes = Paths.get(userHome, ".mime.types"); Path etcMimeTypes = Paths.get("/etc/mime.types"); return chain(new GioFileTypeDetector(), diff --git a/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java b/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java index 2aa3fbcbaa2..7598cf9e37f 100644 --- a/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java +++ b/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java @@ -32,9 +32,9 @@ package sun.nio.ch; import java.io.IOException; -import java.io.FileDescriptor; import java.util.Iterator; import java.util.LinkedList; +import sun.security.action.GetPropertyAction; /* * struct kevent { // 32-bit 64-bit @@ -84,10 +84,8 @@ class KQueueArrayWrapper { static { IOUtil.load(); initStructSizes(); - String datamodel = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.arch.data.model") - ); - is64bit = datamodel.equals("64"); + String datamodel = GetPropertyAction.getProperty("sun.arch.data.model"); + is64bit = "64".equals(datamodel); } KQueueArrayWrapper() { diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java index 0dcee95bfc3..6b9a56a9fa7 100644 --- a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java +++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java @@ -28,7 +28,6 @@ package sun.nio.fs; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.spi.FileTypeDetector; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -47,8 +46,8 @@ public class MacOSXFileSystemProvider extends BsdFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + Path userMimeTypes = Paths.get( + GetPropertyAction.getProperty("user.home"), ".mime.types"); return chain(new MimeTypesFileTypeDetector(userMimeTypes), new UTIFileTypeDetector()); diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index 06a685b2482..2322741110a 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -71,6 +71,17 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { initialize(2048, null); } + private static void checkKeySize(int keysize) + throws InvalidParameterException { + + if ((keysize < 512) || (keysize > 8192) || ((keysize & 0x3F) != 0)) { + throw new InvalidParameterException( + "DH key size must be multiple of 64, and can only range " + + "from 512 to 8192 (inclusive). " + + "The specific key size " + keysize + " is not supported"); + } + } + /** * Initializes this key pair generator for a certain keysize and source of * randomness. @@ -80,16 +91,22 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { * @param random the source of randomness */ public void initialize(int keysize, SecureRandom random) { - if ((keysize < 512) || (keysize > 2048) || (keysize % 64 != 0)) { - throw new InvalidParameterException("Keysize must be multiple " - + "of 64, and can only range " - + "from 512 to 2048 " - + "(inclusive)"); + checkKeySize(keysize); + + // Use the built-in parameters (ranging from 512 to 8192) + // when available. + this.params = ParameterCache.getCachedDHParameterSpec(keysize); + + // Due to performance issue, only support DH parameters generation + // up to 1024 bits. + if ((this.params == null) && (keysize > 1024)) { + throw new InvalidParameterException( + "Unsupported " + keysize + "-bit DH parameter generation"); } + this.pSize = keysize; this.lSize = 0; this.random = random; - this.params = null; } /** @@ -115,11 +132,10 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { params = (DHParameterSpec)algParams; pSize = params.getP().bitLength(); - if ((pSize < 512) || (pSize > 2048) || - (pSize % 64 != 0)) { - throw new InvalidAlgorithmParameterException - ("Prime size must be multiple of 64, and can only range " - + "from 512 to 2048 (inclusive)"); + try { + checkKeySize(pSize); + } catch (InvalidParameterException ipe) { + throw new InvalidAlgorithmParameterException(ipe.getMessage()); } // exponent size is optional, could be 0 @@ -164,7 +180,7 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { } BigInteger x; - BigInteger pMinus2 = p.subtract(BigInteger.valueOf(2)); + BigInteger pMinus2 = p.subtract(BigInteger.TWO); // // PKCS#3 section 7.1 "Private-value generation" diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java index 86c4cd900bb..f8001b5ab20 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java @@ -25,6 +25,7 @@ package com.sun.crypto.provider; +import java.math.BigInteger; import java.security.*; import java.security.spec.*; import javax.crypto.spec.DHParameterSpec; @@ -46,8 +47,7 @@ import javax.crypto.spec.DHGenParameterSpec; * @see java.security.spec.AlgorithmParameterSpec * @see DHParameters */ -public final class DHParameterGenerator -extends AlgorithmParameterGeneratorSpi { +public final class DHParameterGenerator extends AlgorithmParameterGeneratorSpi { // The size in bits of the prime modulus private int primeSize = 2048; @@ -59,12 +59,16 @@ extends AlgorithmParameterGeneratorSpi { private SecureRandom random = null; private static void checkKeySize(int keysize) - throws InvalidAlgorithmParameterException { - if ((keysize != 2048) && - ((keysize < 512) || (keysize > 1024) || (keysize % 64 != 0))) { - throw new InvalidAlgorithmParameterException( - "Keysize must be multiple of 64 ranging from " - + "512 to 1024 (inclusive), or 2048"); + throws InvalidParameterException { + + boolean supported = ((keysize == 2048) || (keysize == 3072) || + ((keysize >= 512) && (keysize <= 1024) && ((keysize & 0x3F) == 0))); + + if (!supported) { + throw new InvalidParameterException( + "DH key size must be multiple of 64 and range " + + "from 512 to 1024 (inclusive), or 2048, 3072. " + + "The specific key size " + keysize + " is not supported"); } } @@ -76,13 +80,9 @@ extends AlgorithmParameterGeneratorSpi { * @param keysize the keysize (size of prime modulus) in bits * @param random the source of randomness */ + @Override protected void engineInit(int keysize, SecureRandom random) { - // Re-uses DSA parameters and thus have the same range - try { - checkKeySize(keysize); - } catch (InvalidAlgorithmParameterException ex) { - throw new InvalidParameterException(ex.getMessage()); - } + checkKeySize(keysize); this.primeSize = keysize; this.random = random; } @@ -98,32 +98,31 @@ extends AlgorithmParameterGeneratorSpi { * @exception InvalidAlgorithmParameterException if the given parameter * generation values are inappropriate for this parameter generator */ + @Override protected void engineInit(AlgorithmParameterSpec genParamSpec, - SecureRandom random) - throws InvalidAlgorithmParameterException { + SecureRandom random) throws InvalidAlgorithmParameterException { + if (!(genParamSpec instanceof DHGenParameterSpec)) { throw new InvalidAlgorithmParameterException ("Inappropriate parameter type"); } DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec; - primeSize = dhParamSpec.getPrimeSize(); - - // Re-uses DSA parameters and thus have the same range - checkKeySize(primeSize); - exponentSize = dhParamSpec.getExponentSize(); - if (exponentSize <= 0) { - throw new InvalidAlgorithmParameterException - ("Exponent size must be greater than zero"); + if ((exponentSize <= 0) || (exponentSize >= primeSize)) { + throw new InvalidAlgorithmParameterException( + "Exponent size (" + exponentSize + + ") must be positive and less than modulus size (" + + primeSize + ")"); + } + try { + checkKeySize(primeSize); + } catch (InvalidParameterException ipe) { + throw new InvalidAlgorithmParameterException(ipe.getMessage()); } - // Require exponentSize < primeSize - if (exponentSize >= primeSize) { - throw new InvalidAlgorithmParameterException - ("Exponent size must be less than modulus size"); - } + this.random = random; } /** @@ -131,24 +130,22 @@ extends AlgorithmParameterGeneratorSpi { * * @return the new AlgorithmParameters object */ + @Override protected AlgorithmParameters engineGenerateParameters() { - AlgorithmParameters algParams = null; - if (this.exponentSize == 0) { - this.exponentSize = this.primeSize - 1; + if (random == null) { + random = SunJCE.getRandom(); } - if (this.random == null) - this.random = SunJCE.getRandom(); - + BigInteger paramP = null; + BigInteger paramG = null; try { - AlgorithmParameterGenerator paramGen; - DSAParameterSpec dsaParamSpec; - - paramGen = AlgorithmParameterGenerator.getInstance("DSA"); - paramGen.init(this.primeSize, random); - algParams = paramGen.generateParameters(); - dsaParamSpec = algParams.getParameterSpec(DSAParameterSpec.class); + AlgorithmParameterGenerator dsaParamGen = + AlgorithmParameterGenerator.getInstance("DSA"); + dsaParamGen.init(primeSize, random); + AlgorithmParameters dsaParams = dsaParamGen.generateParameters(); + DSAParameterSpec dsaParamSpec = + dsaParams.getParameterSpec(DSAParameterSpec.class); DHParameterSpec dhParamSpec; if (this.exponentSize > 0) { @@ -159,16 +156,13 @@ extends AlgorithmParameterGeneratorSpi { dhParamSpec = new DHParameterSpec(dsaParamSpec.getP(), dsaParamSpec.getG()); } - algParams = AlgorithmParameters.getInstance("DH", - SunJCE.getInstance()); + AlgorithmParameters algParams = + AlgorithmParameters.getInstance("DH", SunJCE.getInstance()); algParams.init(dhParamSpec); - } catch (InvalidParameterSpecException e) { - // this should never happen - throw new RuntimeException(e.getMessage()); - } catch (NoSuchAlgorithmException e) { - // this should never happen, because we provide it - throw new RuntimeException(e.getMessage()); + + return algParams; + } catch (Exception ex) { + throw new ProviderException("Unexpected exception", ex); } - return algParams; } } diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 9f8f54a1823..87fa4a383f3 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -512,11 +512,17 @@ final class GaloisCounterMode extends FeedbackCipher { byte[] sOut = new byte[s.length]; GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock); gctrForSToTag.doFinal(s, 0, s.length, sOut, 0); + + // check entire authentication tag for time-consistency + int mismatch = 0; for (int i = 0; i < tagLenBytes; i++) { - if (tag[i] != sOut[i]) { - throw new AEADBadTagException("Tag mismatch!"); - } + mismatch |= tag[i] ^ sOut[i]; } + + if (mismatch != 0) { + throw new AEADBadTagException("Tag mismatch!"); + } + return len; } diff --git a/jdk/src/java.base/share/classes/java/io/DataInput.java b/jdk/src/java.base/share/classes/java/io/DataInput.java index dca9187d4a7..60e03c2173c 100644 --- a/jdk/src/java.base/share/classes/java/io/DataInput.java +++ b/jdk/src/java.base/share/classes/java/io/DataInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -182,10 +182,11 @@ interface DataInput { * not all bytes of {@code b} have been * updated with data from the input stream. * - * @param b the buffer into which the data is read. - * @exception EOFException if this stream reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this stream reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ void readFully(byte b[]) throws IOException; @@ -226,12 +227,16 @@ interface DataInput { * and so on. The number of bytes read is, * at most, equal to {@code len}. * - * @param b the buffer into which the data is read. - * @param off an int specifying the offset into the data. - * @param len an int specifying the number of bytes to read. - * @exception EOFException if this stream reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @param off an int specifying the offset in the data array {@code b}. + * @param len an int specifying the number of bytes to read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. + * @throws EOFException if this stream reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ void readFully(byte b[], int off, int len) throws IOException; diff --git a/jdk/src/java.base/share/classes/java/io/DataInputStream.java b/jdk/src/java.base/share/classes/java/io/DataInputStream.java index 6ce6b233ee6..f92c4f91b0c 100644 --- a/jdk/src/java.base/share/classes/java/io/DataInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/DataInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,38 +150,43 @@ class DataInputStream extends FilterInputStream implements DataInput { } /** - * See the general contract of the readFully - * method of DataInput. + * See the general contract of the {@code readFully} + * method of {@code DataInput}. *

* Bytes * for this operation are read from the contained * input stream. * - * @param b the buffer into which the data is read. - * @exception EOFException if this input stream reaches the end before - * reading all the bytes. - * @exception IOException the stream has been closed and the contained - * input stream does not support reading after close, or - * another I/O error occurs. - * @see java.io.FilterInputStream#in + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this input stream reaches the end before + * reading all the bytes. + * @throws IOException the stream has been closed and the contained + * input stream does not support reading after close, or + * another I/O error occurs. + * @see java.io.FilterInputStream#in */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } /** - * See the general contract of the readFully - * method of DataInput. + * See the general contract of the {@code readFully} + * method of {@code DataInput}. *

* Bytes * for this operation are read from the contained * input stream. * * @param b the buffer into which the data is read. - * @param off the start offset of the data. + * @param off the start offset in the data array {@code b}. * @param len the number of bytes to read. + * @exception NullPointerException if {@code b} is {@code null}. + * @exception IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. * @exception EOFException if this input stream reaches the end before - * reading all the bytes. + * reading all the bytes. * @exception IOException the stream has been closed and the contained * input stream does not support reading after close, or * another I/O error occurs. diff --git a/jdk/src/java.base/share/classes/java/io/File.java b/jdk/src/java.base/share/classes/java/io/File.java index 089171bab9e..7f23340920b 100644 --- a/jdk/src/java.base/share/classes/java/io/File.java +++ b/jdk/src/java.base/share/classes/java/io/File.java @@ -31,7 +31,6 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.List; import java.util.ArrayList; -import java.security.AccessController; import java.security.SecureRandom; import java.nio.file.Path; import java.nio.file.FileSystems; @@ -1896,8 +1895,8 @@ public class File private TempDirectory() { } // temporary directory location - private static final File tmpdir = new File(AccessController - .doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + private static final File tmpdir = new File( + GetPropertyAction.getProperty("java.io.tmpdir")); static File location() { return tmpdir; } diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index dbf10bd757d..a591136419d 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -40,6 +40,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; +import jdk.internal.misc.JavaObjectInputStreamAccess; +import jdk.internal.misc.ObjectStreamClassValidator; +import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import sun.reflect.misc.ReflectUtil; @@ -853,10 +856,14 @@ public class ObjectInputStream * exactly 'length' bytes. * * @param buf the buffer into which the data is read - * @param off the start offset of the data + * @param off the start offset in the destination array {@code buf} * @param len the maximum number of bytes read * @return the actual number of bytes read, -1 is returned when the end of * the stream is reached. + * @throws NullPointerException if {@code buf} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code buf.length - off}. * @throws IOException If an I/O error has occurred. * @see java.io.DataInputStream#readFully(byte[],int,int) */ @@ -1014,6 +1021,7 @@ public class ObjectInputStream * Reads bytes, blocking until all bytes are read. * * @param buf the buffer into which the data is read + * @throws NullPointerException If {@code buf} is {@code null}. * @throws EOFException If end of file is reached. * @throws IOException If other I/O error has occurred. */ @@ -1025,8 +1033,12 @@ public class ObjectInputStream * Reads bytes, blocking until all bytes are read. * * @param buf the buffer into which the data is read - * @param off the start offset of the data + * @param off the start offset into the data array {@code buf} * @param len the maximum number of bytes to read + * @throws NullPointerException If {@code buf} is {@code null}. + * @throws IndexOutOfBoundsException If {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code buf.length - off}. * @throws EOFException If end of file is reached. * @throws IOException If other I/O error has occurred. */ @@ -1509,23 +1521,28 @@ public class ObjectInputStream throws IOException { byte tc = bin.peekByte(); + ObjectStreamClass descriptor; switch (tc) { case TC_NULL: - return (ObjectStreamClass) readNull(); - + descriptor = (ObjectStreamClass) readNull(); + break; case TC_REFERENCE: - return (ObjectStreamClass) readHandle(unshared); - + descriptor = (ObjectStreamClass) readHandle(unshared); + break; case TC_PROXYCLASSDESC: - return readProxyDesc(unshared); - + descriptor = readProxyDesc(unshared); + break; case TC_CLASSDESC: - return readNonProxyDesc(unshared); - + descriptor = readNonProxyDesc(unshared); + break; default: throw new StreamCorruptedException( String.format("invalid type code: %02X", tc)); } + if (descriptor != null) { + validateDescriptor(descriptor); + } + return descriptor; } private boolean isCustomSubclass() { @@ -1915,6 +1932,8 @@ public class ObjectInputStream if (obj == null || handles.lookupException(passHandle) != null) { defaultReadFields(null, slotDesc); // skip field values } else if (slotDesc.hasReadObjectMethod()) { + ThreadDeath t = null; + boolean reset = false; SerialCallbackContext oldContext = curContext; if (oldContext != null) oldContext.check(); @@ -1933,10 +1952,19 @@ public class ObjectInputStream */ handles.markException(passHandle, ex); } finally { - curContext.setUsed(); - if (oldContext!= null) - oldContext.check(); - curContext = oldContext; + do { + try { + curContext.setUsed(); + if (oldContext!= null) + oldContext.check(); + curContext = oldContext; + reset = true; + } catch (ThreadDeath x) { + t = x; // defer until reset is true + } + } while (!reset); + if (t != null) + throw t; } /* @@ -3647,4 +3675,20 @@ public class ObjectInputStream } } + private void validateDescriptor(ObjectStreamClass descriptor) { + ObjectStreamClassValidator validating = validator; + if (validating != null) { + validating.validateDescriptor(descriptor); + } + } + + // controlled access to ObjectStreamClassValidator + private volatile ObjectStreamClassValidator validator; + + private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) { + ois.validator = validator; + } + static { + SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator); + } } diff --git a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java index 5179cce2dbe..cca42a71bbf 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java @@ -49,9 +49,9 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import jdk.internal.misc.Unsafe; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.ReflectionFactory; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.misc.ReflectUtil; import static java.io.ObjectStreamField.*; diff --git a/jdk/src/java.base/share/classes/java/io/ObjectStreamField.java b/jdk/src/java.base/share/classes/java/io/ObjectStreamField.java index bf03a67d317..3e5c6aa92aa 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectStreamField.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamField.java @@ -26,8 +26,8 @@ package java.io; import java.lang.reflect.Field; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; /** diff --git a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java index db6ae71f89f..1a8344df88b 100644 --- a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -418,10 +418,11 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * read. This method blocks until the requested number of bytes are * read, the end of the stream is detected, or an exception is thrown. * - * @param b the buffer into which the data is read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws EOFException if this file reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); @@ -434,12 +435,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * read. This method blocks until the requested number of bytes are * read, the end of the stream is detected, or an exception is thrown. * - * @param b the buffer into which the data is read. - * @param off the start offset of the data. - * @param len the number of bytes to read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. + * @param b the buffer into which the data is read. + * @param off the start offset into the data array {@code b}. + * @param len the number of bytes to read. + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off} is negative, + * {@code len} is negative, or {@code len} is greater than + * {@code b.length - off}. + * @throws EOFException if this file reaches the end before reading + * all the bytes. + * @throws IOException if an I/O error occurs. */ public final void readFully(byte b[], int off, int len) throws IOException { int n = 0; diff --git a/jdk/src/java.base/share/classes/java/lang/Boolean.java b/jdk/src/java.base/share/classes/java/lang/Boolean.java index b53995193f1..eeda751719c 100644 --- a/jdk/src/java.base/share/classes/java/lang/Boolean.java +++ b/jdk/src/java.base/share/classes/java/lang/Boolean.java @@ -79,13 +79,16 @@ public final class Boolean implements java.io.Serializable, * Allocates a {@code Boolean} object representing the * {@code value} argument. * - *

Note: It is rarely appropriate to use this constructor. - * Unless a new instance is required, the static factory - * {@link #valueOf(boolean)} is generally a better choice. It is - * likely to yield significantly better space and time performance. - * * @param value the value of the {@code Boolean}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(boolean)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. + * Also consider using the final fields {@link #TRUE} and {@link #FALSE} + * if possible. */ + @Deprecated(since="9") public Boolean(boolean value) { this.value = value; } @@ -94,15 +97,18 @@ public final class Boolean implements java.io.Serializable, * Allocates a {@code Boolean} object representing the value * {@code true} if the string argument is not {@code null} * and is equal, ignoring case, to the string {@code "true"}. - * Otherwise, allocate a {@code Boolean} object representing the - * value {@code false}. Examples:

- * {@code new Boolean("True")} produces a {@code Boolean} object - * that represents {@code true}.
- * {@code new Boolean("yes")} produces a {@code Boolean} object - * that represents {@code false}. + * Otherwise, allocates a {@code Boolean} object representing the + * value {@code false}. * * @param s the string to be converted to a {@code Boolean}. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseBoolean(String)} to convert a string to a + * {@code boolean} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Boolean} object. */ + @Deprecated(since="9") public Boolean(String s) { this(parseBoolean(s)); } diff --git a/jdk/src/java.base/share/classes/java/lang/Byte.java b/jdk/src/java.base/share/classes/java/lang/Byte.java index 51f687cb389..877af689556 100644 --- a/jdk/src/java.base/share/classes/java/lang/Byte.java +++ b/jdk/src/java.base/share/classes/java/lang/Byte.java @@ -297,7 +297,13 @@ public final class Byte extends Number implements Comparable { * * @param value the value to be represented by the * {@code Byte}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(byte)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Byte(byte value) { this.value = value; } @@ -311,10 +317,16 @@ public final class Byte extends Number implements Comparable { * * @param s the {@code String} to be converted to a * {@code Byte} - * @throws NumberFormatException If the {@code String} + * @throws NumberFormatException if the {@code String} * does not contain a parsable {@code byte}. - * @see java.lang.Byte#parseByte(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseByte(String)} to convert a string to a + * {@code byte} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Byte} object. */ + @Deprecated(since="9") public Byte(String s) throws NumberFormatException { this.value = parseByte(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/Character.java b/jdk/src/java.base/share/classes/java/lang/Character.java index ea42bfb3d6e..9f9e4de1972 100644 --- a/jdk/src/java.base/share/classes/java/lang/Character.java +++ b/jdk/src/java.base/share/classes/java/lang/Character.java @@ -1256,14 +1256,14 @@ class Character implements java.io.Serializable, Comparable { new UnicodeBlock("SPECIALS"); /** - * @deprecated As of J2SE 5, use {@link #HIGH_SURROGATES}, - * {@link #HIGH_PRIVATE_USE_SURROGATES}, and - * {@link #LOW_SURROGATES}. These new constants match - * the block definitions of the Unicode Standard. - * The {@link #of(char)} and {@link #of(int)} methods - * return the new constants, not SURROGATES_AREA. + * @deprecated + * Instead of {@code SURROGATES_AREA}, use {@link #HIGH_SURROGATES}, + * {@link #HIGH_PRIVATE_USE_SURROGATES}, and {@link #LOW_SURROGATES}. + * These constants match the block definitions of the Unicode Standard. + * The {@link #of(char)} and {@link #of(int)} methods return the + * standard constants. */ - @Deprecated + @Deprecated(since="1.5") public static final UnicodeBlock SURROGATES_AREA = new UnicodeBlock("SURROGATES_AREA"); @@ -7451,7 +7451,13 @@ class Character implements java.io.Serializable, Comparable { * * @param value the value to be represented by the * {@code Character} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(char)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Character(char value) { this.value = value; } @@ -8799,7 +8805,7 @@ class Character implements java.io.Serializable, Comparable { * @since 1.0.2 * @deprecated Replaced by isJavaIdentifierStart(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isJavaLetter(char ch) { return isJavaIdentifierStart(ch); } @@ -8835,7 +8841,7 @@ class Character implements java.io.Serializable, Comparable { * @since 1.0.2 * @deprecated Replaced by isJavaIdentifierPart(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isJavaLetterOrDigit(char ch) { return isJavaIdentifierPart(ch); } @@ -9580,7 +9586,7 @@ class Character implements java.io.Serializable, Comparable { * @see Character#isWhitespace(char) * @deprecated Replaced by isWhitespace(char). */ - @Deprecated + @Deprecated(since="1.1") public static boolean isSpace(char ch) { return (ch <= 0x0020) && (((((1L << 0x0009) | diff --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index fa6971dabfa..3ea9467a45f 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -66,10 +66,10 @@ import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; -import sun.reflect.CallerSensitive; -import sun.reflect.ConstantPool; -import sun.reflect.Reflection; -import sun.reflect.ReflectionFactory; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.ConstantPool; +import jdk.internal.reflect.Reflection; +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.repository.ClassRepository; @@ -3473,7 +3473,7 @@ public final class Class implements java.io.Serializable, if (reflectionFactory == null) { reflectionFactory = java.security.AccessController.doPrivileged - (new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); + (new ReflectionFactory.GetReflectionFactoryAction()); } return reflectionFactory; } diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 9fe76558c82..61123302a3c 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -60,8 +60,8 @@ import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; @@ -727,7 +727,7 @@ public abstract class ClassLoader { * @deprecated Replaced by {@link #defineClass(String, byte[], int, int) * defineClass(String, byte[], int, int)} */ - @Deprecated + @Deprecated(since="1.1") protected final Class defineClass(byte[] b, int off, int len) throws ClassFormatError { @@ -817,6 +817,9 @@ public abstract class ClassLoader { if (!checkName(name)) throw new NoClassDefFoundError("IllegalName: " + name); + // Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias + // relies on the fact that spoofing is impossible if a class has a name + // of the form "java.*" if ((name != null) && name.startsWith("java.") && this != getBuiltinPlatformClassLoader()) { throw new SecurityException @@ -2012,7 +2015,7 @@ public abstract class ClassLoader { * * @since 1.2 */ - @Deprecated + @Deprecated(since="9") protected Package getPackage(String name) { Package pkg = getDefinedPackage(name); if (pkg == null) { diff --git a/jdk/src/java.base/share/classes/java/lang/Double.java b/jdk/src/java.base/share/classes/java/lang/Double.java index 473b86dd909..75a227e5282 100644 --- a/jdk/src/java.base/share/classes/java/lang/Double.java +++ b/jdk/src/java.base/share/classes/java/lang/Double.java @@ -589,7 +589,13 @@ public final class Double extends Number implements Comparable { * represents the primitive {@code double} argument. * * @param value the value to be represented by the {@code Double}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(double)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Double(double value) { this.value = value; } @@ -601,10 +607,16 @@ public final class Double extends Number implements Comparable { * {@code double} value as if by the {@code valueOf} method. * * @param s a string to be converted to a {@code Double}. - * @throws NumberFormatException if the string does not contain a + * @throws NumberFormatException if the string does not contain a * parsable number. - * @see java.lang.Double#valueOf(java.lang.String) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseDouble(String)} to convert a string to a + * {@code double} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Double} object. */ + @Deprecated(since="9") public Double(String s) throws NumberFormatException { value = parseDouble(s); } diff --git a/jdk/src/java.base/share/classes/java/lang/Float.java b/jdk/src/java.base/share/classes/java/lang/Float.java index 334d3d033da..60e08db7ad5 100644 --- a/jdk/src/java.base/share/classes/java/lang/Float.java +++ b/jdk/src/java.base/share/classes/java/lang/Float.java @@ -502,7 +502,13 @@ public final class Float extends Number implements Comparable { * represents the primitive {@code float} argument. * * @param value the value to be represented by the {@code Float}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(float)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Float(float value) { this.value = value; } @@ -512,7 +518,13 @@ public final class Float extends Number implements Comparable { * represents the argument converted to type {@code float}. * * @param value the value to be represented by the {@code Float}. + * + * @deprecated + * It is rarely appropriate to use this constructor. Instead, use the + * static factory method {@link #valueOf(float)} method as follows: + * {@code Float.valueOf((float)value)}. */ + @Deprecated(since="9") public Float(double value) { this.value = (float)value; } @@ -523,11 +535,17 @@ public final class Float extends Number implements Comparable { * represented by the string. The string is converted to a * {@code float} value as if by the {@code valueOf} method. * - * @param s a string to be converted to a {@code Float}. - * @throws NumberFormatException if the string does not contain a - * parsable number. - * @see java.lang.Float#valueOf(java.lang.String) + * @param s a string to be converted to a {@code Float}. + * @throws NumberFormatException if the string does not contain a + * parsable number. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseFloat(String)} to convert a string to a + * {@code float} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Float} object. */ + @Deprecated(since="9") public Float(String s) throws NumberFormatException { value = parseFloat(s); } 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 2a846c4d07f..7765d784e07 100644 --- a/jdk/src/java.base/share/classes/java/lang/Integer.java +++ b/jdk/src/java.base/share/classes/java/lang/Integer.java @@ -1106,7 +1106,13 @@ public final class Integer extends Number implements Comparable { * * @param value the value to be represented by the * {@code Integer} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(int)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Integer(int value) { this.value = value; } @@ -1118,12 +1124,17 @@ public final class Integer extends Number implements Comparable { * {@code int} value in exactly the manner used by the * {@code parseInt} method for radix 10. * - * @param s the {@code String} to be converted to an - * {@code Integer}. - * @exception NumberFormatException if the {@code String} does not - * contain a parsable integer. - * @see java.lang.Integer#parseInt(java.lang.String, int) + * @param s the {@code String} to be converted to an {@code Integer}. + * @throws NumberFormatException if the {@code String} does not + * contain a parsable integer. + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseInt(String)} to convert a string to a + * {@code int} primitive, or use {@link #valueOf(String)} + * to convert a string to an {@code Integer} object. */ + @Deprecated(since="9") public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); } 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 ae93a7ca827..793d15e53b2 100644 --- a/jdk/src/java.base/share/classes/java/lang/Long.java +++ b/jdk/src/java.base/share/classes/java/lang/Long.java @@ -1340,7 +1340,13 @@ public final class Long extends Number implements Comparable { * * @param value the value to be represented by the * {@code Long} object. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(long)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Long(long value) { this.value = value; } @@ -1356,8 +1362,14 @@ public final class Long extends Number implements Comparable { * {@code Long}. * @throws NumberFormatException if the {@code String} does not * contain a parsable {@code long}. - * @see java.lang.Long#parseLong(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseLong(String)} to convert a string to a + * {@code long} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Long} object. */ + @Deprecated(since="9") public Long(String s) throws NumberFormatException { this.value = parseLong(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/Math.java b/jdk/src/java.base/share/classes/java/lang/Math.java index 17c254a1171..4244d40a3b9 100644 --- a/jdk/src/java.base/share/classes/java/lang/Math.java +++ b/jdk/src/java.base/share/classes/java/lang/Math.java @@ -25,6 +25,7 @@ package java.lang; +import java.math.BigDecimal; import java.util.Random; import jdk.internal.math.FloatConsts; import jdk.internal.math.DoubleConsts; @@ -1449,6 +1450,199 @@ public final class Math { return (a <= b) ? a : b; } + /** + * Returns the fused multiply add of the three arguments; that is, + * returns the exact product of the first two arguments summed + * with the third argument and then rounded once to the nearest + * {@code double}. + * + * The rounding is done using the {@linkplain + * java.math.RoundingMode#HALF_EVEN round to nearest even + * rounding mode}. + * + * In contrast, if {@code a * b + c} is evaluated as a regular + * floating-point expression, two rounding errors are involved, + * the first for the multiply operation, the second for the + * addition operation. + * + *

Special cases: + *

    + *
  • If any argument is NaN, the result is NaN. + * + *
  • If one of the first two arguments is infinite and the + * other is zero, the result is NaN. + * + *
  • If the exact product of the first two arguments is infinite + * (in other words, at least one of the arguments is infinite and + * the other is neither zero nor NaN) and the third argument is an + * infinity of the opposite sign, the result is NaN. + * + *
+ * + *

Note that {@code fma(a, 1.0, c)} returns the same + * result as ({@code a + c}). However, + * {@code fma(a, b, +0.0)} does not always return the + * same result as ({@code a * b}) since + * {@code fma(-0.0, +0.0, +0.0)} is {@code +0.0} while + * ({@code -0.0 * +0.0}) is {@code -0.0}; {@code fma(a, b, -0.0)} is + * equivalent to ({@code a * b}) however. + * + * @apiNote This method corresponds to the fusedMultiplyAdd + * operation defined in IEEE 754-2008. + * + * @param a a value + * @param b a value + * @param c a value + * + * @return (a × b + c) + * computed, as if with unlimited range and precision, and rounded + * once to the nearest {@code double} value + */ + // @HotSpotIntrinsicCandidate + public static double fma(double a, double b, double c) { + /* + * Infinity and NaN arithmetic is not quite the same with two + * roundings as opposed to just one so the simple expression + * "a * b + c" cannot always be used to compute the correct + * result. With two roundings, the product can overflow and + * if the addend is infinite, a spurious NaN can be produced + * if the infinity from the overflow and the infinite addend + * have opposite signs. + */ + + // First, screen for and handle non-finite input values whose + // arithmetic is not supported by BigDecimal. + if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c)) { + return Double.NaN; + } else { // All inputs non-NaN + boolean infiniteA = Double.isInfinite(a); + boolean infiniteB = Double.isInfinite(b); + boolean infiniteC = Double.isInfinite(c); + double result; + + if (infiniteA || infiniteB || infiniteC) { + if (infiniteA && b == 0.0 || + infiniteB && a == 0.0 ) { + return Double.NaN; + } + // Store product in a double field to cause an + // overflow even if non-strictfp evaluation is being + // used. + double product = a * b; + if (Double.isInfinite(product) && !infiniteA && !infiniteB) { + // Intermediate overflow; might cause a + // spurious NaN if added to infinite c. + assert Double.isInfinite(c); + return c; + } else { + result = product + c; + assert !Double.isFinite(result); + return result; + } + } else { // All inputs finite + BigDecimal product = (new BigDecimal(a)).multiply(new BigDecimal(b)); + if (c == 0.0) { // Positive or negative zero + // If the product is an exact zero, use a + // floating-point expression to compute the sign + // of the zero final result. The product is an + // exact zero if and only if at least one of a and + // b is zero. + if (a == 0.0 || b == 0.0) { + return a * b + c; + } else { + // The sign of a zero addend doesn't matter if + // the product is nonzero. The sign of a zero + // addend is not factored in the result if the + // exact product is nonzero but underflows to + // zero; see IEEE-754 2008 section 6.3 "The + // sign bit". + return product.doubleValue(); + } + } else { + return product.add(new BigDecimal(c)).doubleValue(); + } + } + } + } + + /** + * Returns the fused multiply add of the three arguments; that is, + * returns the exact product of the first two arguments summed + * with the third argument and then rounded once to the nearest + * {@code float}. + * + * The rounding is done using the {@linkplain + * java.math.RoundingMode#HALF_EVEN round to nearest even + * rounding mode}. + * + * In contrast, if {@code a * b + c} is evaluated as a regular + * floating-point expression, two rounding errors are involved, + * the first for the multiply operation, the second for the + * addition operation. + * + *

Special cases: + *

    + *
  • If any argument is NaN, the result is NaN. + * + *
  • If one of the first two arguments is infinite and the + * other is zero, the result is NaN. + * + *
  • If the exact product of the first two arguments is infinite + * (in other words, at least one of the arguments is infinite and + * the other is neither zero nor NaN) and the third argument is an + * infinity of the opposite sign, the result is NaN. + * + *
+ * + *

Note that {@code fma(a, 1.0f, c)} returns the same + * result as ({@code a + c}). However, + * {@code fma(a, b, +0.0f)} does not always return the + * same result as ({@code a * b}) since + * {@code fma(-0.0f, +0.0f, +0.0f)} is {@code +0.0f} while + * ({@code -0.0f * +0.0f}) is {@code -0.0f}; {@code fma(a, b, -0.0f)} is + * equivalent to ({@code a * b}) however. + * + * @apiNote This method corresponds to the fusedMultiplyAdd + * operation defined in IEEE 754-2008. + * + * @param a a value + * @param b a value + * @param c a value + * + * @return (a × b + c) + * computed, as if with unlimited range and precision, and rounded + * once to the nearest {@code float} value + */ + // @HotSpotIntrinsicCandidate + public static float fma(float a, float b, float c) { + /* + * Since the double format has more than twice the precision + * of the float format, the multiply of a * b is exact in + * double. The add of c to the product then incurs one + * rounding error. Since the double format moreover has more + * than (2p + 2) precision bits compared to the p bits of the + * float format, the two roundings of (a * b + c), first to + * the double format and then secondarily to the float format, + * are equivalent to rounding the intermediate result directly + * to the float format. + * + * In terms of strictfp vs default-fp concerns related to + * overflow and underflow, since + * + * (Float.MAX_VALUE * Float.MAX_VALUE) << Double.MAX_VALUE + * (Float.MIN_VALUE * Float.MIN_VALUE) >> Double.MIN_VALUE + * + * neither the multiply nor add will overflow or underflow in + * double. Therefore, it is not necessary for this method to + * be declared strictfp to have reproducible + * behavior. However, it is necessary to explicitly store down + * to a float variable to avoid returning a value in the float + * extended value set. + */ + float result = (float)(((double) a * (double) b ) + (double) c); + return result; + } + /** * Returns the size of an ulp of the argument. An ulp, unit in * the last place, of a {@code double} value is the positive diff --git a/jdk/src/java.base/share/classes/java/lang/Package.java b/jdk/src/java.base/share/classes/java/lang/Package.java index 5b80278b097..1aa9e98fbf2 100644 --- a/jdk/src/java.base/share/classes/java/lang/Package.java +++ b/jdk/src/java.base/share/classes/java/lang/Package.java @@ -36,8 +36,8 @@ import java.security.PrivilegedAction; import java.util.Objects; import jdk.internal.loader.BootLoader; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** @@ -333,7 +333,7 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated * @see ClassLoader#getDefinedPackage */ @CallerSensitive - @Deprecated + @Deprecated(since="9") @SuppressWarnings("deprecation") public static Package getPackage(String name) { ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); diff --git a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java index ebd47fcfe87..638be0e9f72 100644 --- a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java +++ b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java @@ -30,13 +30,12 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.channels.Pipe; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.security.AccessController; -import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; + /** * This class is used to create operating system processes. * @@ -468,11 +467,9 @@ public final class ProcessBuilder * @since 1.7 */ public abstract static class Redirect { - private static final File NULL_FILE = AccessController.doPrivileged( - (PrivilegedAction) () -> { - return new File((System.getProperty("os.name") - .startsWith("Windows") ? "NUL" : "/dev/null")); - } + private static final File NULL_FILE = new File( + (GetPropertyAction.getProperty("os.name") + .startsWith("Windows") ? "NUL" : "/dev/null") ); /** diff --git a/jdk/src/java.base/share/classes/java/lang/Runtime.java b/jdk/src/java.base/share/classes/java/lang/Runtime.java index 668357e7067..a5deffc16b8 100644 --- a/jdk/src/java.base/share/classes/java/lang/Runtime.java +++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java @@ -27,8 +27,8 @@ package java.lang; import java.io.*; import java.util.StringTokenizer; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** * Every Java application has a single instance of class @@ -289,6 +289,7 @@ public class Runtime { * finalizers being called on live objects while other threads are * concurrently manipulating those objects, resulting in erratic * behavior or deadlock. + * This method is subject to removal in a future version of Java SE. * * @throws SecurityException * if a security manager exists and its {@code checkExit} @@ -299,7 +300,7 @@ public class Runtime { * @see java.lang.SecurityManager#checkExit(int) * @since 1.1 */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public static void runFinalizersOnExit(boolean value) { SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -894,8 +895,9 @@ public class Runtime { * stream in the local encoding into a character stream in Unicode is via * the {@code InputStreamReader} and {@code BufferedReader} * classes. + * This method is subject to removal in a future version of Java SE. */ - @Deprecated + @Deprecated(since="1.1", forRemoval=true) public InputStream getLocalizedInputStream(InputStream in) { return in; } @@ -915,6 +917,7 @@ public class Runtime { * Unicode character stream into a byte stream in the local encoding is via * the {@code OutputStreamWriter}, {@code BufferedWriter}, and * {@code PrintWriter} classes. + * This method is subject to removal in a future version of Java SE. * * @param out OutputStream to localize * @return a localized output stream @@ -923,7 +926,7 @@ public class Runtime { * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream) */ - @Deprecated + @Deprecated(since="1.1", forRemoval=true) public OutputStream getLocalizedOutputStream(OutputStream out) { return out; } diff --git a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java index 4560219fe8e..e88a5eaa181 100644 --- a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java +++ b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java @@ -38,7 +38,7 @@ import java.net.InetAddress; import java.lang.reflect.*; import java.net.URL; -import sun.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitive; import sun.security.util.SecurityConstants; /** @@ -229,7 +229,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") protected boolean inCheck; /* @@ -262,7 +262,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") public boolean getInCheck() { return inCheck; } @@ -345,7 +345,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected ClassLoader currentClassLoader() { ClassLoader cl = currentClassLoader0(); if ((cl != null) && hasAllPermission()) @@ -391,7 +391,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected Class currentLoadedClass() { Class c = currentLoadedClass0(); if ((c != null) && hasAllPermission()) @@ -411,7 +411,7 @@ class SecurityManager { * call be used instead. * */ - @Deprecated + @Deprecated(since="1.2") protected native int classDepth(String name); /** @@ -449,7 +449,7 @@ class SecurityManager { * @see java.lang.ClassLoader#getSystemClassLoader() getSystemClassLoader * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.2") protected int classLoaderDepth() { int depth = classLoaderDepth0(); if (depth != -1) { @@ -474,7 +474,7 @@ class SecurityManager { * It is recommended that the checkPermission * call be used instead. */ - @Deprecated + @Deprecated(since="1.2") protected boolean inClass(String name) { return classDepth(name) >= 0; } @@ -491,7 +491,7 @@ class SecurityManager { * call be used instead. * @see #currentClassLoader() currentClassLoader */ - @Deprecated + @Deprecated(since="1.2") protected boolean inClassLoader() { return currentClassLoader() != null; } @@ -1217,7 +1217,7 @@ class SecurityManager { * @deprecated Use #checkPermission(java.security.Permission) instead * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.4") public void checkMulticast(InetAddress maddr, byte ttl) { String host = maddr.getHostAddress(); if (!host.startsWith("[") && host.indexOf(':') != -1) { @@ -1297,9 +1297,10 @@ class SecurityManager { * was trusted to bring up a top-level window. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("showWindowWithoutWarningBanner")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public boolean checkTopLevelWindow(Object window) { if (window == null) { throw new NullPointerException("window can't be null"); @@ -1340,9 +1341,10 @@ class SecurityManager { * thread could access the system clipboard. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("accessClipboard")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public void checkSystemClipboardAccess() { checkPermission(SecurityConstants.ALL_PERMISSION); } @@ -1358,9 +1360,10 @@ class SecurityManager { * thread could access the AWT event queue. The method has been * obsoleted and code should instead use {@link #checkPermission} * to check {@code AWTPermission("accessEventQueue")}. + * This method is subject to removal in a future version of Java SE. * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) public void checkAwtEventQueueAccess() { checkPermission(SecurityConstants.ALL_PERMISSION); } @@ -1626,12 +1629,13 @@ class SecurityManager { * Users of this method should instead invoke {@link #checkPermission} * directly. This method will be changed in a future release * to check the permission {@code java.security.AllPermission}. + * This method is subject to removal in a future version of Java SE. * * @see java.lang.reflect.Member * @since 1.1 * @see #checkPermission(java.security.Permission) checkPermission */ - @Deprecated + @Deprecated(since="1.8", forRemoval=true) @CallerSensitive public void checkMemberAccess(Class clazz, int which) { if (clazz == null) { diff --git a/jdk/src/java.base/share/classes/java/lang/Short.java b/jdk/src/java.base/share/classes/java/lang/Short.java index 9fa79f3d8c2..57b291fc03a 100644 --- a/jdk/src/java.base/share/classes/java/lang/Short.java +++ b/jdk/src/java.base/share/classes/java/lang/Short.java @@ -302,7 +302,13 @@ public final class Short extends Number implements Comparable { * * @param value the value to be represented by the * {@code Short}. + * + * @deprecated + * It is rarely appropriate to use this constructor. The static factory + * {@link #valueOf(short)} is generally a better choice, as it is + * likely to yield significantly better space and time performance. */ + @Deprecated(since="9") public Short(short value) { this.value = value; } @@ -318,8 +324,14 @@ public final class Short extends Number implements Comparable { * {@code Short} * @throws NumberFormatException If the {@code String} * does not contain a parsable {@code short}. - * @see java.lang.Short#parseShort(java.lang.String, int) + * + * @deprecated + * It is rarely appropriate to use this constructor. + * Use {@link #parseShort(String)} to convert a string to a + * {@code short} primitive, or use {@link #valueOf(String)} + * to convert a string to a {@code Short} object. */ + @Deprecated(since="9") public Short(String s) throws NumberFormatException { this.value = parseShort(s, 10); } diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java index ac2e8916bea..73446062bea 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -24,13 +24,12 @@ */ package java.lang; +import jdk.internal.reflect.MethodAccessor; import java.lang.StackWalker.Option; import java.lang.StackWalker.StackFrame; import java.lang.annotation.Native; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Objects; @@ -40,6 +39,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import sun.security.action.GetPropertyAction; import static java.lang.StackStreamFactory.WalkerState.*; @@ -978,25 +978,20 @@ final class StackStreamFactory { } private static boolean isReflectionFrame(Class c) { - if (c.getName().startsWith("sun.reflect") && - !sun.reflect.MethodAccessor.class.isAssignableFrom(c)) { - throw new InternalError("Not sun.reflect.MethodAccessor: " + c.toString()); + if (c.getName().startsWith("jdk.internal.reflect") && + !MethodAccessor.class.isAssignableFrom(c)) { + throw new InternalError("Not jdk.internal.reflect.MethodAccessor: " + c.toString()); } // ## should filter all @Hidden frames? return c == Method.class || - sun.reflect.MethodAccessor.class.isAssignableFrom(c) || + MethodAccessor.class.isAssignableFrom(c) || c.getName().startsWith("java.lang.invoke.LambdaForm"); } private static boolean getProperty(String key, boolean value) { - String s = AccessController.doPrivileged(new PrivilegedAction<>() { - @Override - public String run() { - return System.getProperty(key); - } - }); + String s = GetPropertyAction.getProperty(key); if (s != null) { - return Boolean.valueOf(s); + return Boolean.parseBoolean(s); } return value; } diff --git a/jdk/src/java.base/share/classes/java/lang/StackWalker.java b/jdk/src/java.base/share/classes/java/lang/StackWalker.java index 636762e17d4..7eeef016681 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java +++ b/jdk/src/java.base/share/classes/java/lang/StackWalker.java @@ -24,7 +24,7 @@ */ package java.lang; -import sun.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitive; import java.util.*; import java.util.function.Consumer; diff --git a/jdk/src/java.base/share/classes/java/lang/StrictMath.java b/jdk/src/java.base/share/classes/java/lang/StrictMath.java index 0c82f6afbf5..a92f566c153 100644 --- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java +++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java @@ -1134,6 +1134,110 @@ public final class StrictMath { return Math.min(a, b); } + /** + * Returns the fused multiply add of the three arguments; that is, + * returns the exact product of the first two arguments summed + * with the third argument and then rounded once to the nearest + * {@code double}. + * + * The rounding is done using the {@linkplain + * java.math.RoundingMode#HALF_EVEN round to nearest even + * rounding mode}. + * + * In contrast, if {@code a * b + c} is evaluated as a regular + * floating-point expression, two rounding errors are involved, + * the first for the multiply operation, the second for the + * addition operation. + * + *

Special cases: + *

    + *
  • If any argument is NaN, the result is NaN. + * + *
  • If one of the first two arguments is infinite and the + * other is zero, the result is NaN. + * + *
  • If the exact product of the first two arguments is infinite + * (in other words, at least one of the arguments is infinite and + * the other is neither zero nor NaN) and the third argument is an + * infinity of the opposite sign, the result is NaN. + * + *
+ * + *

Note that {@code fusedMac(a, 1.0, c)} returns the same + * result as ({@code a + c}). However, + * {@code fusedMac(a, b, +0.0)} does not always return the + * same result as ({@code a * b}) since + * {@code fusedMac(-0.0, +0.0, +0.0)} is {@code +0.0} while + * ({@code -0.0 * +0.0}) is {@code -0.0}; {@code fusedMac(a, b, -0.0)} is + * equivalent to ({@code a * b}) however. + * + * @apiNote This method corresponds to the fusedMultiplyAdd + * operation defined in IEEE 754-2008. + * + * @param a a value + * @param b a value + * @param c a value + * + * @return (a × b + c) + * computed, as if with unlimited range and precision, and rounded + * once to the nearest {@code double} value + */ + public static double fma(double a, double b, double c) { + return Math.fma(a, b, c); + } + + /** + * Returns the fused multiply add of the three arguments; that is, + * returns the exact product of the first two arguments summed + * with the third argument and then rounded once to the nearest + * {@code float}. + * + * The rounding is done using the {@linkplain + * java.math.RoundingMode#HALF_EVEN round to nearest even + * rounding mode}. + * + * In contrast, if {@code a * b + c} is evaluated as a regular + * floating-point expression, two rounding errors are involved, + * the first for the multiply operation, the second for the + * addition operation. + * + *

Special cases: + *

    + *
  • If any argument is NaN, the result is NaN. + * + *
  • If one of the first two arguments is infinite and the + * other is zero, the result is NaN. + * + *
  • If the exact product of the first two arguments is infinite + * (in other words, at least one of the arguments is infinite and + * the other is neither zero nor NaN) and the third argument is an + * infinity of the opposite sign, the result is NaN. + * + *
+ * + *

Note that {@code fma(a, 1.0f, c)} returns the same + * result as ({@code a + c}). However, + * {@code fma(a, b, +0.0f)} does not always return the + * same result as ({@code a * b}) since + * {@code fma(-0.0f, +0.0f, +0.0f)} is {@code +0.0f} while + * ({@code -0.0f * +0.0f}) is {@code -0.0f}; {@code fma(a, b, -0.0f)} is + * equivalent to ({@code a * b}) however. + * + * @apiNote This method corresponds to the fusedMultiplyAdd + * operation defined in IEEE 754-2008. + * + * @param a a value + * @param b a value + * @param c a value + * + * @return (a × b + c) + * computed, as if with unlimited range and precision, and rounded + * once to the nearest {@code float} value + */ + public static float fma(float a, float b, float c) { + return Math.fma(a, b, c); + } + /** * Returns the size of an ulp of the argument. An ulp, unit in * the last place, of a {@code double} value is the positive 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 a609223d42f..a1772977727 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -363,7 +363,7 @@ public final class String * @see #String(byte[], java.nio.charset.Charset) * @see #String(byte[]) */ - @Deprecated + @Deprecated(since="1.1") public String(byte ascii[], int hibyte, int offset, int count) { checkBoundsOffCount(offset, count, ascii.length); if (count == 0) { @@ -415,7 +415,7 @@ public final class String * @see #String(byte[], java.nio.charset.Charset) * @see #String(byte[]) */ - @Deprecated + @Deprecated(since="1.1") public String(byte ascii[], int hibyte) { this(ascii, hibyte, 0, ascii.length); } @@ -911,7 +911,7 @@ public final class String * dst.length} * */ - @Deprecated + @Deprecated(since="1.1") public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { checkBoundsBeginEnd(srcBegin, srcEnd, length()); Objects.requireNonNull(dst); diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 5bbaff28335..2ddd37f5da1 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -56,8 +56,8 @@ import java.util.Objects; import java.util.ResourceBundle; import java.util.function.Supplier; import sun.nio.ch.Interruptible; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; import jdk.internal.HotSpotIntrinsicCandidate; @@ -1715,6 +1715,7 @@ public final class System { * finalizers being called on live objects while other threads are * concurrently manipulating those objects, resulting in erratic * behavior or deadlock. + * This method is subject to removal in a future version of Java SE. * @param value indicating enabling or disabling of finalization * @throws SecurityException * if a security manager exists and its checkExit @@ -1725,7 +1726,7 @@ public final class System { * @see java.lang.SecurityManager#checkExit(int) * @since 1.1 */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public static void runFinalizersOnExit(boolean value) { Runtime.runFinalizersOnExit(value); } @@ -1978,7 +1979,7 @@ public final class System { private static void setJavaLangAccess() { // Allow privileged classes outside of java.lang SharedSecrets.setJavaLangAccess(new JavaLangAccess(){ - public sun.reflect.ConstantPool getConstantPool(Class klass) { + public jdk.internal.reflect.ConstantPool getConstantPool(Class klass) { return klass.getConstantPool(); } public boolean casAnnotationType(Class klass, AnnotationType oldType, AnnotationType newType) { diff --git a/jdk/src/java.base/share/classes/java/lang/Thread.java b/jdk/src/java.base/share/classes/java/lang/Thread.java index d3c6c9e7f4f..310ada1b470 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -37,8 +37,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; import sun.nio.ch.Interruptible; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.security.util.SecurityConstants; import jdk.internal.HotSpotIntrinsicCandidate; @@ -929,7 +929,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void stop() { SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -961,8 +961,9 @@ class Thread implements Runnable { * For more information, see * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. + * This method is subject to removal in a future version of Java SE. */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public final synchronized void stop(Throwable obj) { throw new UnsupportedOperationException(); } @@ -1082,9 +1083,10 @@ class Thread implements Runnable { * "frozen" processes. For more information, see * * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?. + * This method is subject to removal in a future version of Java SE. * @throws NoSuchMethodError always */ - @Deprecated + @Deprecated(since="1.5", forRemoval=true) public void destroy() { throw new NoSuchMethodError(); } @@ -1122,7 +1124,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void suspend() { checkAccess(); suspend0(); @@ -1148,7 +1150,7 @@ class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated + @Deprecated(since="1.2") public final void resume() { checkAccess(); resume0(); @@ -1309,8 +1311,10 @@ class Thread implements Runnable { * @deprecated The definition of this call depends on {@link #suspend}, * which is deprecated. Further, the results of this call * were never well-defined. + * This method is subject to removal in a future version of Java SE. + * @see StackWalker */ - @Deprecated + @Deprecated(since="1.2", forRemoval=true) public native int countStackFrames(); /** diff --git a/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java b/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java index e477800f61c..0a97e4cad94 100644 --- a/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/jdk/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -607,7 +607,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * @deprecated This method is inherently unsafe. See * {@link Thread#stop} for details. */ - @Deprecated + @Deprecated(since="1.2") public final void stop() { if (stopOrSuspend(false)) Thread.currentThread().stop(); @@ -669,7 +669,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * @deprecated This method is inherently deadlock-prone. See * {@link Thread#suspend} for details. */ - @Deprecated + @Deprecated(since="1.2") @SuppressWarnings("deprecation") public final void suspend() { if (stopOrSuspend(true)) @@ -732,7 +732,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * both of which have been deprecated, as they are inherently * deadlock-prone. See {@link Thread#suspend} for details. */ - @Deprecated + @Deprecated(since="1.2") @SuppressWarnings("deprecation") public final void resume() { int ngroupsSnapshot; @@ -1073,7 +1073,7 @@ class ThreadGroup implements Thread.UncaughtExceptionHandler { * which is deprecated. Further, the behavior of this call * was never specified. */ - @Deprecated + @Deprecated(since="1.2") public boolean allowThreadSuspension(boolean b) { this.vmAllowSuspension = b; if (!b) { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 739573507ab..a0df622f501 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -88,8 +88,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; static { final String key = "jdk.internal.lambda.dumpProxyClasses"; - String path = AccessController.doPrivileged( - new GetPropertyAction(key)); + String path = GetPropertyAction.getProperty(key); dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path); } 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 7525d5ffb0b..de4e3c15537 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 @@ -733,6 +733,7 @@ import java.util.Objects; } @Override + @SuppressWarnings("deprecation") public int hashCode() { // Avoid autoboxing getReferenceKind(), since this is used early and will force // early initialization of Byte$ByteCache @@ -826,7 +827,7 @@ import java.util.Objects; assert(isResolved() == isResolved); } - void checkForTypeAlias() { + void checkForTypeAlias(Class refc) { if (isInvocable()) { MethodType type; if (this.type instanceof MethodType) @@ -834,16 +835,16 @@ import java.util.Objects; else this.type = type = getMethodType(); if (type.erase() == type) return; - if (VerifyAccess.isTypeVisible(type, clazz)) return; - throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz); + if (VerifyAccess.isTypeVisible(type, refc)) return; + throw new LinkageError("bad method type alias: "+type+" not visible from "+refc); } else { Class type; if (this.type instanceof Class) type = (Class) this.type; else this.type = type = getFieldType(); - if (VerifyAccess.isTypeVisible(type, clazz)) return; - throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz); + if (VerifyAccess.isTypeVisible(type, refc)) return; + throw new LinkageError("bad field type alias: "+type+" not visible from "+refc); } } @@ -1015,10 +1016,25 @@ import java.util.Objects; MemberName m = ref.clone(); // JVM will side-effect the ref assert(refKind == m.getReferenceKind()); try { + // There are 4 entities in play here: + // * LC: lookupClass + // * REFC: symbolic reference class (MN.clazz before resolution); + // * DEFC: resolved method holder (MN.clazz after resolution); + // * PTYPES: parameter types (MN.type) + // + // What we care about when resolving a MemberName is consistency between DEFC and PTYPES. + // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM + // finishes the resolution, so do TA checks right after MHN.resolve() is over. + // + // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation, + // so it is safe to call a MH from any context. + // + // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't + // participate in method selection. m = MethodHandleNatives.resolve(m, lookupClass); - m.checkForTypeAlias(); + m.checkForTypeAlias(m.getDeclaringClass()); m.resolution = null; - } catch (LinkageError ex) { + } catch (ClassNotFoundException | LinkageError ex) { // JVM reports that the "bytecode behavior" would get an error assert(!m.isResolved()); m.resolution = ex; 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 3f1bb2034a6..a108836ce51 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 @@ -33,13 +33,13 @@ import java.util.Iterator; import java.util.List; import java.util.function.Function; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import jdk.internal.vm.annotation.Stable; import sun.invoke.empty.Empty; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java index 7a5d3f1f0b2..67c197dd709 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -49,7 +49,7 @@ class MethodHandleNatives { static native void init(MemberName self, Object ref); static native void expand(MemberName self); - static native MemberName resolve(MemberName self, Class caller) throws LinkageError; + static native MemberName resolve(MemberName self, Class caller) throws LinkageError, ClassNotFoundException; static native int getMembers(Class defc, String matchName, String matchSig, int matchFlags, Class caller, int skip, MemberName[] results); 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 18ec5d6894d..09db4f93512 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 @@ -30,8 +30,8 @@ import java.security.AccessController; import java.security.PrivilegedAction; import sun.invoke.WrapperInstance; import java.util.ArrayList; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import static java.lang.invoke.MethodHandleStatics.*; 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 df1cba46fa8..4fbc1d84671 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 @@ -25,9 +25,9 @@ package java.lang.invoke; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.util.Properties; import jdk.internal.misc.Unsafe; +import sun.security.action.GetPropertyAction; /** * This class consists exclusively of static names internal to the @@ -53,32 +53,27 @@ import jdk.internal.misc.Unsafe; static final boolean VAR_HANDLE_GUARDS; static { - final Object[] values = new Object[10]; - 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", 0); - values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30); - values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); - values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); - values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127); - values[9] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.VarHandle.VAR_HANDLE_GUARDS", "true")); - return null; - } - }); - DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0]; - DUMP_CLASS_FILES = (Boolean) values[1]; - TRACE_INTERPRETER = (Boolean) values[2]; - TRACE_METHOD_LINKAGE = (Boolean) values[3]; - COMPILE_THRESHOLD = (Integer) values[4]; - DONT_INLINE_THRESHOLD = (Integer) values[5]; - PROFILE_LEVEL = (Integer) values[6]; - PROFILE_GWT = (Boolean) values[7]; - CUSTOMIZE_THRESHOLD = (Integer) values[8]; - VAR_HANDLE_GUARDS = (Boolean) values[9]; + Properties props = GetPropertyAction.getProperties(); + DEBUG_METHOD_HANDLE_NAMES = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.DEBUG_NAMES")); + DUMP_CLASS_FILES = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); + TRACE_INTERPRETER = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.TRACE_INTERPRETER")); + TRACE_METHOD_LINKAGE = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE")); + COMPILE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", "0")); + DONT_INLINE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", "30")); + PROFILE_LEVEL = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.PROFILE_LEVEL", "0")); + PROFILE_GWT = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); + CUSTOMIZE_THRESHOLD = Integer.parseInt( + props.getProperty("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", "127")); + VAR_HANDLE_GUARDS = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.VarHandle.VAR_HANDLE_GUARDS", "true")); if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) { throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range"); 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 dd6c3d0384a..5f9fc90b54d 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 @@ -28,6 +28,7 @@ package java.lang.invoke; import java.lang.reflect.*; import java.util.ArrayList; import java.util.BitSet; +import java.util.Iterator; import java.util.List; import java.util.Arrays; import java.util.Objects; @@ -37,8 +38,8 @@ import java.security.PrivilegedAction; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; import java.lang.invoke.LambdaForm.BasicType; @@ -53,6 +54,7 @@ import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; +import static java.lang.invoke.MethodType.methodType; /** * This class consists exclusively of static methods that operate on or return @@ -3000,7 +3002,7 @@ assert((int)twice.invokeExact(21) == 42); private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length]; private static MethodHandle makeIdentity(Class ptype) { - MethodType mtype = MethodType.methodType(ptype, ptype); + MethodType mtype = methodType(ptype, ptype); LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY); } @@ -3018,7 +3020,7 @@ assert((int)twice.invokeExact(21) == 42); } private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length]; private static MethodHandle makeZero(Class rtype) { - MethodType mtype = MethodType.methodType(rtype); + MethodType mtype = methodType(rtype); LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO); } @@ -3929,7 +3931,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); MethodHandle throwException(Class returnType, Class exType) { if (!Throwable.class.isAssignableFrom(exType)) throw new ClassCastException(exType.getName()); - return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType)); + return MethodHandleImpl.throwException(methodType(returnType, exType)); } /** @@ -4166,7 +4168,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); for (int i = 0; i < nclauses; ++i) { Class t = iterationVariableTypes.get(i); if (init.get(i) == null) { - init.set(i, empty(MethodType.methodType(t, commonSuffix))); + init.set(i, empty(methodType(t, commonSuffix))); } if (step.get(i) == null) { step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i)); @@ -4175,7 +4177,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence)); } if (fini.get(i) == null) { - fini.set(i, empty(MethodType.methodType(t, commonParameterSequence))); + fini.set(i, empty(methodType(t, commonParameterSequence))); } } @@ -4269,7 +4271,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) { - MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType()); + MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) : + identity(init.type().returnType()); MethodHandle[] checkExit = {null, null, pred, fin}; MethodHandle[] varBody = {init, body}; return loop(checkExit, varBody); @@ -4335,7 +4338,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) { - MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType()); + MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) : + identity(init.type().returnType()); MethodHandle[] clause = {init, body, pred, fin}; return loop(clause); } @@ -4472,8 +4476,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) { - MethodHandle returnVar = dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), - 0, int.class, int.class); + MethodHandle returnVar = dropArguments(init == null || init.type().returnType() == void.class ? + zero(void.class) : identity(init.type().returnType()), 0, int.class, int.class); MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)}; MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar}; MethodHandle[] bodyClause = {init, @@ -4485,6 +4489,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); /** * Constructs a loop that ranges over the elements produced by an {@code Iterator}. * The iterator will be produced by the evaluation of the {@code iterator} handle. + * This handle must have {@link java.util.Iterator} as its return type. * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead, * and will be applied to a leading argument of the loop handle. * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter. @@ -4534,7 +4539,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * assertEquals(reversedList, (List) loop.invoke(list)); * } *

- * @implSpec The implementation of this method is equivalent to: + * @implSpec The implementation of this method is equivalent to (excluding error handling): *

{@code
      * MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
      *     // assume MH_next and MH_hasNext are handles to methods of Iterator
@@ -4550,6 +4555,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
      * }
* * @param iterator a handle to return the iterator to start the loop. + * The handle must have {@link java.util.Iterator} as its return type. * Passing {@code null} will make the loop call {@link Iterable#iterator()} on the first * incoming value. * @param init initializer for additional loop state. This determines the loop's result type. @@ -4565,21 +4571,23 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @since 9 */ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { - checkIteratedLoop(body); + checkIteratedLoop(iterator, body); + final boolean voidInit = init == null || init.type().returnType() == void.class; MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); MethodHandle initIterator = iterator == null ? - initit.asType(initit.type().changeParameterType(0, body.type().parameterType(init == null ? 1 : 2))) : + initit.asType(initit.type().changeParameterType(0, body.type().parameterType(voidInit ? 1 : 2))) : iterator; Class itype = initIterator.type().returnType(); Class ttype = body.type().parameterType(0); MethodHandle returnVar = - dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), 0, itype); + dropArguments(voidInit ? zero(void.class) : identity(init.type().returnType()), 0, itype); MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext); MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype)); - MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), returnVar}; + MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), + returnVar}; MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)}; return loop(iterVar, bodyClause); @@ -4833,7 +4841,10 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); } } - private static void checkIteratedLoop(MethodHandle body) { + private static void checkIteratedLoop(MethodHandle iterator, MethodHandle body) { + if (null != iterator && !Iterator.class.isAssignableFrom(iterator.type().returnType())) { + throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type"); + } if (null == body) { throw newIllegalArgumentException("iterated loop body must not be null"); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 6469a4b8a6d..44f29a4a136 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -33,7 +33,6 @@ import jdk.internal.vm.annotation.ForceInline; import jdk.internal.misc.Unsafe; import java.lang.invoke.MethodHandles.Lookup; -import java.security.AccessController; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -188,14 +187,15 @@ public final class StringConcatFactory { private static final ProxyClassesDumper DUMPER; static { - final String strategy = AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat")); - CACHE_ENABLE = Boolean.parseBoolean(AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.cache"))); - DEBUG = Boolean.parseBoolean(AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.debug"))); - final String dumpPath = AccessController.doPrivileged( - new GetPropertyAction("java.lang.invoke.stringConcat.dumpClasses")); + Properties props = GetPropertyAction.getProperties(); + final String strategy = + props.getProperty("java.lang.invoke.stringConcat"); + CACHE_ENABLE = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.stringConcat.cache")); + DEBUG = Boolean.parseBoolean( + props.getProperty("java.lang.invoke.stringConcat.debug")); + final String dumpPath = + props.getProperty("java.lang.invoke.stringConcat.dumpClasses"); STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy); CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 83d8fc59aaf..1cdd12838b1 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -39,6 +39,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import sun.security.action.GetPropertyAction; /** * A finder of modules. A {@code ModuleFinder} is used to find modules during @@ -152,7 +153,7 @@ public interface ModuleFinder { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - PrivilegedAction pa = () -> System.getProperty("java.home"); + PrivilegedAction pa = new GetPropertyAction("java.home"); home = AccessController.doPrivileged(pa); Permission p = new FilePermission(home + File.separator + "-", "read"); sm.checkPermission(p); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index 5b1545dc73b..9d8e0f35c52 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -27,9 +27,9 @@ package java.lang.reflect; import java.security.AccessController; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.ReflectionFactory; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; +import jdk.internal.reflect.ReflectionFactory; import java.lang.annotation.Annotation; /** @@ -230,7 +230,7 @@ public class AccessibleObject implements AnnotatedElement { // very early in the bootstrapping process. static final ReflectionFactory reflectionFactory = AccessController.doPrivileged( - new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); + new ReflectionFactory.GetReflectionFactoryAction()); /** * @throws NullPointerException {@inheritDoc} 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 4b38728340e..af5fd1d8482 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 @@ -26,9 +26,9 @@ package java.lang.reflect; import jdk.internal.misc.SharedSecrets; -import sun.reflect.CallerSensitive; -import sun.reflect.ConstructorAccessor; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.ConstructorAccessor; +import jdk.internal.reflect.Reflection; import sun.reflect.annotation.TypeAnnotation; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.generics.repository.ConstructorRepository; 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 062676f64b7..862de42638c 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 @@ -26,9 +26,9 @@ package java.lang.reflect; import jdk.internal.misc.SharedSecrets; -import sun.reflect.CallerSensitive; -import sun.reflect.FieldAccessor; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.FieldAccessor; +import jdk.internal.reflect.Reflection; import sun.reflect.generics.repository.FieldRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; 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 005ed2453b7..6e6fab98389 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 @@ -27,9 +27,9 @@ package java.lang.reflect; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.SharedSecrets; -import sun.reflect.CallerSensitive; -import sun.reflect.MethodAccessor; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.MethodAccessor; +import jdk.internal.reflect.Reflection; import sun.reflect.generics.repository.MethodRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Modifier.java b/jdk/src/java.base/share/classes/java/lang/reflect/Modifier.java index f84a35166a9..d3875d387c2 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Modifier.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Modifier.java @@ -27,8 +27,8 @@ package java.lang.reflect; import java.security.AccessController; import java.util.StringJoiner; -import sun.reflect.LangReflectAccess; -import sun.reflect.ReflectionFactory; +import jdk.internal.reflect.LangReflectAccess; +import jdk.internal.reflect.ReflectionFactory; /** * The Modifier class provides {@code static} methods and @@ -51,8 +51,7 @@ public class Modifier { * packages */ static { - sun.reflect.ReflectionFactory factory = - AccessController.doPrivileged( + ReflectionFactory factory = AccessController.doPrivileged( new ReflectionFactory.GetReflectionFactoryAction()); factory.setLangReflectAccess(new java.lang.reflect.ReflectAccess()); } diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java index 406e3a38519..5de7394a406 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -56,8 +56,8 @@ import jdk.internal.loader.BootLoader; import jdk.internal.misc.JavaLangReflectModuleAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ServicesCatalog; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.security.util.SecurityConstants; /** diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java index ea281b137e9..8802abeda76 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -47,9 +47,10 @@ import jdk.internal.loader.BootLoader; import jdk.internal.module.Modules; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; +import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; /** @@ -581,11 +582,7 @@ public class Proxy implements java.io.Serializable { } private static final String DEBUG = - AccessController.doPrivileged(new PrivilegedAction<>() { - public String run() { - return System.getProperty("jdk.proxy.debug", ""); - } - }); + GetPropertyAction.getProperty("jdk.proxy.debug", ""); private static boolean isDebug() { return !DEBUG.isEmpty(); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 12e1723e0df..cc8dbbfffab 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -1750,7 +1750,7 @@ class ProxyGenerator { * Get or assign the index for a CONSTANT_Float entry. */ public short getFloat(float f) { - return getValue(new Float(f)); + return getValue(f); } /** diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java b/jdk/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java index 5a043930030..2a6abd3d682 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java @@ -25,14 +25,14 @@ package java.lang.reflect; -import sun.reflect.MethodAccessor; -import sun.reflect.ConstructorAccessor; +import jdk.internal.reflect.MethodAccessor; +import jdk.internal.reflect.ConstructorAccessor; /** Package-private class implementing the sun.reflect.LangReflectAccess interface, allowing the java.lang package to instantiate objects in this package. */ -class ReflectAccess implements sun.reflect.LangReflectAccess { +class ReflectAccess implements jdk.internal.reflect.LangReflectAccess { public Field newField(Class declaringClass, String name, Class type, diff --git a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 7a9b7fc17ed..debc60f74b9 100644 --- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -31,6 +31,7 @@ import sun.net.ResourceManager; import java.util.Set; import java.util.HashSet; import java.util.Collections; +import sun.security.action.GetPropertyAction; /** * Abstract datagram and multicast socket implementation base class. @@ -51,9 +52,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl protected InetAddress connectedAddress = null; private int connectedPort = -1; - private static final String os = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("os.name") - ); + private static final String os = GetPropertyAction.getProperty("os.name"); /** * flag set if the native connect() call not to be used diff --git a/jdk/src/java.base/share/classes/java/net/InetAddress.java b/jdk/src/java.base/share/classes/java/net/InetAddress.java index d385aac06e5..e79c5115413 100644 --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java @@ -894,19 +894,17 @@ class InetAddress implements java.io.Serializable { */ private static final class PlatformNameService implements NameService { - public InetAddress[] lookupAllHostAddr(String host) - throws UnknownHostException { - - return impl.lookupAllHostAddr(host); - - } - - public String getHostByAddr(byte[] addr) throws UnknownHostException { - - return impl.getHostByAddr(addr); - + public InetAddress[] lookupAllHostAddr(String host) + throws UnknownHostException + { + return impl.lookupAllHostAddr(host); } + public String getHostByAddr(byte[] addr) + throws UnknownHostException + { + return impl.getHostByAddr(addr); + } } /** @@ -991,7 +989,6 @@ class InetAddress implements java.io.Serializable { return host; } - /** *

Lookup a host mapping by name. Retrieve the IP addresses * associated with a host. @@ -1004,7 +1001,6 @@ class InetAddress implements java.io.Serializable { * @throws UnknownHostException * if no IP address for the {@code host} could be found */ - public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException { String hostEntry; @@ -1127,8 +1123,8 @@ class InetAddress implements java.io.Serializable { */ private static NameService createNameService() { - String hostsFileName = AccessController - .doPrivileged(new GetPropertyAction("jdk.net.hosts.file")); + String hostsFileName = + GetPropertyAction.getProperty("jdk.net.hosts.file"); NameService theNameService; if (hostsFileName != null) { theNameService = new HostsFileNameService(hostsFileName); @@ -1647,8 +1643,7 @@ class InetAddress implements java.io.Serializable { * property can vary across implementations of the java. * classes. The default is an empty String "". */ - String prefix = AccessController.doPrivileged( - new GetPropertyAction("impl.prefix", "")); + String prefix = GetPropertyAction.getProperty("impl.prefix", ""); try { impl = Class.forName("java.net." + prefix + implName).newInstance(); } catch (ClassNotFoundException e) { diff --git a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java index f7974d0d705..c3a0d1c675a 100644 --- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java @@ -33,6 +33,7 @@ import java.security.PrivilegedExceptionAction; import sun.net.SocksProxy; import sun.net.spi.DefaultProxySelector; import sun.net.www.ParseUtil; +import sun.security.action.GetPropertyAction; /* import org.ietf.jgss.*; */ /** @@ -177,8 +178,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { userName = pw.getUserName(); password = new String(pw.getPassword()); } else { - userName = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("user.name")); + userName = GetPropertyAction.getProperty("user.name"); } if (userName == null) return false; @@ -1088,8 +1088,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { userName = System.getProperty("user.name"); } catch (SecurityException se) { /* swallow Exception */ } } else { - userName = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("user.name")); + userName = GetPropertyAction.getProperty("user.name"); } return userName; } diff --git a/jdk/src/java.base/share/classes/java/net/URL.java b/jdk/src/java.base/share/classes/java/net/URL.java index cce9cf9425a..099e8b9e0c8 100644 --- a/jdk/src/java.base/share/classes/java/net/URL.java +++ b/jdk/src/java.base/share/classes/java/net/URL.java @@ -42,6 +42,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import sun.security.util.SecurityConstants; +import sun.security.action.GetPropertyAction; /** * Class {@code URL} represents a Uniform Resource @@ -1210,12 +1211,8 @@ public final class URL implements java.io.Serializable { } private static URLStreamHandler lookupViaProperty(String protocol) { - String packagePrefixList = java.security.AccessController.doPrivileged( - new PrivilegedAction<>() { - public String run() { - return System.getProperty(protocolPathProp, null); - } - }); + String packagePrefixList = + GetPropertyAction.getProperty(protocolPathProp); if (packagePrefixList == null) { // not set return null; diff --git a/jdk/src/java.base/share/classes/java/net/URLConnection.java b/jdk/src/java.base/share/classes/java/net/URLConnection.java index 87f4378b2ad..459a820bcde 100644 --- a/jdk/src/java.base/share/classes/java/net/URLConnection.java +++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java @@ -43,6 +43,7 @@ import java.security.Permission; import java.security.AccessController; import sun.security.util.SecurityConstants; import sun.net.www.MessageHeader; +import sun.security.action.GetPropertyAction; /** * The abstract class {@code URLConnection} is the superclass @@ -1395,8 +1396,8 @@ public abstract class URLConnection { * is always the last one on the returned package list. */ private String getContentHandlerPkgPrefixes() { - String packagePrefixList = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction(contentPathProp, "")); + String packagePrefixList = + GetPropertyAction.getProperty(contentPathProp, ""); if (packagePrefixList != "") { packagePrefixList += "|"; diff --git a/jdk/src/java.base/share/classes/java/net/URLEncoder.java b/jdk/src/java.base/share/classes/java/net/URLEncoder.java index 5ad817bc72c..2f2c3e6c9c4 100644 --- a/jdk/src/java.base/share/classes/java/net/URLEncoder.java +++ b/jdk/src/java.base/share/classes/java/net/URLEncoder.java @@ -25,19 +25,12 @@ package java.net; -import java.io.ByteArrayOutputStream; -import java.io.BufferedWriter; -import java.io.OutputStreamWriter; -import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.CharArrayWriter; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; /** @@ -140,9 +133,7 @@ public class URLEncoder { dontNeedEncoding.set('.'); dontNeedEncoding.set('*'); - dfltEncName = AccessController.doPrivileged( - new GetPropertyAction("file.encoding") - ); + dfltEncName = GetPropertyAction.getProperty("file.encoding"); } /** diff --git a/jdk/src/java.base/share/classes/java/net/URLPermission.java b/jdk/src/java.base/share/classes/java/net/URLPermission.java index 78373e1087f..e188c81d73b 100644 --- a/jdk/src/java.base/share/classes/java/net/URLPermission.java +++ b/jdk/src/java.base/share/classes/java/net/URLPermission.java @@ -170,7 +170,8 @@ public final class URLPermission extends Permission { parseURI(getName()); int colon = actions.indexOf(':'); if (actions.lastIndexOf(':') != colon) { - throw new IllegalArgumentException("invalid actions string"); + throw new IllegalArgumentException( + "Invalid actions string: \"" + actions + "\""); } String methods, headers; @@ -371,7 +372,8 @@ public final class URLPermission extends Permission { l.add(s); b = new StringBuilder(); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in methods: \"" + methods + "\""); } else { if (c >= 'a' && c <= 'z') { c += 'A' - 'a'; @@ -398,7 +400,8 @@ public final class URLPermission extends Permission { } b.append(c); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in headers: \"" + headers + "\""); } else if (c == '-') { capitalizeNext = true; b.append(c); @@ -423,14 +426,16 @@ public final class URLPermission extends Permission { int len = url.length(); int delim = url.indexOf(':'); if (delim == -1 || delim + 1 == len) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } scheme = url.substring(0, delim).toLowerCase(); this.ssp = url.substring(delim + 1); if (!ssp.startsWith("//")) { if (!ssp.equals("*")) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } this.authority = new Authority(scheme, "*"); return; diff --git a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java index 78ee33e764a..de49a8c6271 100644 --- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java @@ -283,8 +283,8 @@ public abstract class Charset if (level == null) { if (!VM.isBooted()) return false; - bugLevel = level = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.cs.bugLevel", "")); + bugLevel = level = + GetPropertyAction.getProperty("sun.nio.cs.bugLevel", ""); } return level.equals(bl); } @@ -609,8 +609,7 @@ public abstract class Charset public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { - String csn = AccessController.doPrivileged( - new GetPropertyAction("file.encoding")); + String csn = GetPropertyAction.getProperty("file.encoding"); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; diff --git a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java index 2bc3d992c60..a6af1a15b1f 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java +++ b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java @@ -28,7 +28,6 @@ package java.nio.file; import java.util.Set; import java.util.EnumSet; import java.security.SecureRandom; -import static java.security.AccessController.*; import java.io.IOException; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; @@ -47,7 +46,7 @@ class TempFileHelper { // temporary directory location private static final Path tmpdir = - Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + Paths.get(GetPropertyAction.getProperty("java.io.tmpdir")); private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); diff --git a/jdk/src/java.base/share/classes/java/security/AccessController.java b/jdk/src/java.base/share/classes/java/security/AccessController.java index 90503d29cf8..b37b476efdd 100644 --- a/jdk/src/java.base/share/classes/java/security/AccessController.java +++ b/jdk/src/java.base/share/classes/java/security/AccessController.java @@ -26,8 +26,8 @@ package java.security; import sun.security.util.Debug; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** *

The AccessController class is used for access control operations diff --git a/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java b/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java index 8355dee87d4..98c66365c1b 100644 --- a/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/jdk/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -437,7 +437,7 @@ public class ChoiceFormat extends NumberFormat { if (status.index == start) { status.errorIndex = furthest; } - return new Double(bestNumber); + return Double.valueOf(bestNumber); } /** diff --git a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java index a82011fd7d5..587a64e13f1 100644 --- a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1996,7 +1996,7 @@ public class DecimalFormat extends NumberFormat { // special case NaN if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { pos.index = pos.index + symbols.getNaN().length(); - return new Double(Double.NaN); + return Double.valueOf(Double.NaN); } boolean[] status = new boolean[STATUS_LENGTH]; @@ -2007,19 +2007,19 @@ public class DecimalFormat extends NumberFormat { // special case INFINITY if (status[STATUS_INFINITE]) { if (status[STATUS_POSITIVE] == (multiplier >= 0)) { - return new Double(Double.POSITIVE_INFINITY); + return Double.valueOf(Double.POSITIVE_INFINITY); } else { - return new Double(Double.NEGATIVE_INFINITY); + return Double.valueOf(Double.NEGATIVE_INFINITY); } } if (multiplier == 0) { if (digitList.isZero()) { - return new Double(Double.NaN); + return Double.valueOf(Double.NaN); } else if (status[STATUS_POSITIVE]) { - return new Double(Double.POSITIVE_INFINITY); + return Double.valueOf(Double.POSITIVE_INFINITY); } else { - return new Double(Double.NEGATIVE_INFINITY); + return Double.valueOf(Double.NEGATIVE_INFINITY); } } @@ -2093,8 +2093,8 @@ public class DecimalFormat extends NumberFormat { !isParseIntegerOnly(); } - return gotDouble ? - (Number)new Double(doubleResult) : (Number)Long.valueOf(longResult); + // cast inside of ?: because of binary numeric promotion, JLS 15.25 + return gotDouble ? (Number)doubleResult : (Number)longResult; } } diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index d7baf69c5b5..c77a8c5f888 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1539,8 +1539,8 @@ public final class DateTimeFormatterBuilder { *

      *  Pattern  Count  Equivalent builder methods
      *  -------  -----  --------------------------
-     *    O       1      appendLocalizedOffsetPrefixed(TextStyle.SHORT);
-     *    OOOO    4      appendLocalizedOffsetPrefixed(TextStyle.FULL);
+     *    O       1      appendLocalizedOffset(TextStyle.SHORT);
+     *    OOOO    4      appendLocalizedOffset(TextStyle.FULL);
      *    X       1      appendOffset("+HHmm","Z")
      *    XX      2      appendOffset("+HHMM","Z")
      *    XXX     3      appendOffset("+HH:MM","Z")
@@ -3519,9 +3519,7 @@ public final class DateTimeFormatterBuilder {
                 return false;
             }
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                buf.append(gmtText);
-            }
+            buf.append(gmtText);
             int totalSecs = Math.toIntExact(offsetSecs);
             if (totalSecs != 0) {
                 int absHours = Math.abs((totalSecs / 3600) % 100);  // anything larger than 99 silently dropped
@@ -3565,14 +3563,12 @@ public final class DateTimeFormatterBuilder {
         @Override
         public int parse(DateTimeParseContext context, CharSequence text, int position) {
             int pos = position;
-            int end = pos + text.length();
+            int end = text.length();
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
+            if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
                     return ~position;
                 }
-                pos += gmtText.length();
-            }
+            pos += gmtText.length();
             // parse normal plus/minus offset
             int negative = 0;
             if (pos == end) {
diff --git a/jdk/src/java.base/share/classes/java/util/Locale.java b/jdk/src/java.base/share/classes/java/util/Locale.java
index 2d121e2e7ef..e05904f6f6b 100644
--- a/jdk/src/java.base/share/classes/java/util/Locale.java
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java
@@ -45,7 +45,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamField;
 import java.io.Serializable;
-import java.security.AccessController;
 import java.text.MessageFormat;
 import java.util.spi.LocaleNameProvider;
 
@@ -859,11 +858,10 @@ public final class Locale implements Cloneable, Serializable {
 
     private static Locale initDefault() {
         String language, region, script, country, variant;
-        language = AccessController.doPrivileged(
-            new GetPropertyAction("user.language", "en"));
+        Properties props = GetPropertyAction.getProperties();
+        language = props.getProperty("user.language", "en");
         // for compatibility, check for old user.region property
-        region = AccessController.doPrivileged(
-            new GetPropertyAction("user.region"));
+        region = props.getProperty("user.region");
         if (region != null) {
             // region can be of form country, country_variant, or _variant
             int i = region.indexOf('_');
@@ -876,27 +874,25 @@ public final class Locale implements Cloneable, Serializable {
             }
             script = "";
         } else {
-            script = AccessController.doPrivileged(
-                new GetPropertyAction("user.script", ""));
-            country = AccessController.doPrivileged(
-                new GetPropertyAction("user.country", ""));
-            variant = AccessController.doPrivileged(
-                new GetPropertyAction("user.variant", ""));
+            script = props.getProperty("user.script", "");
+            country = props.getProperty("user.country", "");
+            variant = props.getProperty("user.variant", "");
         }
 
         return getInstance(language, script, country, variant, null);
     }
 
     private static Locale initDefault(Locale.Category category) {
+        Properties props = GetPropertyAction.getProperties();
         return getInstance(
-            AccessController.doPrivileged(
-                new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
-            AccessController.doPrivileged(
-                new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
-            AccessController.doPrivileged(
-                new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
-            AccessController.doPrivileged(
-                new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
+            props.getProperty(category.languageKey,
+                    defaultLocale.getLanguage()),
+            props.getProperty(category.scriptKey,
+                    defaultLocale.getScript()),
+            props.getProperty(category.countryKey,
+                    defaultLocale.getCountry()),
+            props.getProperty(category.variantKey,
+                    defaultLocale.getVariant()),
             null);
     }
 
diff --git a/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java b/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java
index 58ff7570269..9c20a680733 100644
--- a/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java
+++ b/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java
@@ -43,7 +43,6 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.IOException;
-import java.nio.charset.Charset;
 import java.nio.charset.MalformedInputException;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnmappableCharacterException;
@@ -142,8 +141,8 @@ public class PropertyResourceBundle extends ResourceBundle {
     // Check whether the strict encoding is specified.
     // The possible encoding is either "ISO-8859-1" or "UTF-8".
     private static final String encoding =
-        AccessController.doPrivileged(
-            new GetPropertyAction("java.util.PropertyResourceBundle.encoding", ""))
+        GetPropertyAction
+                .getProperty("java.util.PropertyResourceBundle.encoding", "")
         .toUpperCase(Locale.ROOT);
 
     /**
diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
index 80f7738cde3..4ce2b50720a 100644
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -64,8 +64,8 @@ import java.util.spi.ResourceBundleProvider;
 
 import jdk.internal.misc.JavaUtilResourceBundleAccess;
 import jdk.internal.misc.SharedSecrets;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
 import sun.util.locale.provider.ResourceBundleProviderSupport;
diff --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
index 8d38e785709..7ccce279357 100644
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
@@ -51,8 +51,8 @@ import jdk.internal.misc.VM;
 import jdk.internal.module.ServicesCatalog;
 import jdk.internal.module.ServicesCatalog.ServiceProvider;
 
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 
 
 /**
diff --git a/jdk/src/java.base/share/classes/java/util/TimeZone.java b/jdk/src/java.base/share/classes/java/util/TimeZone.java
index 3bf886b2721..22c382cb0a2 100644
--- a/jdk/src/java.base/share/classes/java/util/TimeZone.java
+++ b/jdk/src/java.base/share/classes/java/util/TimeZone.java
@@ -660,14 +660,12 @@ public abstract class TimeZone implements Serializable, Cloneable {
     private static synchronized TimeZone setDefaultZone() {
         TimeZone tz;
         // get the time zone ID from the system properties
-        String zoneID = AccessController.doPrivileged(
-                new GetPropertyAction("user.timezone"));
+        String zoneID = GetPropertyAction.getProperty("user.timezone");
 
         // if the time zone ID is not set (yet), perform the
         // platform to Java time zone ID mapping.
         if (zoneID == null || zoneID.isEmpty()) {
-            String javaHome = AccessController.doPrivileged(
-                    new GetPropertyAction("java.home"));
+            String javaHome = GetPropertyAction.getProperty("java.home");
             try {
                 zoneID = getSystemTimeZoneID(javaHome);
                 if (zoneID == null) {
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
index 69ecc46cf6d..2af74b20961 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
@@ -455,7 +455,7 @@ public class ThreadLocalRandom extends Random {
             s = v1 * v1 + v2 * v2;
         } while (s >= 1 || s == 0);
         double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
-        nextLocalGaussian.set(new Double(v2 * multiplier));
+        nextLocalGaussian.set(Double.valueOf(v2 * multiplier));
         return v1 * multiplier;
     }
 
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index 09b372dc822..10ee364b5b9 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -42,8 +42,8 @@ import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 
 /**
  * A reflection-based utility that enables atomic updates to
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 8770b2d962a..c3ad0afff21 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -42,8 +42,8 @@ import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 
 /**
  * A reflection-based utility that enables atomic updates to
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index b30341f73f9..f6dbbe36479 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -42,8 +42,8 @@ import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 
 /**
  * A reflection-based utility that enables atomic updates to
diff --git a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
index f28750c3a97..ff26faad4f4 100644
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
@@ -34,7 +34,6 @@ import java.util.stream.StreamSupport;
 import java.util.zip.*;
 import java.security.CodeSigner;
 import java.security.cert.Certificate;
-import java.security.AccessController;
 import java.security.CodeSource;
 import jdk.internal.misc.SharedSecrets;
 import sun.security.action.GetPropertyAction;
@@ -155,16 +154,16 @@ class JarFile extends ZipFile {
 
         BASE_VERSION = 8;  // one less than lowest version for versioned entries
         int runtimeVersion = jdk.Version.current().major();
-        String jarVersion = AccessController.doPrivileged(
-                new GetPropertyAction("jdk.util.jar.version"));
+        String jarVersion =
+                GetPropertyAction.getProperty("jdk.util.jar.version");
         if (jarVersion != null) {
             int jarVer = Integer.parseInt(jarVersion);
             runtimeVersion = (jarVer > runtimeVersion)
                     ? runtimeVersion : Math.max(jarVer, 0);
         }
         RUNTIME_VERSION = runtimeVersion;
-        String enableMultiRelease = AccessController.doPrivileged(
-                new GetPropertyAction("jdk.util.jar.enableMultiRelease", "true"));
+        String enableMultiRelease = GetPropertyAction
+                .getProperty("jdk.util.jar.enableMultiRelease", "true");
         switch (enableMultiRelease) {
             case "true":
             default:
diff --git a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java
index 44f1cccd080..ac47ad12032 100644
--- a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java
+++ b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java
@@ -29,6 +29,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.File;
 import java.io.IOException;
+import sun.security.action.GetPropertyAction;
 
 
 /**
@@ -694,8 +695,7 @@ public abstract class Pack200 {
             Class impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
             if (impl == null) {
                 // The first time, we must decide which class to use.
-                implName = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction(prop,""));
+                implName = GetPropertyAction.getProperty(prop,"");
                 if (implName != null && !implName.equals(""))
                     impl = Class.forName(implName);
                 else if (PACK_PROVIDER.equals(prop))
diff --git a/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java b/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java
index 94d7abc78a5..f7768da27da 100644
--- a/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java
+++ b/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java
@@ -94,8 +94,7 @@ public class PatternSyntaxException
     }
 
     private static final String nl =
-        java.security.AccessController
-            .doPrivileged(new GetPropertyAction("line.separator"));
+            GetPropertyAction.getProperty("line.separator");
 
     /**
      * Returns a multi-line string containing the description of the syntax
diff --git a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
index 6b480aa1d5e..ff76017651b 100644
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
@@ -33,6 +33,7 @@ import java.util.Vector;
 import java.util.HashSet;
 import static java.util.zip.ZipConstants64.*;
 import static java.util.zip.ZipUtils.*;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This class implements an output stream filter for writing files in the
@@ -54,9 +55,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
      */
     private static final boolean inhibitZip64 =
         Boolean.parseBoolean(
-            java.security.AccessController.doPrivileged(
-                new sun.security.action.GetPropertyAction(
-                    "jdk.util.zip.inhibitZip64", "false")));
+            GetPropertyAction.getProperty("jdk.util.zip.inhibitZip64"));
 
     private static class XEntry {
         final ZipEntry entry;
diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java
index 316016aac35..b436414308f 100644
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java
@@ -51,9 +51,9 @@ public abstract class SSLSocketFactory extends SocketFactory
     static final boolean DEBUG;
 
     static {
-        String s = java.security.AccessController.doPrivileged(
-            new GetPropertyAction("javax.net.debug", "")).toLowerCase(
-                                                            Locale.ENGLISH);
+        String s = GetPropertyAction.getProperty("javax.net.debug", "")
+                .toLowerCase(Locale.ENGLISH);
+
         DEBUG = s.contains("all") || s.contains("ssl");
     }
 
diff --git a/jdk/src/java.base/share/classes/jdk/Version.java b/jdk/src/java.base/share/classes/jdk/Version.java
index 75c6b35c444..756af9ec051 100644
--- a/jdk/src/java.base/share/classes/jdk/Version.java
+++ b/jdk/src/java.base/share/classes/jdk/Version.java
@@ -26,8 +26,6 @@
 package jdk;
 
 import java.math.BigInteger;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -35,6 +33,7 @@ import java.util.stream.Collectors;
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
+import sun.security.action.GetPropertyAction;
 
 /**
  * A representation of the JDK version-string which contains a version
@@ -274,12 +273,7 @@ public final class Version
      */
     public static Version current() {
         if (current == null) {
-            current = parse(AccessController.doPrivileged(
-                new PrivilegedAction<>() {
-                    public String run() {
-                        return System.getProperty("java.version");
-                    }
-                }));
+            current = parse(GetPropertyAction.getProperty("java.version"));
         }
         return current;
     }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java
index cb64fb088c0..41a51b88acf 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java
@@ -136,7 +136,7 @@ public class ImageReader extends BasicImageReader {
         private final BasicFileAttributes fileAttrs;
         private boolean completed;
 
-        Node(String name, BasicFileAttributes fileAttrs) {
+        protected Node(String name, BasicFileAttributes fileAttrs) {
             this.name = Objects.requireNonNull(name);
             this.fileAttrs = Objects.requireNonNull(fileAttrs);
         }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java
deleted file mode 100644
index ab7bd29ac06..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jrtfs;
-
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Formatter;
-
-/**
- * Base class for file attributes supported by jrt file systems.
- *
- * @implNote This class needs to maintain JDK 8 source compatibility.
- *
- * It is used internally in the JDK to implement jimage/jrtfs access,
- * but also compiled and delivered as part of the jrtfs.jar to support access
- * to the jimage file provided by the shipped JDK by tools running on JDK 8.
- */
-public abstract class AbstractJrtFileAttributes implements BasicFileAttributes {
-
-    // jrt fs specific attributes
-    /**
-     * Compressed resource file. If not available or not applicable, 0L is
-     * returned.
-     *
-     * @return the compressed resource size for compressed resources.
-     */
-    public abstract long compressedSize();
-
-    /**
-     * "file" extension of a file resource.
-     *
-     * @return extension string for the file resource
-     */
-    public abstract String extension();
-
-    @Override
-    public final String toString() {
-        StringBuilder sb = new StringBuilder(1024);
-        try (Formatter fm = new Formatter(sb)) {
-            if (creationTime() != null) {
-                fm.format("    creationTime    : %tc%n", creationTime().toMillis());
-            } else {
-                fm.format("    creationTime    : null%n");
-            }
-
-            if (lastAccessTime() != null) {
-                fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
-            } else {
-                fm.format("    lastAccessTime  : null%n");
-            }
-            fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
-            fm.format("    isRegularFile   : %b%n", isRegularFile());
-            fm.format("    isDirectory     : %b%n", isDirectory());
-            fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
-            fm.format("    isOther         : %b%n", isOther());
-            fm.format("    fileKey         : %s%n", fileKey());
-            fm.format("    size            : %d%n", size());
-            fm.format("    compressedSize  : %d%n", compressedSize());
-            fm.format("    extension       : %s%n", extension());
-        }
-        return sb.toString();
-    }
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java
deleted file mode 100644
index 42004e6e9c9..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jrtfs;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.nio.channels.NonWritableChannelException;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.SeekableByteChannel;
-import java.nio.charset.Charset;
-import java.nio.file.ClosedFileSystemException;
-import java.nio.file.CopyOption;
-import java.nio.file.FileStore;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.OpenOption;
-import java.nio.file.Path;
-import java.nio.file.PathMatcher;
-import java.nio.file.ReadOnlyFileSystemException;
-import java.nio.file.StandardOpenOption;
-import java.nio.file.WatchService;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.UserPrincipalLookupService;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-/**
- * Base class for jrt file systems. jrt filesystem implementations are currently
- * available on top of .jimage file and on top "exploded" build directories.
- *
- * @implNote This class needs to maintain JDK 8 source compatibility.
- *
- * It is used internally in the JDK to implement jimage/jrtfs access,
- * but also compiled and delivered as part of the jrtfs.jar to support access
- * to the jimage file provided by the shipped JDK by tools running on JDK 8.
- */
-abstract class AbstractJrtFileSystem extends FileSystem {
-
-    private final JrtFileSystemProvider provider;
-
-    AbstractJrtFileSystem(JrtFileSystemProvider provider, Map options) {
-        this.provider = provider;
-    }
-
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
-
-    // static utility methods
-    static ReadOnlyFileSystemException readOnly() {
-        return new ReadOnlyFileSystemException();
-    }
-
-    // if a Path does not exist, throw exception
-    static void checkExists(Path path) {
-        if (Files.notExists(path)) {
-            throw new FileSystemNotFoundException(path.toString());
-        }
-    }
-
-    static byte[] getBytes(String name) {
-        return name.getBytes(UTF_8);
-    }
-
-    static String getString(byte[] name) {
-        return new String(name, UTF_8);
-    }
-
-    // do the supplied options imply that we have to chase symlinks?
-    static boolean followLinks(LinkOption... options) {
-        if (options != null) {
-            for (LinkOption lo : options) {
-                if (lo == LinkOption.NOFOLLOW_LINKS) {
-                    return false;
-                } else if (lo == null) {
-                    throw new NullPointerException();
-                } else {
-                    throw new AssertionError("should not reach here");
-                }
-            }
-        }
-        return true;
-    }
-
-    // check that the options passed are supported by (read-only) jrt file system
-    static void checkOptions(Set options) {
-        // check for options of null type and option is an intance of StandardOpenOption
-        for (OpenOption option : options) {
-            if (option == null) {
-                throw new NullPointerException();
-            }
-            if (!(option instanceof StandardOpenOption)) {
-                throw new IllegalArgumentException();
-            }
-        }
-
-        if (options.contains(StandardOpenOption.WRITE)
-                || options.contains(StandardOpenOption.APPEND)) {
-            throw readOnly();
-        }
-    }
-
-    // FileSystem method implementations
-    @Override
-    public FileSystemProvider provider() {
-        return provider;
-    }
-
-    @Override
-    public Iterable getRootDirectories() {
-        ArrayList pathArr = new ArrayList<>();
-        pathArr.add(getRootPath());
-        return pathArr;
-    }
-
-    @Override
-    public AbstractJrtPath getPath(String first, String... more) {
-        String path;
-        if (more.length == 0) {
-            path = first;
-        } else {
-            StringBuilder sb = new StringBuilder();
-            sb.append(first);
-            for (String segment : more) {
-                if (segment.length() > 0) {
-                    if (sb.length() > 0) {
-                        sb.append('/');
-                    }
-                    sb.append(segment);
-                }
-            }
-            path = sb.toString();
-        }
-        return getRootPath().newJrtPath(getBytes(path));
-    }
-
-    @Override
-    public final boolean isReadOnly() {
-        return true;
-    }
-
-    @Override
-    public final UserPrincipalLookupService getUserPrincipalLookupService() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public final WatchService newWatchService() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public final Iterable getFileStores() {
-        ArrayList list = new ArrayList<>(1);
-        list.add(getFileStore(getRootPath()));
-        return list;
-    }
-
-    private static final Set supportedFileAttributeViews
-            = Collections.unmodifiableSet(
-                    new HashSet(Arrays.asList("basic", "jrt")));
-
-    @Override
-    public final Set supportedFileAttributeViews() {
-        return supportedFileAttributeViews;
-    }
-
-    @Override
-    public final String toString() {
-        return "jrt:/";
-    }
-
-    @Override
-    public final String getSeparator() {
-        return "/";
-    }
-
-    private static final String GLOB_SYNTAX = "glob";
-    private static final String REGEX_SYNTAX = "regex";
-
-    @Override
-    public PathMatcher getPathMatcher(String syntaxAndInput) {
-        int pos = syntaxAndInput.indexOf(':');
-        if (pos <= 0 || pos == syntaxAndInput.length()) {
-            throw new IllegalArgumentException();
-        }
-        String syntax = syntaxAndInput.substring(0, pos);
-        String input = syntaxAndInput.substring(pos + 1);
-        String expr;
-        if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
-            expr = JrtUtils.toRegexPattern(input);
-        } else {
-            if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
-                expr = input;
-            } else {
-                throw new UnsupportedOperationException("Syntax '" + syntax
-                        + "' not recognized");
-            }
-        }
-        // return matcher
-        final Pattern pattern = Pattern.compile(expr);
-        return (Path path) -> pattern.matcher(path.toString()).matches();
-    }
-
-    // These methods throw read only file system exception
-    final void setTimes(AbstractJrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
-            throws IOException {
-        throw readOnly();
-    }
-
-    final void createDirectory(AbstractJrtPath jrtPath, FileAttribute... attrs) throws IOException {
-        throw readOnly();
-    }
-
-    final void deleteFile(AbstractJrtPath jrtPath, boolean failIfNotExists)
-            throws IOException {
-        throw readOnly();
-    }
-
-    final OutputStream newOutputStream(AbstractJrtPath jrtPath, OpenOption... options)
-            throws IOException {
-        throw readOnly();
-    }
-
-    final void copyFile(boolean deletesrc, AbstractJrtPath srcPath, AbstractJrtPath dstPath, CopyOption... options)
-            throws IOException {
-        throw readOnly();
-    }
-
-    final FileChannel newFileChannel(AbstractJrtPath jrtPath,
-            Set options,
-            FileAttribute... attrs)
-            throws IOException {
-        throw new UnsupportedOperationException("newFileChannel");
-    }
-
-    final InputStream newInputStream(AbstractJrtPath jrtPath) throws IOException {
-        return new ByteArrayInputStream(getFileContent(jrtPath));
-    }
-
-    final SeekableByteChannel newByteChannel(AbstractJrtPath jrtPath,
-            Set options,
-            FileAttribute... attrs)
-            throws IOException {
-        checkOptions(options);
-
-        byte[] buf = getFileContent(jrtPath);
-        final ReadableByteChannel rbc
-                = Channels.newChannel(new ByteArrayInputStream(buf));
-        final long size = buf.length;
-        return new SeekableByteChannel() {
-            long read = 0;
-
-            @Override
-            public boolean isOpen() {
-                return rbc.isOpen();
-            }
-
-            @Override
-            public long position() throws IOException {
-                return read;
-            }
-
-            @Override
-            public SeekableByteChannel position(long pos)
-                    throws IOException {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public int read(ByteBuffer dst) throws IOException {
-                int n = rbc.read(dst);
-                if (n > 0) {
-                    read += n;
-                }
-                return n;
-            }
-
-            @Override
-            public SeekableByteChannel truncate(long size)
-                    throws IOException {
-                throw new NonWritableChannelException();
-            }
-
-            @Override
-            public int write(ByteBuffer src) throws IOException {
-                throw new NonWritableChannelException();
-            }
-
-            @Override
-            public long size() throws IOException {
-                return size;
-            }
-
-            @Override
-            public void close() throws IOException {
-                rbc.close();
-            }
-        };
-    }
-
-    final JrtFileStore getFileStore(AbstractJrtPath jrtPath) {
-        return new JrtFileStore(jrtPath);
-    }
-
-    final void ensureOpen() throws IOException {
-        if (!isOpen()) {
-            throw new ClosedFileSystemException();
-        }
-    }
-
-    // abstract methods to be implemented by a particular jrt file system
-    abstract AbstractJrtPath getRootPath();
-
-    abstract boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException;
-
-    abstract boolean isLink(AbstractJrtPath jrtPath) throws IOException;
-
-    abstract AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException;
-
-    abstract AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException;
-
-    abstract boolean exists(AbstractJrtPath jrtPath) throws IOException;
-
-    abstract boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException;
-
-    /**
-     * returns the list of child paths of the given directory "path"
-     *
-     * @param path name of the directory whose content is listed
-     * @return iterator for child paths of the given directory path
-     */
-    abstract Iterator iteratorOf(AbstractJrtPath jrtPath) throws IOException;
-
-    // returns the content of the file resource specified by the path
-    abstract byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException;
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java
deleted file mode 100644
index 8e939a0c5d0..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jrtfs;
-
-import java.io.*;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.channels.*;
-import java.nio.file.*;
-import java.nio.file.DirectoryStream.Filter;
-import java.nio.file.attribute.*;
-import java.util.*;
-import static java.nio.file.StandardOpenOption.*;
-import static java.nio.file.StandardCopyOption.*;
-
-/**
- * Base class for Path implementation of jrt file systems.
- *
- * @implNote This class needs to maintain JDK 8 source compatibility.
- *
- * It is used internally in the JDK to implement jimage/jrtfs access,
- * but also compiled and delivered as part of the jrtfs.jar to support access
- * to the jimage file provided by the shipped JDK by tools running on JDK 8.
- */
-abstract class AbstractJrtPath implements Path {
-
-    protected final AbstractJrtFileSystem jrtfs;
-    private final byte[] path;
-    private volatile int[] offsets;
-    private int hashcode = 0;  // cached hashcode (created lazily)
-
-    AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path) {
-        this(jrtfs, path, false);
-        this.resolved = null;
-    }
-
-    AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) {
-        this.resolved = null;
-        this.jrtfs = jrtfs;
-        if (normalized) {
-            this.path = path;
-        } else {
-            this.path = normalize(path);
-        }
-    }
-
-    // factory methods to create subtypes of AbstractJrtPath
-    protected abstract AbstractJrtPath newJrtPath(byte[] path);
-
-    protected abstract AbstractJrtPath newJrtPath(byte[] path, boolean normalized);
-
-    final byte[] getName() {
-        return path;
-    }
-
-    @Override
-    public final AbstractJrtPath getRoot() {
-        if (this.isAbsolute()) {
-            return jrtfs.getRootPath();
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public final AbstractJrtPath getFileName() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0) {
-            return null;  // no elements so no name
-        }
-        if (count == 1 && path[0] != '/') {
-            return this;
-        }
-        int lastOffset = offsets[count - 1];
-        int len = path.length - lastOffset;
-        byte[] result = new byte[len];
-        System.arraycopy(path, lastOffset, result, 0, len);
-        return newJrtPath(result);
-    }
-
-    @Override
-    public final AbstractJrtPath getParent() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0) // no elements so no parent
-        {
-            return null;
-        }
-        int len = offsets[count - 1] - 1;
-        if (len <= 0) // parent is root only (may be null)
-        {
-            return getRoot();
-        }
-        byte[] result = new byte[len];
-        System.arraycopy(path, 0, result, 0, len);
-        return newJrtPath(result);
-    }
-
-    @Override
-    public final int getNameCount() {
-        initOffsets();
-        return offsets.length;
-    }
-
-    @Override
-    public final AbstractJrtPath getName(int index) {
-        initOffsets();
-        if (index < 0 || index >= offsets.length) {
-            throw new IllegalArgumentException();
-        }
-        int begin = offsets[index];
-        int len;
-        if (index == (offsets.length - 1)) {
-            len = path.length - begin;
-        } else {
-            len = offsets[index + 1] - begin - 1;
-        }
-        // construct result
-        byte[] result = new byte[len];
-        System.arraycopy(path, begin, result, 0, len);
-        return newJrtPath(result);
-    }
-
-    @Override
-    public final AbstractJrtPath subpath(int beginIndex, int endIndex) {
-        initOffsets();
-        if (beginIndex < 0
-                || beginIndex >= offsets.length
-                || endIndex > offsets.length
-                || beginIndex >= endIndex) {
-            throw new IllegalArgumentException();
-        }
-
-        // starting offset and length
-        int begin = offsets[beginIndex];
-        int len;
-        if (endIndex == offsets.length) {
-            len = path.length - begin;
-        } else {
-            len = offsets[endIndex] - begin - 1;
-        }
-        // construct result
-        byte[] result = new byte[len];
-        System.arraycopy(path, begin, result, 0, len);
-        return newJrtPath(result);
-    }
-
-    @Override
-    public final AbstractJrtPath toRealPath(LinkOption... options) throws IOException {
-        AbstractJrtPath realPath = newJrtPath(getResolvedPath()).toAbsolutePath();
-        realPath = JrtFileSystem.followLinks(options) ? jrtfs.resolveLink(this) : realPath;
-        realPath.checkAccess();
-        return realPath;
-    }
-
-    final AbstractJrtPath readSymbolicLink() throws IOException {
-        if (!jrtfs.isLink(this)) {
-            throw new IOException("not a symbolic link");
-        }
-
-        return jrtfs.resolveLink(this);
-    }
-
-    final boolean isHidden() {
-        return false;
-    }
-
-    @Override
-    public final AbstractJrtPath toAbsolutePath() {
-        if (isAbsolute()) {
-            return this;
-        } else {
-            //add / bofore the existing path
-            byte[] tmp = new byte[path.length + 1];
-            tmp[0] = '/';
-            System.arraycopy(path, 0, tmp, 1, path.length);
-            return newJrtPath(tmp).normalize();
-        }
-    }
-
-    @Override
-    public final URI toUri() {
-        try {
-            return new URI("jrt",
-                    JrtFileSystem.getString(toAbsolutePath().path),
-                    null);
-        } catch (URISyntaxException ex) {
-            throw new AssertionError(ex);
-        }
-    }
-
-    private boolean equalsNameAt(AbstractJrtPath other, int index) {
-        int mbegin = offsets[index];
-        int mlen;
-        if (index == (offsets.length - 1)) {
-            mlen = path.length - mbegin;
-        } else {
-            mlen = offsets[index + 1] - mbegin - 1;
-        }
-        int obegin = other.offsets[index];
-        int olen;
-        if (index == (other.offsets.length - 1)) {
-            olen = other.path.length - obegin;
-        } else {
-            olen = other.offsets[index + 1] - obegin - 1;
-        }
-        if (mlen != olen) {
-            return false;
-        }
-        int n = 0;
-        while (n < mlen) {
-            if (path[mbegin + n] != other.path[obegin + n]) {
-                return false;
-            }
-            n++;
-        }
-        return true;
-    }
-
-    @Override
-    public final AbstractJrtPath relativize(Path other) {
-        final AbstractJrtPath o = checkPath(other);
-        if (o.equals(this)) {
-            return newJrtPath(new byte[0], true);
-        }
-        if (/* this.getFileSystem() != o.getFileSystem() || */this.isAbsolute() != o.isAbsolute()) {
-            throw new IllegalArgumentException();
-        }
-        int mc = this.getNameCount();
-        int oc = o.getNameCount();
-        int n = Math.min(mc, oc);
-        int i = 0;
-        while (i < n) {
-            if (!equalsNameAt(o, i)) {
-                break;
-            }
-            i++;
-        }
-        int dotdots = mc - i;
-        int len = dotdots * 3 - 1;
-        if (i < oc) {
-            len += (o.path.length - o.offsets[i] + 1);
-        }
-        byte[] result = new byte[len];
-
-        int pos = 0;
-        while (dotdots > 0) {
-            result[pos++] = (byte) '.';
-            result[pos++] = (byte) '.';
-            if (pos < len) // no tailing slash at the end
-            {
-                result[pos++] = (byte) '/';
-            }
-            dotdots--;
-        }
-        if (i < oc) {
-            System.arraycopy(o.path, o.offsets[i],
-                    result, pos,
-                    o.path.length - o.offsets[i]);
-        }
-        return newJrtPath(result);
-    }
-
-    @Override
-    public AbstractJrtFileSystem getFileSystem() {
-        return jrtfs;
-    }
-
-    @Override
-    public final boolean isAbsolute() {
-        return (this.path.length > 0 && path[0] == '/');
-    }
-
-    @Override
-    public final AbstractJrtPath resolve(Path other) {
-        final AbstractJrtPath o = checkPath(other);
-        if (o.isAbsolute()) {
-            return o;
-        }
-        byte[] res;
-        if (this.path[path.length - 1] == '/') {
-            res = new byte[path.length + o.path.length];
-            System.arraycopy(path, 0, res, 0, path.length);
-            System.arraycopy(o.path, 0, res, path.length, o.path.length);
-        } else {
-            res = new byte[path.length + 1 + o.path.length];
-            System.arraycopy(path, 0, res, 0, path.length);
-            res[path.length] = '/';
-            System.arraycopy(o.path, 0, res, path.length + 1, o.path.length);
-        }
-        return newJrtPath(res);
-    }
-
-    @Override
-    public final Path resolveSibling(Path other) {
-        if (other == null) {
-            throw new NullPointerException();
-        }
-        Path parent = getParent();
-        return (parent == null) ? other : parent.resolve(other);
-    }
-
-    @Override
-    public final boolean startsWith(Path other) {
-        final AbstractJrtPath o = checkPath(other);
-        if (o.isAbsolute() != this.isAbsolute()
-                || o.path.length > this.path.length) {
-            return false;
-        }
-        int olast = o.path.length;
-        for (int i = 0; i < olast; i++) {
-            if (o.path[i] != this.path[i]) {
-                return false;
-            }
-        }
-        olast--;
-        return o.path.length == this.path.length
-                || o.path[olast] == '/'
-                || this.path[olast + 1] == '/';
-    }
-
-    @Override
-    public final boolean endsWith(Path other) {
-        final AbstractJrtPath o = checkPath(other);
-        int olast = o.path.length - 1;
-        if (olast > 0 && o.path[olast] == '/') {
-            olast--;
-        }
-        int last = this.path.length - 1;
-        if (last > 0 && this.path[last] == '/') {
-            last--;
-        }
-        if (olast == -1) // o.path.length == 0
-        {
-            return last == -1;
-        }
-        if ((o.isAbsolute() && (!this.isAbsolute() || olast != last))
-                || (last < olast)) {
-            return false;
-        }
-        for (; olast >= 0; olast--, last--) {
-            if (o.path[olast] != this.path[last]) {
-                return false;
-            }
-        }
-        return o.path[olast + 1] == '/'
-                || last == -1 || this.path[last] == '/';
-    }
-
-    @Override
-    public final AbstractJrtPath resolve(String other) {
-        return resolve(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final Path resolveSibling(String other) {
-        return resolveSibling(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final boolean startsWith(String other) {
-        return startsWith(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final boolean endsWith(String other) {
-        return endsWith(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final AbstractJrtPath normalize() {
-        byte[] res = getResolved();
-        if (res == path) // no change
-        {
-            return this;
-        }
-        return newJrtPath(res, true);
-    }
-
-    private AbstractJrtPath checkPath(Path path) {
-        if (path == null) {
-            throw new NullPointerException();
-        }
-        if (!(path instanceof AbstractJrtPath)) {
-            throw new ProviderMismatchException();
-        }
-        return (AbstractJrtPath) path;
-    }
-
-    // create offset list if not already created
-    private void initOffsets() {
-        if (offsets == null) {
-            int count, index;
-            // count names
-            count = 0;
-            index = 0;
-            while (index < path.length) {
-                byte c = path[index++];
-                if (c != '/') {
-                    count++;
-                    while (index < path.length && path[index] != '/') {
-                        index++;
-                    }
-                }
-            }
-            // populate offsets
-            int[] result = new int[count];
-            count = 0;
-            index = 0;
-            while (index < path.length) {
-                byte c = path[index];
-                if (c == '/') {
-                    index++;
-                } else {
-                    result[count++] = index++;
-                    while (index < path.length && path[index] != '/') {
-                        index++;
-                    }
-                }
-            }
-            synchronized (this) {
-                if (offsets == null) {
-                    offsets = result;
-                }
-            }
-        }
-    }
-
-    private volatile byte[] resolved;
-
-    final byte[] getResolvedPath() {
-        byte[] r = resolved;
-        if (r == null) {
-            if (isAbsolute()) {
-                r = getResolved();
-            } else {
-                r = toAbsolutePath().getResolvedPath();
-            }
-            resolved = r;
-        }
-        return resolved;
-    }
-
-    // removes redundant slashs, replace "\" to separator "/"
-    // and check for invalid characters
-    private static byte[] normalize(byte[] path) {
-        if (path.length == 0) {
-            return path;
-        }
-        byte prevC = 0;
-        for (int i = 0; i < path.length; i++) {
-            byte c = path[i];
-            if (c == '\\') {
-                return normalize(path, i);
-            }
-            if (c == (byte) '/' && prevC == '/') {
-                return normalize(path, i - 1);
-            }
-            if (c == '\u0000') {
-                throw new InvalidPathException(JrtFileSystem.getString(path),
-                        "Path: nul character not allowed");
-            }
-            prevC = c;
-        }
-
-        if (path.length > 1 && path[path.length - 1] == '/') {
-            return Arrays.copyOf(path, path.length - 1);
-        }
-
-        return path;
-    }
-
-    private static byte[] normalize(byte[] path, int off) {
-        byte[] to = new byte[path.length];
-        int n = 0;
-        while (n < off) {
-            to[n] = path[n];
-            n++;
-        }
-        int m = n;
-        byte prevC = 0;
-        while (n < path.length) {
-            byte c = path[n++];
-            if (c == (byte) '\\') {
-                c = (byte) '/';
-            }
-            if (c == (byte) '/' && prevC == (byte) '/') {
-                continue;
-            }
-            if (c == '\u0000') {
-                throw new InvalidPathException(JrtFileSystem.getString(path),
-                        "Path: nul character not allowed");
-            }
-            to[m++] = c;
-            prevC = c;
-        }
-        if (m > 1 && to[m - 1] == '/') {
-            m--;
-        }
-        return (m == to.length) ? to : Arrays.copyOf(to, m);
-    }
-
-    // Remove DotSlash(./) and resolve DotDot (..) components
-    private byte[] getResolved() {
-        if (path.length == 0) {
-            return path;
-        }
-        for (int i = 0; i < path.length; i++) {
-            byte c = path[i];
-            if (c == (byte) '.') {
-                return resolve0();
-            }
-        }
-
-        return path;
-    }
-
-    // TBD: performance, avoid initOffsets
-    private byte[] resolve0() {
-        byte[] to = new byte[path.length];
-        int nc = getNameCount();
-        int[] lastM = new int[nc];
-        int lastMOff = -1;
-        int m = 0;
-        for (int i = 0; i < nc; i++) {
-            int n = offsets[i];
-            int len = (i == offsets.length - 1)
-                    ? (path.length - n) : (offsets[i + 1] - n - 1);
-            if (len == 1 && path[n] == (byte) '.') {
-                if (m == 0 && path[0] == '/') // absolute path
-                {
-                    to[m++] = '/';
-                }
-                continue;
-            }
-            if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
-                if (lastMOff >= 0) {
-                    m = lastM[lastMOff--];  // retreat
-                    continue;
-                }
-                if (path[0] == '/') {  // "/../xyz" skip
-                    if (m == 0) {
-                        to[m++] = '/';
-                    }
-                } else {               // "../xyz" -> "../xyz"
-                    if (m != 0 && to[m - 1] != '/') {
-                        to[m++] = '/';
-                    }
-                    while (len-- > 0) {
-                        to[m++] = path[n++];
-                    }
-                }
-                continue;
-            }
-            if (m == 0 && path[0] == '/' || // absolute path
-                    m != 0 && to[m - 1] != '/') {   // not the first name
-                to[m++] = '/';
-            }
-            lastM[++lastMOff] = m;
-            while (len-- > 0) {
-                to[m++] = path[n++];
-            }
-        }
-        if (m > 1 && to[m - 1] == '/') {
-            m--;
-        }
-        return (m == to.length) ? to : Arrays.copyOf(to, m);
-    }
-
-    @Override
-    public final String toString() {
-        return JrtFileSystem.getString(path);
-    }
-
-    @Override
-    public final int hashCode() {
-        int h = hashcode;
-        if (h == 0) {
-            hashcode = h = Arrays.hashCode(path);
-        }
-        return h;
-    }
-
-    @Override
-    public final boolean equals(Object obj) {
-        return obj != null
-                && obj instanceof AbstractJrtPath
-                && this.jrtfs == ((AbstractJrtPath) obj).jrtfs
-                && compareTo((Path) obj) == 0;
-    }
-
-    @Override
-    public final int compareTo(Path other) {
-        final AbstractJrtPath o = checkPath(other);
-        int len1 = this.path.length;
-        int len2 = o.path.length;
-
-        int n = Math.min(len1, len2);
-        byte v1[] = this.path;
-        byte v2[] = o.path;
-
-        int k = 0;
-        while (k < n) {
-            int c1 = v1[k] & 0xff;
-            int c2 = v2[k] & 0xff;
-            if (c1 != c2) {
-                return c1 - c2;
-            }
-            k++;
-        }
-        return len1 - len2;
-    }
-
-    @Override
-    public final WatchKey register(
-            WatchService watcher,
-            WatchEvent.Kind[] events,
-            WatchEvent.Modifier... modifiers) {
-        if (watcher == null || events == null || modifiers == null) {
-            throw new NullPointerException();
-        }
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public final WatchKey register(WatchService watcher, WatchEvent.Kind... events) {
-        return register(watcher, events, new WatchEvent.Modifier[0]);
-    }
-
-    @Override
-    public final File toFile() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public final Iterator iterator() {
-        return new Iterator() {
-            private int i = 0;
-
-            @Override
-            public boolean hasNext() {
-                return (i < getNameCount());
-            }
-
-            @Override
-            public Path next() {
-                if (i < getNameCount()) {
-                    Path result = getName(i);
-                    i++;
-                    return result;
-                } else {
-                    throw new NoSuchElementException();
-                }
-            }
-
-            @Override
-            public void remove() {
-                throw new ReadOnlyFileSystemException();
-            }
-        };
-    }
-
-    /////////////////////////////////////////////////////////////////////
-    // Helpers for JrtFileSystemProvider and JrtFileSystem
-    final int getPathLength() {
-        return path.length;
-    }
-
-    final void createDirectory(FileAttribute... attrs)
-            throws IOException {
-        jrtfs.createDirectory(this, attrs);
-    }
-
-    final InputStream newInputStream(OpenOption... options) throws IOException {
-        if (options.length > 0) {
-            for (OpenOption opt : options) {
-                if (opt != READ) {
-                    throw new UnsupportedOperationException("'" + opt + "' not allowed");
-                }
-            }
-        }
-        return jrtfs.newInputStream(this);
-    }
-
-    final DirectoryStream newDirectoryStream(Filter filter)
-            throws IOException {
-        return new JrtDirectoryStream(this, filter);
-    }
-
-    final void delete() throws IOException {
-        jrtfs.deleteFile(this, true);
-    }
-
-    final void deleteIfExists() throws IOException {
-        jrtfs.deleteFile(this, false);
-    }
-
-    final AbstractJrtFileAttributes getAttributes(LinkOption... options) throws IOException {
-        AbstractJrtFileAttributes zfas = jrtfs.getFileAttributes(this, options);
-        if (zfas == null) {
-            throw new NoSuchFileException(toString());
-        }
-        return zfas;
-    }
-
-    final void setAttribute(String attribute, Object value, LinkOption... options)
-            throws IOException {
-        String type;
-        String attr;
-        int colonPos = attribute.indexOf(':');
-        if (colonPos == -1) {
-            type = "basic";
-            attr = attribute;
-        } else {
-            type = attribute.substring(0, colonPos++);
-            attr = attribute.substring(colonPos);
-        }
-        JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options);
-        if (view == null) {
-            throw new UnsupportedOperationException("view <" + view + "> is not supported");
-        }
-        view.setAttribute(attr, value);
-    }
-
-    final void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
-            throws IOException {
-        jrtfs.setTimes(this, mtime, atime, ctime);
-    }
-
-    final Map readAttributes(String attributes, LinkOption... options)
-            throws IOException {
-        String view;
-        String attrs;
-        int colonPos = attributes.indexOf(':');
-        if (colonPos == -1) {
-            view = "basic";
-            attrs = attributes;
-        } else {
-            view = attributes.substring(0, colonPos++);
-            attrs = attributes.substring(colonPos);
-        }
-        JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options);
-        if (jrtfv == null) {
-            throw new UnsupportedOperationException("view not supported");
-        }
-        return jrtfv.readAttributes(attrs);
-    }
-
-    final FileStore getFileStore() throws IOException {
-        // each JrtFileSystem only has one root (as requested for now)
-        if (exists()) {
-            return jrtfs.getFileStore(this);
-        }
-        throw new NoSuchFileException(JrtFileSystem.getString(path));
-    }
-
-    final boolean isSameFile(Path other) throws IOException {
-        if (this.equals(other)) {
-            return true;
-        }
-        if (other == null
-                || this.getFileSystem() != other.getFileSystem()) {
-            return false;
-        }
-        this.checkAccess();
-        AbstractJrtPath target = (AbstractJrtPath) other;
-        target.checkAccess();
-        return Arrays.equals(this.getResolvedPath(), target.getResolvedPath())
-                || jrtfs.isSameFile(this, target);
-    }
-
-    final SeekableByteChannel newByteChannel(Set options,
-            FileAttribute... attrs)
-            throws IOException {
-        return jrtfs.newByteChannel(this, options, attrs);
-    }
-
-    final FileChannel newFileChannel(Set options,
-            FileAttribute... attrs)
-            throws IOException {
-        return jrtfs.newFileChannel(this, options, attrs);
-    }
-
-    final void checkAccess(AccessMode... modes) throws IOException {
-        boolean w = false;
-        boolean x = false;
-        for (AccessMode mode : modes) {
-            switch (mode) {
-                case READ:
-                    break;
-                case WRITE:
-                    w = true;
-                    break;
-                case EXECUTE:
-                    x = true;
-                    break;
-                default:
-                    throw new UnsupportedOperationException();
-            }
-        }
-
-        BasicFileAttributes attrs = jrtfs.getFileAttributes(this);
-        if (attrs == null && (path.length != 1 || path[0] != '/')) {
-            throw new NoSuchFileException(toString());
-        }
-        if (w) {
-//            if (jrtfs.isReadOnly())
-            throw new AccessDeniedException(toString());
-        }
-        if (x) {
-            throw new AccessDeniedException(toString());
-        }
-    }
-
-    final boolean exists() {
-        try {
-            return jrtfs.exists(this);
-        } catch (IOException x) {
-        }
-        return false;
-    }
-
-    final OutputStream newOutputStream(OpenOption... options) throws IOException {
-        if (options.length == 0) {
-            return jrtfs.newOutputStream(this,
-                    CREATE_NEW, WRITE);
-        }
-        return jrtfs.newOutputStream(this, options);
-    }
-
-    final void move(AbstractJrtPath target, CopyOption... options)
-            throws IOException {
-        if (this.jrtfs == target.jrtfs) {
-            jrtfs.copyFile(true,
-                    this, target,
-                    options);
-        } else {
-            copyToTarget(target, options);
-            delete();
-        }
-    }
-
-    final void copy(AbstractJrtPath target, CopyOption... options)
-            throws IOException {
-        if (this.jrtfs == target.jrtfs) {
-            jrtfs.copyFile(false,
-                    this, target,
-                    options);
-        } else {
-            copyToTarget(target, options);
-        }
-    }
-
-    private void copyToTarget(AbstractJrtPath target, CopyOption... options)
-            throws IOException {
-        boolean replaceExisting = false;
-        boolean copyAttrs = false;
-        for (CopyOption opt : options) {
-            if (opt == REPLACE_EXISTING) {
-                replaceExisting = true;
-            } else if (opt == COPY_ATTRIBUTES) {
-                copyAttrs = true;
-            }
-        }
-        // attributes of source file
-        BasicFileAttributes jrtfas = getAttributes();
-        // check if target exists
-        boolean exists;
-        if (replaceExisting) {
-            try {
-                target.deleteIfExists();
-                exists = false;
-            } catch (DirectoryNotEmptyException x) {
-                exists = true;
-            }
-        } else {
-            exists = target.exists();
-        }
-        if (exists) {
-            throw new FileAlreadyExistsException(target.toString());
-        }
-
-        if (jrtfas.isDirectory()) {
-            // create directory or file
-            target.createDirectory();
-        } else {
-            try (InputStream is = jrtfs.newInputStream(this); OutputStream os = target.newOutputStream()) {
-                byte[] buf = new byte[8192];
-                int n;
-                while ((n = is.read(buf)) != -1) {
-                    os.write(buf, 0, n);
-                }
-            }
-        }
-        if (copyAttrs) {
-            BasicFileAttributeView view
-                    = JrtFileAttributeView.get(target, BasicFileAttributeView.class);
-            try {
-                view.setTimes(jrtfas.lastModifiedTime(),
-                        jrtfas.lastAccessTime(),
-                        jrtfas.creationTime());
-            } catch (IOException x) {
-                // rollback?
-                try {
-                    target.delete();
-                } catch (IOException ignore) {
-                }
-                throw x;
-            }
-        }
-    }
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java
new file mode 100644
index 00000000000..ae43c2151f0
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.internal.jimage.ImageReader.Node;
+
+/**
+ * A jrt file system built on $JAVA_HOME/modules directory ('exploded modules
+ * build')
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+class ExplodedImage extends SystemImage {
+
+    private static final String MODULES = "/modules/";
+    private static final String PACKAGES = "/packages/";
+    private static final int PACKAGES_LEN = PACKAGES.length();
+
+    private final FileSystem defaultFS;
+    private final String separator;
+    private final Map nodes = Collections.synchronizedMap(new HashMap<>());
+    private final BasicFileAttributes modulesDirAttrs;
+
+    ExplodedImage(Path modulesDir) throws IOException {
+        defaultFS = FileSystems.getDefault();
+        String str = defaultFS.getSeparator();
+        separator = str.equals("/") ? null : str;
+        modulesDirAttrs = Files.readAttributes(modulesDir, BasicFileAttributes.class);
+        initNodes();
+    }
+
+    // A Node that is backed by actual default file system Path
+    private final class PathNode extends Node {
+
+        // Path in underlying default file system
+        private Path path;
+        private PathNode link;
+        private List children;
+
+        PathNode(String name, Path path, BasicFileAttributes attrs) {  // path
+            super(name, attrs);
+            this.path = path;
+        }
+
+        PathNode(String name, Node link) {              // link
+            super(name, link.getFileAttributes());
+            this.link = (PathNode)link;
+        }
+
+        PathNode(String name, List children) {    // dir
+            super(name, modulesDirAttrs);
+            this.children = children;
+        }
+
+        @Override
+        public boolean isDirectory() {
+            return children != null ||
+                   (link == null && getFileAttributes().isDirectory());
+        }
+
+        @Override
+        public boolean isLink() {
+            return link != null;
+        }
+
+        @Override
+        public PathNode resolveLink(boolean recursive) {
+            if (link == null)
+                return this;
+            return recursive && link.isLink() ? link.resolveLink(true) : link;
+        }
+
+        byte[] getContent() throws IOException {
+            if (!getFileAttributes().isRegularFile())
+                throw new FileSystemException(getName() + " is not file");
+            return Files.readAllBytes(path);
+        }
+
+        @Override
+        public List getChildren() {
+            if (!isDirectory())
+                throw new IllegalArgumentException("not a directory: " + getNameString());
+            if (children == null) {
+                List list = new ArrayList<>();
+                try (DirectoryStream stream = Files.newDirectoryStream(path)) {
+                    for (Path p : stream) {
+                        p = explodedModulesDir.relativize(p);
+                        String pName = MODULES + nativeSlashToFrontSlash(p.toString());
+                        Node node = findNode(pName);
+                        if (node != null) {  // findNode may choose to hide certain files!
+                            list.add(node);
+                        }
+                    }
+                } catch (IOException x) {
+                    return null;
+                }
+                children = list;
+            }
+            return children;
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        nodes.clear();
+    }
+
+    @Override
+    public byte[] getResource(Node node) throws IOException {
+        return ((PathNode)node).getContent();
+    }
+
+    // find Node for the given Path
+    @Override
+    public synchronized Node findNode(String str) {
+        Node node = findModulesNode(str);
+        if (node != null) {
+            return node;
+        }
+        // lazily created for paths like /packages///xyz
+        // For example /packages/java.lang/java.base/java/lang/
+        if (str.startsWith(PACKAGES)) {
+            // pkgEndIdx marks end of  part
+            int pkgEndIdx = str.indexOf('/', PACKAGES_LEN);
+            if (pkgEndIdx != -1) {
+                // modEndIdx marks end of  part
+                int modEndIdx = str.indexOf('/', pkgEndIdx + 1);
+                if (modEndIdx != -1) {
+                    // make sure we have such module link!
+                    // ie., /packages// is valid
+                    Node linkNode = nodes.get(str.substring(0, modEndIdx));
+                    if (linkNode == null || !linkNode.isLink()) {
+                        return null;
+                    }
+                    // map to "/modules/zyz" path and return that node
+                    // For example, "/modules/java.base/java/lang" for
+                    // "/packages/java.lang/java.base/java/lang".
+                    String mod = MODULES + str.substring(pkgEndIdx + 1);
+                    return findModulesNode(mod);
+                }
+            }
+        }
+        return null;
+    }
+
+    // find a Node for a path that starts like "/modules/..."
+    Node findModulesNode(String str) {
+        PathNode node = nodes.get(str);
+        if (node != null) {
+            return node;
+        }
+        // lazily created "/modules/xyz/abc/" Node
+        // This is mapped to default file system path "/xyz/abc"
+        Path p = underlyingPath(str);
+        if (p != null) {
+            try {
+                BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class);
+                if (attrs.isRegularFile()) {
+                    Path f = p.getFileName();
+                    if (f.toString().startsWith("_the."))
+                        return null;
+                }
+                node = new PathNode(str, p, attrs);
+                nodes.put(str, node);
+                return node;
+            } catch (IOException x) {
+                // does not exists or unable to determine
+            }
+        }
+        return null;
+    }
+
+    Path underlyingPath(String str) {
+        if (str.startsWith(MODULES)) {
+            str = frontSlashToNativeSlash(str.substring("/modules".length()));
+            return defaultFS.getPath(explodedModulesDir.toString(), str);
+        }
+        return null;
+    }
+
+    // convert "/" to platform path separator
+    private String frontSlashToNativeSlash(String str) {
+        return separator == null ? str : str.replace("/", separator);
+    }
+
+    // convert platform path separator to "/"
+    private String nativeSlashToFrontSlash(String str) {
+        return separator == null ? str : str.replace(separator, "/");
+    }
+
+    // convert "/"s to "."s
+    private String slashesToDots(String str) {
+        return str.replace(separator != null ? separator : "/", ".");
+    }
+
+    // initialize file system Nodes
+    private void initNodes() throws IOException {
+        // same package prefix may exist in mutliple modules. This Map
+        // is filled by walking "jdk modules" directory recursively!
+        Map> packageToModules = new HashMap<>();
+        try (DirectoryStream stream = Files.newDirectoryStream(explodedModulesDir)) {
+            for (Path module : stream) {
+                if (Files.isDirectory(module)) {
+                    String moduleName = module.getFileName().toString();
+                    // make sure "/modules/" is created
+                    findModulesNode(MODULES + moduleName);
+                    Files.walk(module).filter(Files::isDirectory).forEach((p) -> {
+                        p = module.relativize(p);
+                        String pkgName = slashesToDots(p.toString());
+                        // skip META-INFO and empty strings
+                        if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) {
+                            List moduleNames = packageToModules.get(pkgName);
+                            if (moduleNames == null) {
+                                moduleNames = new ArrayList<>();
+                                packageToModules.put(pkgName, moduleNames);
+                            }
+                            moduleNames.add(moduleName);
+                        }
+                    });
+                }
+            }
+        }
+        // create "/modules" directory
+        // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules
+        PathNode modulesDir = new PathNode("/modules", new ArrayList<>(nodes.values()));
+        nodes.put(modulesDir.getName(), modulesDir);
+
+        // create children under "/packages"
+        List packagesChildren = new ArrayList<>(packageToModules.size());
+        for (Map.Entry> entry : packageToModules.entrySet()) {
+            String pkgName = entry.getKey();
+            List moduleNameList = entry.getValue();
+            List moduleLinkNodes = new ArrayList<>(moduleNameList.size());
+            for (String moduleName : moduleNameList) {
+                Node moduleNode = findModulesNode(MODULES + moduleName);
+                PathNode linkNode = new PathNode(PACKAGES + pkgName + "/" + moduleName, moduleNode);
+                nodes.put(linkNode.getName(), linkNode);
+                moduleLinkNodes.add(linkNode);
+            }
+            PathNode pkgDir = new PathNode(PACKAGES + pkgName, moduleLinkNodes);
+            nodes.put(pkgDir.getName(), pkgDir);
+            packagesChildren.add(pkgDir);
+        }
+        // "/packages" dir
+        PathNode packagesDir = new PathNode("/packages", packagesChildren);
+        nodes.put(packagesDir.getName(), packagesDir);
+
+        // finally "/" dir!
+        List rootChildren = new ArrayList<>();
+        rootChildren.add(packagesDir);
+        rootChildren.add(modulesDir);
+        PathNode root = new PathNode("/", rootChildren);
+        nodes.put(root.getName(), root);
+    }
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java
index ed7702c237b..eced854d9d8 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java
@@ -30,6 +30,7 @@ import java.nio.file.DirectoryIteratorException;
 import java.nio.file.NotDirectoryException;
 import java.nio.file.Path;
 import java.util.Iterator;
+import java.util.Objects;
 import java.util.NoSuchElementException;
 import java.io.IOException;
 
@@ -44,115 +45,47 @@ import java.io.IOException;
  */
 final class JrtDirectoryStream implements DirectoryStream {
 
-    private final AbstractJrtFileSystem jrtfs;
-    private final AbstractJrtPath dir;
+    private final JrtPath dir;
     private final DirectoryStream.Filter filter;
     private volatile boolean isClosed;
     private volatile Iterator itr;
 
-    JrtDirectoryStream(AbstractJrtPath jrtPath,
+    JrtDirectoryStream(JrtPath dir,
             DirectoryStream.Filter filter)
-            throws IOException {
-        this.jrtfs = jrtPath.getFileSystem();
-        this.dir = jrtPath;
-        // sanity check
-        if (!jrtfs.isDirectory(dir, true)) {
-            throw new NotDirectoryException(jrtPath.toString());
+            throws IOException
+    {
+        this.dir = dir;
+        if (!dir.jrtfs.isDirectory(dir, true)) {  // sanity check
+            throw new NotDirectoryException(dir.toString());
         }
-
         this.filter = filter;
     }
 
     @Override
     public synchronized Iterator iterator() {
-        if (isClosed) {
+        if (isClosed)
             throw new ClosedDirectoryStreamException();
-        }
-        if (itr != null) {
+        if (itr != null)
             throw new IllegalStateException("Iterator has already been returned");
-        }
-
         try {
-            itr = jrtfs.iteratorOf(dir);
+            itr = dir.jrtfs.iteratorOf(dir, filter);
         } catch (IOException e) {
             throw new IllegalStateException(e);
         }
         return new Iterator() {
-            /*
-             * next Path value to return from this iterator.
-             * null value means hasNext() not called yet
-             * or last hasNext() returned false or resulted
-             * in exception. If last hasNext() returned true,
-             * then this field has non-null value.
-             */
             private Path next;
-
-            // get-and-clear and set-next by these methods
-            private Path getAndClearNext() {
-                assert next != null;
-                Path result = this.next;
-                this.next = null;
-                return result;
-            }
-
-            private void setNext(Path path) {
-                assert path != null;
-                this.next = path;
-            }
-
-            // if hasNext() returns true, 'next' field has non-null Path
             @Override
             public synchronized boolean hasNext() {
-                if (next != null) {
-                    return true;
-                }
-
-                if (isClosed) {
+                if (isClosed)
                     return false;
-                }
-
-                if (filter == null) {
-                    if (itr.hasNext()) {
-                        setNext(itr.next());
-                        return true;
-                    } else {
-                        return false;
-                    }
-                } else {
-                    while (itr.hasNext()) {
-                        Path tmpPath = itr.next();
-                        try {
-                            if (filter.accept(tmpPath)) {
-                                setNext(tmpPath);
-                                return true;
-                            }
-                        } catch (IOException ioe) {
-                            throw new DirectoryIteratorException(ioe);
-                        }
-                    }
-
-                    return false;
-                }
+                return itr.hasNext();
             }
 
             @Override
             public synchronized Path next() {
-                if (next != null) {
-                    return getAndClearNext();
-                }
-
-                if (isClosed) {
+                if (isClosed)
                     throw new NoSuchElementException();
-                }
-
-                if (next == null && itr.hasNext()) {
-                    // missing hasNext() between next() calls.
-                    if (hasNext()) {
-                        return getAndClearNext();
-                    }
-                }
-
-                throw new NoSuchElementException();
+                return itr.next();
             }
 
             @Override
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java
deleted file mode 100644
index 161bbaab487..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jrtfs;
-
-import java.io.IOException;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileTime;
-import jdk.internal.jrtfs.JrtExplodedFileSystem.Node;
-
-/**
- * jrt file system attributes implementation on top of 'exploded file system'
- * Node.
- *
- * @implNote This class needs to maintain JDK 8 source compatibility.
- *
- * It is used internally in the JDK to implement jimage/jrtfs access,
- * but also compiled and delivered as part of the jrtfs.jar to support access
- * to the jimage file provided by the shipped JDK by tools running on JDK 8.
- */
-final class JrtExplodedFileAttributes extends AbstractJrtFileAttributes {
-
-    private final Node node;
-    private final BasicFileAttributes attrs;
-
-    JrtExplodedFileAttributes(Node node) throws IOException {
-        this.node = node;
-        this.attrs = node.getBasicAttrs();
-    }
-
-    @Override
-    public FileTime creationTime() {
-        return attrs.creationTime();
-    }
-
-    @Override
-    public boolean isDirectory() {
-        return node.isDirectory();
-    }
-
-    @Override
-    public boolean isOther() {
-        return false;
-    }
-
-    @Override
-    public boolean isRegularFile() {
-        return node.isFile();
-    }
-
-    @Override
-    public FileTime lastAccessTime() {
-        return attrs.lastAccessTime();
-    }
-
-    @Override
-    public FileTime lastModifiedTime() {
-        return attrs.lastModifiedTime();
-    }
-
-    @Override
-    public long size() {
-        return isRegularFile() ? attrs.size() : 0L;
-    }
-
-    @Override
-    public boolean isSymbolicLink() {
-        return node.isLink();
-    }
-
-    @Override
-    public Object fileKey() {
-        return node.resolveLink(true);
-    }
-
-    @Override
-    public long compressedSize() {
-        return 0L;
-    }
-
-    @Override
-    public String extension() {
-        return node.getExtension();
-    }
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java
deleted file mode 100644
index 3a077b199db..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jrtfs;
-
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemException;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
-import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import static java.util.stream.Collectors.toList;
-import static jdk.internal.jrtfs.AbstractJrtFileSystem.getString;
-
-/**
- * A jrt file system built on $JAVA_HOME/modules directory ('exploded modules
- * build')
- *
- * @implNote This class needs to maintain JDK 8 source compatibility.
- *
- * It is used internally in the JDK to implement jimage/jrtfs access,
- * but also compiled and delivered as part of the jrtfs.jar to support access
- * to the jimage file provided by the shipped JDK by tools running on JDK 8.
- */
-class JrtExplodedFileSystem extends AbstractJrtFileSystem {
-
-    private static final String MODULES = "/modules/";
-    private static final String PACKAGES = "/packages/";
-    private static final int PACKAGES_LEN = PACKAGES.length();
-
-    // root path
-    private final JrtExplodedPath rootPath;
-    private volatile boolean isOpen;
-    private final FileSystem defaultFS;
-    private final String separator;
-    private final Map nodes = Collections.synchronizedMap(new HashMap<>());
-    private final BasicFileAttributes modulesDirAttrs;
-
-    JrtExplodedFileSystem(JrtFileSystemProvider provider,
-            Map env)
-            throws IOException {
-
-        super(provider, env);
-        checkExists(SystemImages.explodedModulesDir());
-        byte[] root = new byte[]{'/'};
-        rootPath = new JrtExplodedPath(this, root);
-        isOpen = true;
-        defaultFS = FileSystems.getDefault();
-        String str = defaultFS.getSeparator();
-        separator = str.equals(getSeparator()) ? null : str;
-        modulesDirAttrs = Files.readAttributes(SystemImages.explodedModulesDir(), BasicFileAttributes.class);
-        initNodes();
-    }
-
-    @Override
-    public void close() throws IOException {
-        cleanup();
-    }
-
-    @Override
-    public boolean isOpen() {
-        return isOpen;
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        cleanup();
-        super.finalize();
-    }
-
-    private synchronized void cleanup() {
-        isOpen = false;
-        nodes.clear();
-    }
-
-    @Override
-    JrtExplodedPath getRootPath() {
-        return rootPath;
-    }
-
-    // Base class for Nodes of this file system
-    abstract class Node {
-
-        private final String name;
-
-        Node(String name) {
-            this.name = name;
-        }
-
-        final String getName() {
-            return name;
-        }
-
-        final String getExtension() {
-            if (isFile()) {
-                final int index = name.lastIndexOf(".");
-                if (index != -1) {
-                    return name.substring(index + 1);
-                }
-            }
-
-            return null;
-        }
-
-        BasicFileAttributes getBasicAttrs() throws IOException {
-            return modulesDirAttrs;
-        }
-
-        boolean isLink() {
-            return false;
-        }
-
-        boolean isDirectory() {
-            return false;
-        }
-
-        boolean isFile() {
-            return false;
-        }
-
-        byte[] getContent() throws IOException {
-            if (!isFile()) {
-                throw new FileSystemException(name + " is not file");
-            }
-
-            throw new AssertionError("ShouldNotReachHere");
-        }
-
-        List getChildren() throws IOException {
-            if (!isDirectory()) {
-                throw new NotDirectoryException(name);
-            }
-
-            throw new AssertionError("ShouldNotReachHere");
-        }
-
-        final Node resolveLink() {
-            return resolveLink(false);
-        }
-
-        Node resolveLink(boolean recursive) {
-            return this;
-        }
-    }
-
-    // A Node that is backed by actual default file system Path
-    private final class PathNode extends Node {
-
-        // Path in underlying default file system
-        private final Path path;
-        private final boolean file;
-        // lazily initialized, don't read attributes unless required!
-        private BasicFileAttributes attrs;
-
-        PathNode(String name, Path path) {
-            super(name);
-            this.path = path;
-            this.file = Files.isRegularFile(path);
-        }
-
-        @Override
-        synchronized BasicFileAttributes getBasicAttrs() throws IOException {
-            if (attrs == null) {
-                attrs = Files.readAttributes(path, BasicFileAttributes.class);
-            }
-            return attrs;
-        }
-
-        @Override
-        boolean isDirectory() {
-            return !file;
-        }
-
-        @Override
-        boolean isFile() {
-            return file;
-        }
-
-        @Override
-        byte[] getContent() throws IOException {
-            if (!isFile()) {
-                throw new FileSystemException(getName() + " is not file");
-            }
-
-            return Files.readAllBytes(path);
-        }
-
-        @Override
-        List getChildren() throws IOException {
-            if (!isDirectory()) {
-                throw new NotDirectoryException(getName());
-            }
-
-            List children = new ArrayList<>();
-            try (DirectoryStream stream = Files.newDirectoryStream(path)) {
-                for (Path cp : stream) {
-                    cp = SystemImages.explodedModulesDir().relativize(cp);
-                    String cpName = MODULES + nativeSlashToFrontSlash(cp.toString());
-                    try {
-                        children.add(findNode(cpName));
-                    } catch (NoSuchFileException nsfe) {
-                        // findNode may choose to hide certain files!
-                    }
-                }
-            }
-
-            return children;
-        }
-    }
-
-    // A Node that links to another Node
-    private final class LinkNode extends Node {
-
-        // underlying linked Node
-        private final Node link;
-
-        LinkNode(String name, Node link) {
-            super(name);
-            this.link = link;
-        }
-
-        @Override
-        BasicFileAttributes getBasicAttrs() throws IOException {
-            return link.getBasicAttrs();
-        }
-
-        @Override
-        public boolean isLink() {
-            return true;
-        }
-
-        @Override
-        Node resolveLink(boolean recursive) {
-            return recursive && (link instanceof LinkNode) ? ((LinkNode) link).resolveLink(true) : link;
-        }
-    }
-
-    // A directory Node with it's children Nodes
-    private final class DirNode extends Node {
-
-        // children Nodes of this Node.
-        private final List children;
-
-        DirNode(String name, List children) {
-            super(name);
-            this.children = children;
-        }
-
-        @Override
-        boolean isDirectory() {
-            return true;
-        }
-
-        @Override
-        List getChildren() throws IOException {
-            return children;
-        }
-    }
-
-    private JrtExplodedPath toJrtExplodedPath(String path) {
-        return toJrtExplodedPath(getBytes(path));
-    }
-
-    private JrtExplodedPath toJrtExplodedPath(byte[] path) {
-        return new JrtExplodedPath(this, path);
-    }
-
-    @Override
-    boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException {
-        Node n1 = checkNode(jrtPath1);
-        Node n2 = checkNode(jrtPath2);
-        return n1 == n2;
-    }
-
-    @Override
-    boolean isLink(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath).isLink();
-    }
-
-    @Override
-    AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
-        String name = checkNode(jrtPath).resolveLink().getName();
-        return toJrtExplodedPath(name);
-    }
-
-    @Override
-    AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException {
-        Node node = checkNode(jrtPath);
-        if (node.isLink() && followLinks(options)) {
-            node = node.resolveLink(true);
-        }
-        return new JrtExplodedFileAttributes(node);
-    }
-
-    @Override
-    boolean exists(AbstractJrtPath jrtPath) throws IOException {
-        try {
-            checkNode(jrtPath);
-            return true;
-        } catch (NoSuchFileException nsfe) {
-            return false;
-        }
-    }
-
-    @Override
-    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException {
-        Node node = checkNode(jrtPath);
-        return resolveLinks && node.isLink()
-                ? node.resolveLink(true).isDirectory()
-                : node.isDirectory();
-    }
-
-    @Override
-    Iterator iteratorOf(AbstractJrtPath dir) throws IOException {
-        Node node = checkNode(dir).resolveLink(true);
-        if (!node.isDirectory()) {
-            throw new NotDirectoryException(getString(dir.getName()));
-        }
-
-        Function nodeToPath =
-            child -> dir.resolve(
-                toJrtExplodedPath(child.getName()).
-                getFileName());
-
-        return node.getChildren().stream().
-                   map(nodeToPath).collect(toList()).
-                   iterator();
-    }
-
-    @Override
-    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath).getContent();
-    }
-
-    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath.getResolvedPath());
-    }
-
-    private Node checkNode(byte[] path) throws IOException {
-        ensureOpen();
-        return findNode(path);
-    }
-
-    synchronized Node findNode(byte[] path) throws IOException {
-        return findNode(getString(path));
-    }
-
-    // find Node for the given Path
-    synchronized Node findNode(String str) throws IOException {
-        Node node = findModulesNode(str);
-        if (node != null) {
-            return node;
-        }
-
-        // lazily created for paths like /packages///xyz
-        // For example /packages/java.lang/java.base/java/lang/
-        if (str.startsWith(PACKAGES)) {
-            // pkgEndIdx marks end of  part
-            int pkgEndIdx = str.indexOf('/', PACKAGES_LEN);
-            if (pkgEndIdx != -1) {
-                // modEndIdx marks end of  part
-                int modEndIdx = str.indexOf('/', pkgEndIdx + 1);
-                if (modEndIdx != -1) {
-                    // make sure we have such module link!
-                    // ie., /packages// is valid
-                    Node linkNode = nodes.get(str.substring(0, modEndIdx));
-                    if (linkNode == null || !linkNode.isLink()) {
-                        throw new NoSuchFileException(str);
-                    }
-
-                    // map to "/modules/zyz" path and return that node
-                    // For example, "/modules/java.base/java/lang" for
-                    // "/packages/java.lang/java.base/java/lang".
-                    String mod = MODULES + str.substring(pkgEndIdx + 1);
-                    return findNode(mod);
-                }
-            }
-        }
-
-        throw new NoSuchFileException(str);
-    }
-
-    // find a Node for a path that starts like "/modules/..."
-    synchronized Node findModulesNode(String str) throws IOException {
-        Node node = nodes.get(str);
-        if (node != null) {
-            return node;
-        }
-
-        // lazily created "/modules/xyz/abc/" Node
-        // This is mapped to default file system path "/xyz/abc"
-        Path p = underlyingPath(str);
-        if (p != null) {
-            if (Files.isRegularFile(p)) {
-                Path file = p.getFileName();
-                if (file.toString().startsWith("_the.")) {
-                    return null;
-                }
-            }
-            node = new PathNode(str, p);
-            nodes.put(str, node);
-            return node;
-        }
-
-        return null;
-    }
-
-    Path underlyingPath(String str) {
-        if (str.startsWith(MODULES)) {
-            str = frontSlashToNativeSlash(str.substring("/modules".length()));
-            return defaultFS.getPath(SystemImages.explodedModulesDir().toString(), str);
-        }
-        return null;
-    }
-
-    // convert "/" to platform path separator
-    private String frontSlashToNativeSlash(String str) {
-        return separator == null ? str : str.replace("/", separator);
-    }
-
-    // convert platform path separator to "/"
-    private String nativeSlashToFrontSlash(String str) {
-        return separator == null ? str : str.replace(separator, "/");
-    }
-
-    // convert "/"s to "."s
-    private String slashesToDots(String str) {
-        return str.replace(separator != null ? separator : "/", ".");
-    }
-
-    // initialize file system Nodes
-    private void initNodes() throws IOException {
-        // same package prefix may exist in mutliple modules. This Map
-        // is filled by walking "jdk modules" directory recursively!
-        Map> packageToModules = new HashMap<>();
-
-        try (DirectoryStream stream = Files.newDirectoryStream(SystemImages.explodedModulesDir())) {
-            for (Path module : stream) {
-                if (Files.isDirectory(module)) {
-                    String moduleName = module.getFileName().toString();
-                    // make sure "/modules/" is created
-                    findModulesNode(MODULES + moduleName);
-
-                    Files.walk(module).filter(Files::isDirectory).forEach((p) -> {
-                        p = module.relativize(p);
-                        String pkgName = slashesToDots(p.toString());
-                        // skip META-INFO and empty strings
-                        if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) {
-                            List moduleNames = packageToModules.get(pkgName);
-                            if (moduleNames == null) {
-                                moduleNames = new ArrayList<>();
-                                packageToModules.put(pkgName, moduleNames);
-                            }
-                            moduleNames.add(moduleName);
-                        }
-                    });
-                }
-            }
-        }
-
-        // create "/modules" directory
-        // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules
-        DirNode modulesDir = new DirNode("/modules", new ArrayList<>(nodes.values()));
-        nodes.put(modulesDir.getName(), modulesDir);
-
-        // create children under "/packages"
-        List packagesChildren = new ArrayList<>(packageToModules.size());
-        for (Map.Entry> entry : packageToModules.entrySet()) {
-            String pkgName = entry.getKey();
-            List moduleNameList = entry.getValue();
-            List moduleLinkNodes = new ArrayList<>(moduleNameList.size());
-            for (String moduleName : moduleNameList) {
-                Node moduleNode = findModulesNode(MODULES + moduleName);
-                LinkNode linkNode = new LinkNode(PACKAGES + pkgName + "/" + moduleName, moduleNode);
-                nodes.put(linkNode.getName(), linkNode);
-                moduleLinkNodes.add(linkNode);
-            }
-
-            DirNode pkgDir = new DirNode(PACKAGES + pkgName, moduleLinkNodes);
-            nodes.put(pkgDir.getName(), pkgDir);
-            packagesChildren.add(pkgDir);
-        }
-
-        // "/packages" dir
-        DirNode packagesDir = new DirNode("/packages", packagesChildren);
-        nodes.put(packagesDir.getName(), packagesDir);
-
-        // finally "/" dir!
-        List rootChildren = new ArrayList<>();
-        rootChildren.add(modulesDir);
-        rootChildren.add(packagesDir);
-        DirNode root = new DirNode("/", rootChildren);
-        nodes.put(root.getName(), root);
-    }
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java
index e6e80657bab..874da9433fd 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java
@@ -29,6 +29,7 @@ import java.nio.file.attribute.*;
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * File attribute view for jrt file system.
@@ -42,7 +43,6 @@ import java.util.Map;
 final class JrtFileAttributeView implements BasicFileAttributeView {
 
     private static enum AttrID {
-
         size,
         creationTime,
         lastAccessTime,
@@ -56,21 +56,19 @@ final class JrtFileAttributeView implements BasicFileAttributeView {
         extension
     };
 
-    private final AbstractJrtPath path;
+    private final JrtPath path;
     private final boolean isJrtView;
     private final LinkOption[] options;
 
-    private JrtFileAttributeView(AbstractJrtPath path, boolean isJrtView, LinkOption... options) {
+    private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) {
         this.path = path;
         this.isJrtView = isJrtView;
         this.options = options;
     }
 
     @SuppressWarnings("unchecked") // Cast to V
-    static  V get(AbstractJrtPath path, Class type, LinkOption... options) {
-        if (type == null) {
-            throw new NullPointerException();
-        }
+    static  V get(JrtPath path, Class type, LinkOption... options) {
+        Objects.requireNonNull(type);
         if (type == BasicFileAttributeView.class) {
             return (V) new JrtFileAttributeView(path, false, options);
         }
@@ -80,10 +78,8 @@ final class JrtFileAttributeView implements BasicFileAttributeView {
         return null;
     }
 
-    static JrtFileAttributeView get(AbstractJrtPath path, String type, LinkOption... options) {
-        if (type == null) {
-            throw new NullPointerException();
-        }
+    static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) {
+        Objects.requireNonNull(type);
         if (type.equals("basic")) {
             return new JrtFileAttributeView(path, false, options);
         }
@@ -99,61 +95,74 @@ final class JrtFileAttributeView implements BasicFileAttributeView {
     }
 
     @Override
-    public AbstractJrtFileAttributes readAttributes() throws IOException {
+    public JrtFileAttributes readAttributes() throws IOException {
         return path.getAttributes(options);
     }
 
     @Override
     public void setTimes(FileTime lastModifiedTime,
-            FileTime lastAccessTime,
-            FileTime createTime)
-            throws IOException {
+                         FileTime lastAccessTime,
+                         FileTime createTime) throws IOException {
         path.setTimes(lastModifiedTime, lastAccessTime, createTime);
     }
 
-    void setAttribute(String attribute, Object value)
+    static void setAttribute(JrtPath path, String attribute, Object value)
             throws IOException {
+        int colonPos = attribute.indexOf(':');
+        if (colonPos != -1) {    // type = "basic", if no ":"
+            String type = attribute.substring(0, colonPos++);
+            if (!type.equals("basic") && !type.equals("jrt")) {
+                throw new UnsupportedOperationException(
+                    "view <" + type + "> is not supported");
+            }
+            attribute = attribute.substring(colonPos);
+        }
         try {
-            if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) {
-                setTimes((FileTime) value, null, null);
-            }
-            if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) {
-                setTimes(null, (FileTime) value, null);
-            }
-            if (AttrID.valueOf(attribute) == AttrID.creationTime) {
-                setTimes(null, null, (FileTime) value);
+            AttrID id = AttrID.valueOf(attribute);
+            if (id == AttrID.lastModifiedTime) {
+                path.setTimes((FileTime) value, null, null);
+            } else if (id == AttrID.lastAccessTime) {
+                path.setTimes(null, (FileTime) value, null);
+            } else if (id == AttrID.creationTime) {
+                path.setTimes(null, null, (FileTime) value);
             }
             return;
-        } catch (IllegalArgumentException x) {
-        }
+        } catch (IllegalArgumentException x) {}
         throw new UnsupportedOperationException("'" + attribute
                 + "' is unknown or read-only attribute");
     }
 
-    Map readAttributes(String attributes)
+    static Map readAttributes(JrtPath path, String attributes,
+                                              LinkOption... options)
             throws IOException {
-        AbstractJrtFileAttributes jrtfas = readAttributes();
+        int colonPos = attributes.indexOf(':');
+        boolean isJrtView = false;
+        if (colonPos != -1) {    // type = "basic", if no ":"
+            String type = attributes.substring(0, colonPos++);
+            if (!type.equals("basic") && !type.equals("jrt")) {
+                throw new UnsupportedOperationException("view <" + type +
+                                                        "> is not supported");
+            }
+            isJrtView = true;
+            attributes = attributes.substring(colonPos);
+        }
+        JrtFileAttributes jrtfas = path.getAttributes();
         LinkedHashMap map = new LinkedHashMap<>();
         if ("*".equals(attributes)) {
             for (AttrID id : AttrID.values()) {
-                try {
-                    map.put(id.name(), attribute(id, jrtfas));
-                } catch (IllegalArgumentException x) {
-                }
+                map.put(id.name(), attribute(id, jrtfas, isJrtView));
             }
         } else {
             String[] as = attributes.split(",");
             for (String a : as) {
-                try {
-                    map.put(a, attribute(AttrID.valueOf(a), jrtfas));
-                } catch (IllegalArgumentException x) {
-                }
+                //throw IllegalArgumentException
+                map.put(a, attribute(AttrID.valueOf(a), jrtfas, isJrtView));
             }
         }
         return map;
     }
 
-    Object attribute(AttrID id, AbstractJrtFileAttributes jrtfas) {
+    static Object attribute(AttrID id, JrtFileAttributes jrtfas, boolean isJrtView) {
         switch (id) {
             case size:
                 return jrtfas.size();
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java
index 9293b1f4e4b..5dd556215d3 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,9 @@
  */
 package jdk.internal.jrtfs;
 
+import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.FileTime;
+import java.util.Formatter;
 import jdk.internal.jimage.ImageReader.Node;
 
 /**
@@ -36,7 +38,7 @@ import jdk.internal.jimage.ImageReader.Node;
  * but also compiled and delivered as part of the jrtfs.jar to support access
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-final class JrtFileAttributes extends AbstractJrtFileAttributes {
+final class JrtFileAttributes  implements BasicFileAttributes {
 
     private final Node node;
 
@@ -90,14 +92,50 @@ final class JrtFileAttributes extends AbstractJrtFileAttributes {
         return node.resolveLink(true);
     }
 
-    ///////// jrt entry attributes ///////////
-    @Override
+    ///////// jrtfs specific attributes ///////////
+    /**
+     * Compressed resource file. If not available or not applicable, 0L is
+     * returned.
+     *
+     * @return the compressed resource size for compressed resources.
+     */
     public long compressedSize() {
         return node.compressedSize();
     }
 
-    @Override
+    /**
+     * "file" extension of a file resource.
+     *
+     * @return extension string for the file resource
+     */
     public String extension() {
         return node.extension();
     }
+
+    @Override
+    public final String toString() {
+        StringBuilder sb = new StringBuilder(1024);
+        try (Formatter fm = new Formatter(sb)) {
+            if (creationTime() != null) {
+                fm.format("    creationTime    : %tc%n", creationTime().toMillis());
+            } else {
+                fm.format("    creationTime    : null%n");
+            }
+            if (lastAccessTime() != null) {
+                fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
+            } else {
+                fm.format("    lastAccessTime  : null%n");
+            }
+            fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
+            fm.format("    isRegularFile   : %b%n", isRegularFile());
+            fm.format("    isDirectory     : %b%n", isDirectory());
+            fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
+            fm.format("    isOther         : %b%n", isOther());
+            fm.format("    fileKey         : %s%n", fileKey());
+            fm.format("    size            : %d%n", size());
+            fm.format("    compressedSize  : %d%n", compressedSize());
+            fm.format("    extension       : %s%n", extension());
+        }
+        return sb.toString();
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java
index 09a1f091482..7d4b0a18822 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java
@@ -30,6 +30,7 @@ import java.nio.file.FileSystem;
 import java.nio.file.attribute.FileAttributeView;
 import java.nio.file.attribute.BasicFileAttributeView;
 import java.nio.file.attribute.FileStoreAttributeView;
+import java.util.Objects;
 
 /**
  * File store implementation for jrt file systems.
@@ -44,7 +45,7 @@ final class JrtFileStore extends FileStore {
 
     protected final FileSystem jrtfs;
 
-    JrtFileStore(AbstractJrtPath jrtPath) {
+    JrtFileStore(JrtPath jrtPath) {
         this.jrtfs = jrtPath.getFileSystem();
     }
 
@@ -71,9 +72,7 @@ final class JrtFileStore extends FileStore {
     @Override
     @SuppressWarnings("unchecked")
     public  V getFileStoreAttributeView(Class type) {
-        if (type == null) {
-            throw new NullPointerException();
-        }
+        Objects.requireNonNull(type, "type");
         return (V) null;
     }
 
@@ -99,7 +98,7 @@ final class JrtFileStore extends FileStore {
 
     @Override
     public boolean supportsFileAttributeView(Class type) {
-        return (type == BasicFileAttributeView.class
-                || type == JrtFileAttributeView.class);
+        return type == BasicFileAttributeView.class ||
+               type == JrtFileAttributeView.class;
     }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java
index 84a7a34daae..d5984095e99 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java
@@ -24,23 +24,47 @@
  */
 package jdk.internal.jrtfs;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.nio.file.LinkOption;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.ClosedFileSystemException;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
 import java.nio.file.FileSystemException;
 import java.nio.file.InvalidPathException;
+import java.nio.file.LinkOption;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.NotDirectoryException;
+import java.nio.file.OpenOption;
 import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.ReadOnlyFileSystemException;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.function.Function;
-import static java.util.stream.Collectors.toList;
-import jdk.internal.jimage.ImageReader;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
 import jdk.internal.jimage.ImageReader.Node;
-
+import static java.util.stream.Collectors.toList;
 
 /**
  * jrt file system implementation built on System jimage files.
@@ -51,33 +75,21 @@ import jdk.internal.jimage.ImageReader.Node;
  * but also compiled and delivered as part of the jrtfs.jar to support access
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-class JrtFileSystem extends AbstractJrtFileSystem {
+class JrtFileSystem extends FileSystem {
 
-    // System image reader
-    private ImageReader bootImage;
-    // root path
-    private final JrtPath rootPath;
+    private final JrtFileSystemProvider provider;
+    private final JrtPath rootPath = new JrtPath(this, "/");
     private volatile boolean isOpen;
+    private volatile boolean isClosable;
+    private SystemImage image;
 
-    // open a .jimage and build directory structure
-    private static ImageReader openImage(Path path) throws IOException {
-        ImageReader image = ImageReader.open(path);
-        image.getRootDirectory();
-        return image;
-    }
-
-    JrtFileSystem(JrtFileSystemProvider provider,
-            Map env)
-            throws IOException {
-        super(provider, env);
-        checkExists(SystemImages.moduleImageFile());
-
-        // open image file
-        this.bootImage = openImage(SystemImages.moduleImageFile());
-
-        byte[] root = new byte[]{'/'};
-        rootPath = new JrtPath(this, root);
-        isOpen = true;
+    JrtFileSystem(JrtFileSystemProvider provider, Map env)
+            throws IOException
+    {
+        this.provider = provider;
+        this.image = SystemImage.open();  // open image file
+        this.isOpen = true;
+        this.isClosable = env != null;
     }
 
     // FileSystem method implementations
@@ -88,6 +100,8 @@ class JrtFileSystem extends AbstractJrtFileSystem {
 
     @Override
     public void close() throws IOException {
+        if (!isClosable)
+            throw new UnsupportedOperationException();
         cleanup();
     }
 
@@ -95,237 +109,397 @@ class JrtFileSystem extends AbstractJrtFileSystem {
     protected void finalize() throws Throwable {
         try {
             cleanup();
-        } catch (IOException ignored) {
+        } catch (IOException ignored) {}
+    }
+
+    @Override
+    public FileSystemProvider provider() {
+        return provider;
+    }
+
+    @Override
+    public Iterable getRootDirectories() {
+        ArrayList dirs = new ArrayList<>();
+        dirs.add(getRootPath());
+        return dirs;
+    }
+
+    @Override
+    public JrtPath getPath(String first, String... more) {
+        if (more.length == 0) {
+            return new JrtPath(this, first);
         }
-        super.finalize();
-    }
-
-    // AbstractJrtFileSystem method implementations
-    @Override
-    JrtPath getRootPath() {
-        return rootPath;
+        StringBuilder sb = new StringBuilder();
+        sb.append(first);
+        for (String path : more) {
+            if (path.length() > 0) {
+                if (sb.length() > 0) {
+                    sb.append('/');
+                }
+                sb.append(path);
+            }
+        }
+        return new JrtPath(this, sb.toString());
     }
 
     @Override
-    boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
-        ensureOpen();
-        Node node1 = findNode(p1);
-        Node node2 = findNode(p2);
-        return node1.equals(node2);
+    public final boolean isReadOnly() {
+        return true;
     }
 
     @Override
-    boolean isLink(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath).isLink();
+    public final UserPrincipalLookupService getUserPrincipalLookupService() {
+        throw new UnsupportedOperationException();
     }
 
     @Override
-    AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
-        Node node = checkNode(jrtPath);
+    public final WatchService newWatchService() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Iterable getFileStores() {
+        ArrayList list = new ArrayList<>(1);
+        list.add(getFileStore(getRootPath()));
+        return list;
+    }
+
+    private static final Set supportedFileAttributeViews
+            = Collections.unmodifiableSet(
+                    new HashSet(Arrays.asList("basic", "jrt")));
+
+    @Override
+    public final Set supportedFileAttributeViews() {
+        return supportedFileAttributeViews;
+    }
+
+    @Override
+    public final String toString() {
+        return "jrt:/";
+    }
+
+    @Override
+    public final String getSeparator() {
+        return "/";
+    }
+
+    @Override
+    public PathMatcher getPathMatcher(String syntaxAndInput) {
+        int pos = syntaxAndInput.indexOf(':');
+        if (pos <= 0 || pos == syntaxAndInput.length()) {
+            throw new IllegalArgumentException();
+        }
+        String syntax = syntaxAndInput.substring(0, pos);
+        String input = syntaxAndInput.substring(pos + 1);
+        String expr;
+        if (syntax.equalsIgnoreCase("glob")) {
+            expr = JrtUtils.toRegexPattern(input);
+        } else if (syntax.equalsIgnoreCase("regex")) {
+            expr = input;
+        } else {
+                throw new UnsupportedOperationException("Syntax '" + syntax
+                        + "' not recognized");
+        }
+        // return matcher
+        final Pattern pattern = Pattern.compile(expr);
+        return (Path path) -> pattern.matcher(path.toString()).matches();
+    }
+
+    JrtPath resolveLink(JrtPath path) throws IOException {
+        Node node = checkNode(path);
         if (node.isLink()) {
             node = node.resolveLink();
-            return toJrtPath(getBytes(node.getName()));
+            return new JrtPath(this, node.getName());  // TBD, normalized?
         }
-
-        return jrtPath;
+        return path;
     }
 
-    @Override
-    JrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options)
+    JrtFileAttributes getFileAttributes(JrtPath path, LinkOption... options)
             throws IOException {
-        Node node = checkNode(jrtPath);
+        Node node = checkNode(path);
         if (node.isLink() && followLinks(options)) {
             return new JrtFileAttributes(node.resolveLink(true));
         }
         return new JrtFileAttributes(node);
     }
 
-    @Override
-    boolean exists(AbstractJrtPath jrtPath) throws IOException {
+    /**
+     * returns the list of child paths of the given directory "path"
+     *
+     * @param path name of the directory whose content is listed
+     * @return iterator for child paths of the given directory path
+     */
+    Iterator iteratorOf(JrtPath path, DirectoryStream.Filter filter)
+            throws IOException {
+        Node node = checkNode(path).resolveLink(true);
+        if (!node.isDirectory()) {
+            throw new NotDirectoryException(path.getName());
+        }
+        if (filter == null) {
+            return node.getChildren()
+                       .stream()
+                       .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
+                       .iterator();
+        }
+        return node.getChildren()
+                   .stream()
+                   .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
+                   .filter(p ->  { try { return filter.accept(p);
+                                   } catch (IOException x) {}
+                                   return false;
+                                  })
+                   .iterator();
+    }
+
+    // returns the content of the file resource specified by the path
+    byte[] getFileContent(JrtPath path) throws IOException {
+        Node node = checkNode(path);
+        if (node.isDirectory()) {
+            throw new FileSystemException(path + " is a directory");
+        }
+        //assert node.isResource() : "resource node expected here";
+        return image.getResource(node);
+    }
+
+    /////////////// Implementation details below this point //////////
+
+    // static utility methods
+    static ReadOnlyFileSystemException readOnly() {
+        return new ReadOnlyFileSystemException();
+    }
+
+    // do the supplied options imply that we have to chase symlinks?
+    static boolean followLinks(LinkOption... options) {
+        if (options != null) {
+            for (LinkOption lo : options) {
+                Objects.requireNonNull(lo);
+                if (lo == LinkOption.NOFOLLOW_LINKS) {
+                    return false;
+                } else {
+                    throw new AssertionError("should not reach here");
+                }
+            }
+        }
+        return true;
+    }
+
+    // check that the options passed are supported by (read-only) jrt file system
+    static void checkOptions(Set options) {
+        // check for options of null type and option is an intance of StandardOpenOption
+        for (OpenOption option : options) {
+            Objects.requireNonNull(option);
+            if (!(option instanceof StandardOpenOption)) {
+                throw new IllegalArgumentException();
+            }
+        }
+        if (options.contains(StandardOpenOption.WRITE) ||
+            options.contains(StandardOpenOption.APPEND)) {
+            throw readOnly();
+        }
+    }
+
+    // clean up this file system - called from finalize and close
+    void cleanup() throws IOException {
+        if (!isOpen) {
+            return;
+        }
+        synchronized (this) {
+            isOpen = false;
+            // close image reader and null out
+            image.close();
+            image = null;
+        }
+    }
+
+    // These methods throw read only file system exception
+    final void setTimes(JrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
+            throws IOException {
+        throw readOnly();
+    }
+
+    // These methods throw read only file system exception
+    final void createDirectory(JrtPath jrtPath, FileAttribute... attrs) throws IOException {
+        throw readOnly();
+    }
+
+    final void deleteFile(JrtPath jrtPath, boolean failIfNotExists)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final OutputStream newOutputStream(JrtPath jrtPath, OpenOption... options)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final void copyFile(boolean deletesrc, JrtPath srcPath, JrtPath dstPath, CopyOption... options)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final FileChannel newFileChannel(JrtPath path,
+            Set options,
+            FileAttribute... attrs)
+            throws IOException {
+        throw new UnsupportedOperationException("newFileChannel");
+    }
+
+    final InputStream newInputStream(JrtPath path) throws IOException {
+        return new ByteArrayInputStream(getFileContent(path));
+    }
+
+    final SeekableByteChannel newByteChannel(JrtPath path,
+            Set options,
+            FileAttribute... attrs)
+            throws IOException {
+        checkOptions(options);
+
+        byte[] buf = getFileContent(path);
+        final ReadableByteChannel rbc
+                = Channels.newChannel(new ByteArrayInputStream(buf));
+        final long size = buf.length;
+        return new SeekableByteChannel() {
+            long read = 0;
+
+            @Override
+            public boolean isOpen() {
+                return rbc.isOpen();
+            }
+
+            @Override
+            public long position() throws IOException {
+                return read;
+            }
+
+            @Override
+            public SeekableByteChannel position(long pos)
+                    throws IOException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public int read(ByteBuffer dst) throws IOException {
+                int n = rbc.read(dst);
+                if (n > 0) {
+                    read += n;
+                }
+                return n;
+            }
+
+            @Override
+            public SeekableByteChannel truncate(long size)
+                    throws IOException {
+                throw new NonWritableChannelException();
+            }
+
+            @Override
+            public int write(ByteBuffer src) throws IOException {
+                throw new NonWritableChannelException();
+            }
+
+            @Override
+            public long size() throws IOException {
+                return size;
+            }
+
+            @Override
+            public void close() throws IOException {
+                rbc.close();
+            }
+        };
+    }
+
+    final JrtFileStore getFileStore(JrtPath path) {
+        return new JrtFileStore(path);
+    }
+
+    final void ensureOpen() throws IOException {
+        if (!isOpen()) {
+            throw new ClosedFileSystemException();
+        }
+    }
+
+    final JrtPath getRootPath() {
+        return rootPath;
+    }
+
+    boolean isSameFile(JrtPath path1, JrtPath path2) throws IOException {
+        return checkNode(path1) == checkNode(path2);
+    }
+
+    boolean isLink(JrtPath path) throws IOException {
+        return checkNode(path).isLink();
+    }
+
+    boolean exists(JrtPath path) throws IOException {
         try {
-            checkNode(jrtPath);
+            checkNode(path);
         } catch (NoSuchFileException exp) {
             return false;
         }
         return true;
     }
 
-    @Override
-    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks)
+    boolean isDirectory(JrtPath path, boolean resolveLinks)
             throws IOException {
-        Node node = checkNode(jrtPath);
+        Node node = checkNode(path);
         return resolveLinks && node.isLink()
                 ? node.resolveLink(true).isDirectory()
                 : node.isDirectory();
     }
 
-    @Override
-    Iterator iteratorOf(AbstractJrtPath jrtPath) throws IOException {
-        Node node = checkNode(jrtPath).resolveLink(true);
-        if (!node.isDirectory()) {
-            throw new NotDirectoryException(getString(jrtPath.getName()));
+    JrtPath toRealPath(JrtPath path, LinkOption... options)
+            throws IOException {
+        Node node = checkNode(path);
+        if (followLinks(options) && node.isLink()) {
+            node = node.resolveLink();
         }
-
-        if (node.isRootDir()) {
-            return rootDirIterator(jrtPath);
-        } else if (node.isModulesDir()) {
-            return modulesDirIterator(jrtPath);
-        } else if (node.isPackagesDir()) {
-            return packagesDirIterator(jrtPath);
-        }
-
-        return nodesToIterator(jrtPath, node.getChildren());
+        // image node holds the real/absolute path name
+        return new JrtPath(this, node.getName(), true);
     }
 
-    @Override
-    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
-        final Node node = checkResource(jrtPath);
-        return bootImage.getResource(node);
-    }
-
-    // Implementation details below this point
-    // clean up this file system - called from finalize and close
-    private void cleanup() throws IOException {
-        if (!isOpen) {
-            return;
-        }
-
-        synchronized (this) {
-            isOpen = false;
-
-            // close all image reader and null out
-            bootImage.close();
-            bootImage = null;
-        }
-    }
-
-    private Node lookup(byte[] path) {
-        Node node = null;
+    private Node lookup(String path) {
         try {
-            node = bootImage.findNode(getString(path));
+            return image.findNode(path);
         } catch (RuntimeException re) {
-            throw new InvalidPathException(getString(path), re.toString());
+            throw new InvalidPathException(path, re.toString());
         }
-        return node;
     }
 
-    private Node lookupSymbolic(byte[] path) {
-        for (int i = 1; i < path.length; i++) {
-            if (path[i] == (byte) '/') {
-                byte[] prefix = Arrays.copyOfRange(path, 0, i);
-                Node node = lookup(prefix);
-                if (node == null) {
-                    break;
-                }
-
-                if (node.isLink()) {
-                    Node link = node.resolveLink(true);
-                    // resolved symbolic path concatenated to the rest of the path
-                    String resPath = link.getName() + getString(path).substring(i);
-                    byte[] resPathBytes = getBytes(resPath);
-                    node = lookup(resPathBytes);
-                    return node != null ? node : lookupSymbolic(resPathBytes);
-                }
+    private Node lookupSymbolic(String path) {
+        int i = 1;
+        while (i < path.length()) {
+            i = path.indexOf('/', i);
+            if (i == -1) {
+                break;
             }
+            String prefix = path.substring(0, i);
+            Node node = lookup(prefix);
+            if (node == null) {
+                break;
+            }
+            if (node.isLink()) {
+                Node link = node.resolveLink(true);
+                // resolved symbolic path concatenated to the rest of the path
+                String resPath = link.getName() + path.substring(i);
+                node = lookup(resPath);
+                return node != null ? node : lookupSymbolic(resPath);
+            }
+            i++;
         }
-
         return null;
     }
 
-    private Node findNode(AbstractJrtPath jrtPath) throws IOException {
-        return findNode(jrtPath.getResolvedPath());
-    }
-
-    private Node findNode(byte[] path) throws IOException {
-        Node node = lookup(path);
+    Node checkNode(JrtPath path) throws IOException {
+        ensureOpen();
+        String p = path.getResolvedPath();
+        Node node = lookup(p);
         if (node == null) {
-            node = lookupSymbolic(path);
+            node = lookupSymbolic(p);
             if (node == null) {
-                throw new NoSuchFileException(getString(path));
+                throw new NoSuchFileException(p);
             }
         }
         return node;
     }
-
-    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath.getResolvedPath());
-    }
-
-    private Node checkNode(byte[] path) throws IOException {
-        ensureOpen();
-        return findNode(path);
-    }
-
-    private Node checkResource(AbstractJrtPath jrtPath) throws IOException {
-        return checkResource(jrtPath.getResolvedPath());
-    }
-
-    private Node checkResource(byte[] path) throws IOException {
-        Node node = checkNode(path);
-        if (node.isDirectory()) {
-            throw new FileSystemException(getString(path) + " is a directory");
-        }
-
-        assert node.isResource() : "resource node expected here";
-        return node;
-    }
-
-    private JrtPath toJrtPath(String path) {
-        return toJrtPath(getBytes(path));
-    }
-
-    private JrtPath toJrtPath(byte[] path) {
-        return new JrtPath(this, path);
-    }
-
-    private Iterator nodesToIterator(AbstractJrtPath dir, List childNodes) {
-        Function nodeToPath =
-            child -> dir.resolve(
-                toJrtPath(child.getNameString()).getFileName());
-        return childNodes.stream().
-                map(nodeToPath).collect(toList()).
-                iterator();
-    }
-
-    private List rootChildren;
-
-    private synchronized void initRootChildren(AbstractJrtPath jrtPath) throws IOException {
-        if (rootChildren == null) {
-            rootChildren = new ArrayList<>();
-            rootChildren.addAll(findNode(jrtPath).getChildren());
-        }
-    }
-
-    private Iterator rootDirIterator(AbstractJrtPath jrtPath) throws IOException {
-        initRootChildren(jrtPath);
-        return nodesToIterator(jrtPath, rootChildren);
-    }
-
-    private List modulesChildren;
-
-    private synchronized void initModulesChildren(AbstractJrtPath jrtPath) throws IOException {
-        if (modulesChildren == null) {
-            modulesChildren = new ArrayList<>();
-            modulesChildren.addAll(findNode(jrtPath).getChildren());
-        }
-    }
-
-    private Iterator modulesDirIterator(AbstractJrtPath jrtPath) throws IOException {
-        initModulesChildren(jrtPath);
-        return nodesToIterator(jrtPath, modulesChildren);
-    }
-
-    private List packagesChildren;
-
-    private synchronized void initPackagesChildren(AbstractJrtPath jrtPath) throws IOException {
-        if (packagesChildren == null) {
-            packagesChildren = new ArrayList<>();
-            packagesChildren.addAll(findNode(jrtPath).getChildren());
-        }
-    }
-
-    private Iterator packagesDirIterator(AbstractJrtPath jrtPath) throws IOException {
-        initPackagesChildren(jrtPath);
-        return nodesToIterator(jrtPath, packagesChildren);
-    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
index 1cae4a5d173..746d61a273c 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,7 +70,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
     private void checkPermission() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            String home = SystemImages.RUNTIME_HOME;
+            String home = SystemImage.RUNTIME_HOME;
             FilePermission perm
                     = new FilePermission(home + File.separator + "-", "read");
             sm.checkPermission(perm);
@@ -101,15 +101,13 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
     @Override
     public FileSystem newFileSystem(URI uri, Map env)
             throws IOException {
+        Objects.requireNonNull(env);
         checkPermission();
         checkUri(uri);
-
-        if (env != null && env.containsKey("java.home")) {
+        if (env.containsKey("java.home")) {
             return newFileSystem((String)env.get("java.home"), uri, env);
         } else {
-            return SystemImages.hasModulesImage()
-                    ? new JrtFileSystem(this, env)
-                    : new JrtExplodedFileSystem(this, env);
+            return new JrtFileSystem(this, env);
         }
     }
 
@@ -121,7 +119,6 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
         if (Files.notExists(jrtfs)) {
             throw new IOException(jrtfs.toString() + " not exist");
         }
-
         Map newEnv = new HashMap<>(env);
         newEnv.remove("java.home");
         ClassLoader cl = newJrtFsLoader(jrtfs);
@@ -139,7 +136,6 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
         JrtFsLoader(URL[] urls) {
             super(urls);
         }
-
         @Override
         protected Class loadClass(String cn, boolean resolve)
                 throws ClassNotFoundException
@@ -208,21 +204,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
                 fs = this.theFileSystem;
                 if (fs == null) {
                     try {
-                        if (SystemImages.hasModulesImage()) {
-                            this.theFileSystem = fs = new JrtFileSystem(this, null) {
-                                @Override
-                                public void close() {
-                                    throw new UnsupportedOperationException();
-                                }
-                            };
-                        } else {
-                            this.theFileSystem = fs = new JrtExplodedFileSystem(this, null) {
-                                @Override
-                                public void close() {
-                                    throw new UnsupportedOperationException();
-                                }
-                            };
-                        }
+                        this.theFileSystem = fs = new JrtFileSystem(this, null);
                     } catch (IOException ioe) {
                         throw new InternalError(ioe);
                     }
@@ -240,69 +222,67 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
     }
 
     // Checks that the given file is a JrtPath
-    static final AbstractJrtPath toAbstractJrtPath(Path path) {
-        if (path == null) {
-            throw new NullPointerException();
-        }
-        if (!(path instanceof AbstractJrtPath)) {
+    static final JrtPath toJrtPath(Path path) {
+        Objects.requireNonNull(path, "path");
+        if (!(path instanceof JrtPath)) {
             throw new ProviderMismatchException();
         }
-        return (AbstractJrtPath) path;
+        return (JrtPath) path;
     }
 
     @Override
     public void checkAccess(Path path, AccessMode... modes) throws IOException {
-        toAbstractJrtPath(path).checkAccess(modes);
+        toJrtPath(path).checkAccess(modes);
     }
 
     @Override
     public Path readSymbolicLink(Path link) throws IOException {
-        return toAbstractJrtPath(link).readSymbolicLink();
+        return toJrtPath(link).readSymbolicLink();
     }
 
     @Override
     public void copy(Path src, Path target, CopyOption... options)
             throws IOException {
-        toAbstractJrtPath(src).copy(toAbstractJrtPath(target), options);
+        toJrtPath(src).copy(toJrtPath(target), options);
     }
 
     @Override
     public void createDirectory(Path path, FileAttribute... attrs)
             throws IOException {
-        toAbstractJrtPath(path).createDirectory(attrs);
+        toJrtPath(path).createDirectory(attrs);
     }
 
     @Override
     public final void delete(Path path) throws IOException {
-        toAbstractJrtPath(path).delete();
+        toJrtPath(path).delete();
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public  V
             getFileAttributeView(Path path, Class type, LinkOption... options) {
-        return JrtFileAttributeView.get(toAbstractJrtPath(path), type, options);
+        return JrtFileAttributeView.get(toJrtPath(path), type, options);
     }
 
     @Override
     public FileStore getFileStore(Path path) throws IOException {
-        return toAbstractJrtPath(path).getFileStore();
+        return toJrtPath(path).getFileStore();
     }
 
     @Override
     public boolean isHidden(Path path) {
-        return toAbstractJrtPath(path).isHidden();
+        return toJrtPath(path).isHidden();
     }
 
     @Override
     public boolean isSameFile(Path path, Path other) throws IOException {
-        return toAbstractJrtPath(path).isSameFile(other);
+        return toJrtPath(path).isSameFile(other);
     }
 
     @Override
     public void move(Path src, Path target, CopyOption... options)
             throws IOException {
-        toAbstractJrtPath(src).move(toAbstractJrtPath(target), options);
+        toJrtPath(src).move(toJrtPath(target), options);
     }
 
     @Override
@@ -319,13 +299,13 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
             Set options,
             FileAttribute... attrs)
             throws IOException {
-        return toAbstractJrtPath(path).newByteChannel(options, attrs);
+        return toJrtPath(path).newByteChannel(options, attrs);
     }
 
     @Override
     public DirectoryStream newDirectoryStream(
             Path path, Filter filter) throws IOException {
-        return toAbstractJrtPath(path).newDirectoryStream(filter);
+        return toJrtPath(path).newDirectoryStream(filter);
     }
 
     @Override
@@ -333,19 +313,19 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
             Set options,
             FileAttribute... attrs)
             throws IOException {
-        return toAbstractJrtPath(path).newFileChannel(options, attrs);
+        return toJrtPath(path).newFileChannel(options, attrs);
     }
 
     @Override
     public InputStream newInputStream(Path path, OpenOption... options)
             throws IOException {
-        return toAbstractJrtPath(path).newInputStream(options);
+        return toJrtPath(path).newInputStream(options);
     }
 
     @Override
     public OutputStream newOutputStream(Path path, OpenOption... options)
             throws IOException {
-        return toAbstractJrtPath(path).newOutputStream(options);
+        return toJrtPath(path).newOutputStream(options);
     }
 
     @Override
@@ -354,7 +334,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
             readAttributes(Path path, Class type, LinkOption... options)
             throws IOException {
         if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) {
-            return (A) toAbstractJrtPath(path).getAttributes(options);
+            return (A) toJrtPath(path).getAttributes(options);
         }
         return null;
     }
@@ -363,13 +343,13 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
     public Map
             readAttributes(Path path, String attribute, LinkOption... options)
             throws IOException {
-        return toAbstractJrtPath(path).readAttributes(attribute, options);
+        return toJrtPath(path).readAttributes(attribute, options);
     }
 
     @Override
     public void setAttribute(Path path, String attribute,
             Object value, LinkOption... options)
             throws IOException {
-        toAbstractJrtPath(path).setAttribute(attribute, value, options);
+        toJrtPath(path).setAttribute(attribute, value, options);
     }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java
index 3bd0f6c1fbd..cf3bbd8d2d9 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,30 @@
  */
 package jdk.internal.jrtfs;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.*;
+import java.nio.file.DirectoryStream.Filter;;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileTime;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import static java.nio.file.StandardOpenOption.*;
+import static java.nio.file.StandardCopyOption.*;
+
 /**
- * jrt Path implementation for jrt on .jimage files.
+ * Base class for Path implementation of jrt file systems.
  *
  * @implNote This class needs to maintain JDK 8 source compatibility.
  *
@@ -33,23 +55,756 @@ package jdk.internal.jrtfs;
  * but also compiled and delivered as part of the jrtfs.jar to support access
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-final class JrtPath extends AbstractJrtPath {
+final class JrtPath implements Path {
 
-    JrtPath(AbstractJrtFileSystem jrtfs, byte[] path) {
-        this(jrtfs, path, false);
+    final JrtFileSystem jrtfs;
+    private final String path;
+    private volatile int[] offsets;
+
+    JrtPath(JrtFileSystem jrtfs, String path) {
+        this.jrtfs = jrtfs;
+        this.path = normalize(path);
+        this.resolved = null;
     }
 
-    JrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) {
-        super(jrtfs, path, normalized);
+    JrtPath(JrtFileSystem jrtfs, String path, boolean normalized) {
+        this.jrtfs = jrtfs;
+        this.path = normalized ? path : normalize(path);
+        this.resolved = null;
+    }
+
+    final String getName() {
+        return path;
     }
 
     @Override
-    protected JrtPath newJrtPath(byte[] path) {
-        return new JrtPath(jrtfs, path);
+    public final JrtPath getRoot() {
+        if (this.isAbsolute()) {
+            return jrtfs.getRootPath();
+        } else {
+            return null;
+        }
     }
 
     @Override
-    protected JrtPath newJrtPath(byte[] path, boolean normalized) {
-        return new JrtPath(jrtfs, path, normalized);
+    public final JrtPath getFileName() {
+        if (path.length() == 0)
+            return this;
+        if (path.length() == 1 && path.charAt(0) == '/')
+            return null;
+        int off = path.lastIndexOf('/');
+        if (off == -1)
+            return this;
+        return new JrtPath(jrtfs, path.substring(off + 1), true);
+    }
+
+    @Override
+    public final JrtPath getParent() {
+        initOffsets();
+        int count = offsets.length;
+        if (count == 0) {     // no elements so no parent
+            return null;
+        }
+        int off = offsets[count - 1] - 1;
+        if (off <= 0) {       // parent is root only (may be null)
+            return getRoot();
+        }
+        return new JrtPath(jrtfs, path.substring(0, off));
+    }
+
+    @Override
+    public final int getNameCount() {
+        initOffsets();
+        return offsets.length;
+    }
+
+    @Override
+    public final JrtPath getName(int index) {
+        initOffsets();
+        if (index < 0 || index >= offsets.length) {
+            throw new IllegalArgumentException();
+        }
+        int begin = offsets[index];
+        int end;
+        if (index == (offsets.length - 1)) {
+            end = path.length();
+        } else {
+            end = offsets[index + 1];
+        }
+        return new JrtPath(jrtfs, path.substring(begin, end));
+    }
+
+    @Override
+    public final JrtPath subpath(int beginIndex, int endIndex) {
+        initOffsets();
+        if (beginIndex < 0 || endIndex > offsets.length ||
+            beginIndex >= endIndex) {
+            throw new IllegalArgumentException();
+        }
+        // starting/ending offsets
+        int begin = offsets[beginIndex];
+        int end;
+        if (endIndex == offsets.length) {
+            end = path.length();
+        } else {
+            end = offsets[endIndex];
+        }
+        return new JrtPath(jrtfs, path.substring(begin, end));
+    }
+
+    @Override
+    public final JrtPath toRealPath(LinkOption... options) throws IOException {
+        return jrtfs.toRealPath(this, options);
+    }
+
+    @Override
+    public final JrtPath toAbsolutePath() {
+        if (isAbsolute())
+            return this;
+        return new JrtPath(jrtfs, "/" + path, true);
+    }
+
+    @Override
+    public final URI toUri() {
+        try {
+            return new URI("jrt", toAbsolutePath().path, null);
+        } catch (URISyntaxException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    private boolean equalsNameAt(JrtPath other, int index) {
+        int mbegin = offsets[index];
+        int mlen;
+        if (index == (offsets.length - 1)) {
+            mlen = path.length() - mbegin;
+        } else {
+            mlen = offsets[index + 1] - mbegin - 1;
+        }
+        int obegin = other.offsets[index];
+        int olen;
+        if (index == (other.offsets.length - 1)) {
+            olen = other.path.length() - obegin;
+        } else {
+            olen = other.offsets[index + 1] - obegin - 1;
+        }
+        if (mlen != olen) {
+            return false;
+        }
+        int n = 0;
+        while (n < mlen) {
+            if (path.charAt(mbegin + n) != other.path.charAt(obegin + n)) {
+                return false;
+            }
+            n++;
+        }
+        return true;
+    }
+
+    @Override
+    public final JrtPath relativize(Path other) {
+        final JrtPath o = checkPath(other);
+        if (o.equals(this)) {
+            return new JrtPath(jrtfs, "", true);
+        }
+        if (path.length() == 0) {
+            return o;
+        }
+        if (jrtfs != o.jrtfs || isAbsolute() != o.isAbsolute()) {
+            throw new IllegalArgumentException();
+        }
+        final String tp = this.path;
+        final String op = o.path;
+        if (op.startsWith(tp)) {    // fast path
+            int off = tp.length();
+            if (op.charAt(off - 1) == '/')
+                return new JrtPath(jrtfs, op.substring(off), true);
+            if (op.charAt(off) == '/')
+                return new JrtPath(jrtfs, op.substring(off + 1), true);
+        }
+        int mc = this.getNameCount();
+        int oc = o.getNameCount();
+        int n = Math.min(mc, oc);
+        int i = 0;
+        while (i < n) {
+            if (!equalsNameAt(o, i)) {
+                break;
+            }
+            i++;
+        }
+        int dotdots = mc - i;
+        int len = dotdots * 3 - 1;
+        if (i < oc) {
+            len += (o.path.length() - o.offsets[i] + 1);
+        }
+        StringBuilder sb  = new StringBuilder(len);
+        while (dotdots > 0) {
+            sb.append("..");
+            if (sb.length() < len) {  // no tailing slash at the end
+                sb.append('/');
+            }
+            dotdots--;
+        }
+        if (i < oc) {
+            sb.append(o.path, o.offsets[i], o.path.length());
+        }
+        return new JrtPath(jrtfs, sb.toString(), true);
+    }
+
+    @Override
+    public JrtFileSystem getFileSystem() {
+        return jrtfs;
+    }
+
+    @Override
+    public final boolean isAbsolute() {
+        return path.length() > 0 && path.charAt(0) == '/';
+    }
+
+    @Override
+    public final JrtPath resolve(Path other) {
+        final JrtPath o = checkPath(other);
+        if (this.path.length() == 0 || o.isAbsolute()) {
+            return o;
+        }
+        if (o.path.length() == 0) {
+            return this;
+        }
+        StringBuilder sb = new StringBuilder(path.length() + o.path.length());
+        sb.append(path);
+        if (path.charAt(path.length() - 1) != '/')
+            sb.append('/');
+        sb.append(o.path);
+        return new JrtPath(jrtfs, sb.toString(), true);
+    }
+
+    @Override
+    public final Path resolveSibling(Path other) {
+        Objects.requireNonNull(other, "other");
+        Path parent = getParent();
+        return (parent == null) ? other : parent.resolve(other);
+    }
+
+    @Override
+    public final boolean startsWith(Path other) {
+        if (!(Objects.requireNonNull(other) instanceof JrtPath))
+            return false;
+        final JrtPath o = (JrtPath)other;
+        final String tp = this.path;
+        final String op = o.path;
+        if (isAbsolute() != o.isAbsolute() || !tp.startsWith(op)) {
+            return false;
+        }
+        int off = op.length();
+        if (off == 0) {
+            return tp.length() == 0;
+        }
+        // check match is on name boundary
+        return tp.length() == off || tp.charAt(off) == '/' ||
+               off == 0 || op.charAt(off - 1) == '/';
+    }
+
+    @Override
+    public final boolean endsWith(Path other) {
+        if (!(Objects.requireNonNull(other) instanceof JrtPath))
+            return false;
+        final JrtPath o = (JrtPath)other;
+        final JrtPath t = this;
+        int olast = o.path.length() - 1;
+        if (olast > 0 && o.path.charAt(olast) == '/') {
+            olast--;
+        }
+        int last = t.path.length() - 1;
+        if (last > 0 && t.path.charAt(last) == '/') {
+            last--;
+        }
+        if (olast == -1) {  // o.path.length == 0
+            return last == -1;
+        }
+        if ((o.isAbsolute() && (!t.isAbsolute() || olast != last))
+            || last < olast) {
+            return false;
+        }
+        for (; olast >= 0; olast--, last--) {
+            if (o.path.charAt(olast) != t.path.charAt(last)) {
+                return false;
+            }
+        }
+        return o.path.charAt(olast + 1) == '/' ||
+               last == -1 || t.path.charAt(last) == '/';
+    }
+
+    @Override
+    public final JrtPath resolve(String other) {
+        return resolve(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final Path resolveSibling(String other) {
+        return resolveSibling(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final boolean startsWith(String other) {
+        return startsWith(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final boolean endsWith(String other) {
+        return endsWith(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final JrtPath normalize() {
+        String res = getResolved();
+        if (res == path) {  // no change
+            return this;
+        }
+        return new JrtPath(jrtfs, res, true);
+    }
+
+    private JrtPath checkPath(Path path) {
+        Objects.requireNonNull(path);
+        if (!(path instanceof JrtPath))
+            throw new ProviderMismatchException();
+        return (JrtPath) path;
+    }
+
+    // create offset list if not already created
+    private void initOffsets() {
+        if (this.offsets == null) {
+            int len = path.length();
+            // count names
+            int count = 0;
+            int off = 0;
+            while (off < len) {
+                char c = path.charAt(off++);
+                if (c != '/') {
+                    count++;
+                    off = path.indexOf('/', off);
+                    if (off == -1)
+                        break;
+                }
+            }
+            // populate offsets
+            int[] offsets = new int[count];
+            count = 0;
+            off = 0;
+            while (off < len) {
+                char c = path.charAt(off);
+                if (c == '/') {
+                    off++;
+                } else {
+                    offsets[count++] = off++;
+                    off = path.indexOf('/', off);
+                    if (off == -1)
+                        break;
+                }
+            }
+            this.offsets = offsets;
+        }
+    }
+
+    private volatile String resolved;
+
+    final String getResolvedPath() {
+        String r = resolved;
+        if (r == null) {
+            if (isAbsolute()) {
+                r = getResolved();
+            } else {
+                r = toAbsolutePath().getResolvedPath();
+            }
+            resolved = r;
+        }
+        return r;
+    }
+
+    // removes redundant slashs, replace "\" to separator "/"
+    // and check for invalid characters
+    private static String normalize(String path) {
+        int len = path.length();
+        if (len == 0) {
+            return path;
+        }
+        char prevC = 0;
+        for (int i = 0; i < len; i++) {
+            char c = path.charAt(i);
+            if (c == '\\' || c == '\u0000') {
+                return normalize(path, i);
+            }
+            if (c == '/' && prevC == '/') {
+                return normalize(path, i - 1);
+            }
+            prevC = c;
+        }
+        if (prevC == '/' && len > 1) {
+            return path.substring(0, len - 1);
+        }
+        return path;
+    }
+
+    private static String normalize(String path, int off) {
+        int len = path.length();
+        StringBuilder to = new StringBuilder(len);
+        to.append(path, 0, off);
+        char prevC = 0;
+        while (off < len) {
+            char c = path.charAt(off++);
+            if (c == '\\') {
+                c = '/';
+            }
+            if (c == '/' && prevC == '/') {
+                continue;
+            }
+            if (c == '\u0000') {
+                throw new InvalidPathException(path,
+                        "Path: nul character not allowed");
+            }
+            to.append(c);
+            prevC = c;
+        }
+        len = to.length();
+        if (len > 1 && to.charAt(len - 1) == '/') {
+            to.deleteCharAt(len - 1);
+        }
+        return to.toString();
+    }
+
+    // Remove DotSlash(./) and resolve DotDot (..) components
+    private String getResolved() {
+        if (path.length() == 0) {
+            return path;
+        }
+        if (path.indexOf('.') == -1) {
+            return path;
+        }
+        int length = path.length();
+        char[] to = new char[length];
+        int nc = getNameCount();
+        int[] lastM = new int[nc];
+        int lastMOff = -1;
+        int m = 0;
+        for (int i = 0; i < nc; i++) {
+            int n = offsets[i];
+            int len = (i == offsets.length - 1) ? length - n
+                                                : offsets[i + 1] - n - 1;
+            if (len == 1 && path.charAt(n) == '.') {
+                if (m == 0 && path.charAt(0) == '/')   // absolute path
+                    to[m++] = '/';
+                continue;
+            }
+            if (len == 2 && path.charAt(n) == '.' && path.charAt(n + 1) == '.') {
+                if (lastMOff >= 0) {
+                    m = lastM[lastMOff--];    // retreat
+                    continue;
+                }
+                if (path.charAt(0) == '/') {  // "/../xyz" skip
+                    if (m == 0)
+                        to[m++] = '/';
+                } else {                      // "../xyz" -> "../xyz"
+                    if (m != 0 && to[m-1] != '/')
+                        to[m++] = '/';
+                    while (len-- > 0)
+                        to[m++] = path.charAt(n++);
+                }
+                continue;
+            }
+            if (m == 0 && path.charAt(0) == '/' ||   // absolute path
+                m != 0 && to[m-1] != '/') {   // not the first name
+                to[m++] = '/';
+            }
+            lastM[++lastMOff] = m;
+            while (len-- > 0)
+                to[m++] = path.charAt(n++);
+        }
+        if (m > 1 && to[m - 1] == '/')
+            m--;
+        return (m == to.length) ? new String(to) : new String(to, 0, m);
+    }
+
+    @Override
+    public final String toString() {
+        return path;
+    }
+
+    @Override
+    public final int hashCode() {
+        return path.hashCode();
+    }
+
+    @Override
+    public final boolean equals(Object obj) {
+        return obj instanceof JrtPath &&
+               this.path.equals(((JrtPath) obj).path);
+    }
+
+    @Override
+    public final int compareTo(Path other) {
+        final JrtPath o = checkPath(other);
+        return path.compareTo(o.path);
+    }
+
+    @Override
+    public final WatchKey register(
+            WatchService watcher,
+            WatchEvent.Kind[] events,
+            WatchEvent.Modifier... modifiers) {
+        Objects.requireNonNull(watcher, "watcher");
+        Objects.requireNonNull(events, "events");
+        Objects.requireNonNull(modifiers, "modifiers");
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final WatchKey register(WatchService watcher, WatchEvent.Kind... events) {
+        return register(watcher, events, new WatchEvent.Modifier[0]);
+    }
+
+    @Override
+    public final File toFile() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Iterator iterator() {
+        return new Iterator() {
+            private int i = 0;
+
+            @Override
+            public boolean hasNext() {
+                return (i < getNameCount());
+            }
+
+            @Override
+            public Path next() {
+                if (i < getNameCount()) {
+                    Path result = getName(i);
+                    i++;
+                    return result;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            @Override
+            public void remove() {
+                throw new ReadOnlyFileSystemException();
+            }
+        };
+    }
+
+    // Helpers for JrtFileSystemProvider and JrtFileSystem
+
+    final JrtPath readSymbolicLink() throws IOException {
+        if (!jrtfs.isLink(this)) {
+            throw new IOException("not a symbolic link");
+        }
+        return jrtfs.resolveLink(this);
+    }
+
+    final boolean isHidden() {
+        return false;
+    }
+
+    final void createDirectory(FileAttribute... attrs)
+            throws IOException {
+        jrtfs.createDirectory(this, attrs);
+    }
+
+    final InputStream newInputStream(OpenOption... options) throws IOException {
+        if (options.length > 0) {
+            for (OpenOption opt : options) {
+                if (opt != READ) {
+                    throw new UnsupportedOperationException("'" + opt + "' not allowed");
+                }
+            }
+        }
+        return jrtfs.newInputStream(this);
+    }
+
+    final DirectoryStream newDirectoryStream(Filter filter)
+            throws IOException {
+        return new JrtDirectoryStream(this, filter);
+    }
+
+    final void delete() throws IOException {
+        jrtfs.deleteFile(this, true);
+    }
+
+    final void deleteIfExists() throws IOException {
+        jrtfs.deleteFile(this, false);
+    }
+
+    final JrtFileAttributes getAttributes(LinkOption... options) throws IOException {
+        JrtFileAttributes zfas = jrtfs.getFileAttributes(this, options);
+        if (zfas == null) {
+            throw new NoSuchFileException(toString());
+        }
+        return zfas;
+    }
+
+    final void setAttribute(String attribute, Object value, LinkOption... options)
+            throws IOException {
+        JrtFileAttributeView.setAttribute(this, attribute, value);
+    }
+
+    final Map readAttributes(String attributes, LinkOption... options)
+            throws IOException {
+        return JrtFileAttributeView.readAttributes(this, attributes, options);
+    }
+
+    final void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
+            throws IOException {
+        jrtfs.setTimes(this, mtime, atime, ctime);
+    }
+
+    final FileStore getFileStore() throws IOException {
+        // each JrtFileSystem only has one root (as requested for now)
+        if (exists()) {
+            return jrtfs.getFileStore(this);
+        }
+        throw new NoSuchFileException(path);
+    }
+
+    final boolean isSameFile(Path other) throws IOException {
+        if (this == other || this.equals(other)) {
+            return true;
+        }
+        if (other == null || this.getFileSystem() != other.getFileSystem()) {
+            return false;
+        }
+        this.checkAccess();
+        JrtPath o = (JrtPath) other;
+        o.checkAccess();
+        return this.getResolvedPath().equals(o.getResolvedPath()) ||
+               jrtfs.isSameFile(this, o);
+    }
+
+    final SeekableByteChannel newByteChannel(Set options,
+                                             FileAttribute... attrs)
+            throws IOException
+    {
+        return jrtfs.newByteChannel(this, options, attrs);
+    }
+
+    final FileChannel newFileChannel(Set options,
+            FileAttribute... attrs)
+            throws IOException {
+        return jrtfs.newFileChannel(this, options, attrs);
+    }
+
+    final void checkAccess(AccessMode... modes) throws IOException {
+        if (modes.length == 0) {    // check if the path exists
+            jrtfs.checkNode(this);  // no need to follow link. the "link" node
+                                    // is built from real node under "/module"
+        } else {
+            boolean w = false;
+            for (AccessMode mode : modes) {
+                switch (mode) {
+                    case READ:
+                        break;
+                    case WRITE:
+                        w = true;
+                        break;
+                    case EXECUTE:
+                        throw new AccessDeniedException(toString());
+                    default:
+                        throw new UnsupportedOperationException();
+                }
+            }
+            jrtfs.checkNode(this);
+            if (w && jrtfs.isReadOnly()) {
+                throw new AccessDeniedException(toString());
+            }
+        }
+    }
+
+    final boolean exists() {
+        try {
+            return jrtfs.exists(this);
+        } catch (IOException x) {}
+        return false;
+    }
+
+    final OutputStream newOutputStream(OpenOption... options) throws IOException {
+        if (options.length == 0) {
+            return jrtfs.newOutputStream(this, CREATE_NEW, WRITE);
+        }
+        return jrtfs.newOutputStream(this, options);
+    }
+
+    final void move(JrtPath target, CopyOption... options) throws IOException {
+        if (this.jrtfs == target.jrtfs) {
+            jrtfs.copyFile(true, this, target, options);
+        } else {
+            copyToTarget(target, options);
+            delete();
+        }
+    }
+
+    final void copy(JrtPath target, CopyOption... options) throws IOException {
+        if (this.jrtfs == target.jrtfs) {
+            jrtfs.copyFile(false, this, target, options);
+        } else {
+            copyToTarget(target, options);
+        }
+    }
+
+    private void copyToTarget(JrtPath target, CopyOption... options)
+            throws IOException {
+        boolean replaceExisting = false;
+        boolean copyAttrs = false;
+        for (CopyOption opt : options) {
+            if (opt == REPLACE_EXISTING) {
+                replaceExisting = true;
+            } else if (opt == COPY_ATTRIBUTES) {
+                copyAttrs = true;
+            }
+        }
+        // attributes of source file
+        BasicFileAttributes jrtfas = getAttributes();
+        // check if target exists
+        boolean exists;
+        if (replaceExisting) {
+            try {
+                target.deleteIfExists();
+                exists = false;
+            } catch (DirectoryNotEmptyException x) {
+                exists = true;
+            }
+        } else {
+            exists = target.exists();
+        }
+        if (exists) {
+            throw new FileAlreadyExistsException(target.toString());
+        }
+        if (jrtfas.isDirectory()) {
+            // create directory or file
+            target.createDirectory();
+        } else {
+            try (InputStream is = jrtfs.newInputStream(this);
+                 OutputStream os = target.newOutputStream()) {
+                byte[] buf = new byte[8192];
+                int n;
+                while ((n = is.read(buf)) != -1) {
+                    os.write(buf, 0, n);
+                }
+            }
+        }
+        if (copyAttrs) {
+            BasicFileAttributeView view =
+                Files.getFileAttributeView(target, BasicFileAttributeView.class);
+            try {
+                view.setTimes(jrtfas.lastModifiedTime(),
+                              jrtfas.lastAccessTime(),
+                              jrtfas.creationTime());
+            } catch (IOException x) {
+                try {
+                    target.delete();  // rollback?
+                } catch (IOException ignore) {}
+                throw x;
+            }
+        }
     }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java
similarity index 68%
rename from jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java
rename to jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java
index 249479ed445..7b155feba88 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java
@@ -24,17 +24,22 @@
  */
 package jdk.internal.jrtfs;
 
+import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
+import java.nio.file.FileSystemNotFoundException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.AccessController;
 import java.security.CodeSource;
 import java.security.PrivilegedAction;
 
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReader.Node;
+
 /**
  * @implNote This class needs to maintain JDK 8 source compatibility.
  *
@@ -42,20 +47,47 @@ import java.security.PrivilegedAction;
  * but also compiled and delivered as part of the jrtfs.jar to support access
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-final class SystemImages {
-    private SystemImages() {}
+abstract class SystemImage {
 
+    abstract Node findNode(String path);
+    abstract byte[] getResource(Node node) throws IOException;
+    abstract void close() throws IOException;
+
+    static SystemImage open() throws IOException {
+        if (modulesImageExists) {
+            // open a .jimage and build directory structure
+            final ImageReader image = ImageReader.open(moduleImageFile);
+            image.getRootDirectory();
+            return new SystemImage() {
+                @Override
+                Node findNode(String path) {
+                    return image.findNode(path);
+                }
+                @Override
+                byte[] getResource(Node node) throws IOException {
+                    return image.getResource(node);
+                }
+                @Override
+                void close() throws IOException {
+                    image.close();
+                }
+            };
+        }
+        if (Files.notExists(explodedModulesDir))
+            throw new FileSystemNotFoundException(explodedModulesDir.toString());
+        return new ExplodedImage(explodedModulesDir);
+    }
 
     static final String RUNTIME_HOME;
     // "modules" jimage file Path
-    private static final Path moduleImageFile;
+    final static Path moduleImageFile;
     // "modules" jimage exists or not?
-    private static final boolean modulesImageExists;
+    final static boolean modulesImageExists;
     // /modules directory Path
-    private static final Path explodedModulesDir;
+    static final Path explodedModulesDir;
 
     static {
-        PrivilegedAction pa = SystemImages::findHome;
+        PrivilegedAction pa = SystemImage::findHome;
         RUNTIME_HOME = AccessController.doPrivileged(pa);
 
         FileSystem fs = FileSystems.getDefault();
@@ -71,25 +103,13 @@ final class SystemImages {
             });
     }
 
-    static boolean hasModulesImage() {
-        return modulesImageExists;
-    }
-
-    static Path moduleImageFile() {
-        return moduleImageFile;
-    }
-
-    static Path explodedModulesDir() {
-        return explodedModulesDir;
-    }
-
     /**
      * Returns the appropriate JDK home for this usage of the FileSystemProvider.
      * When the CodeSource is null (null loader) then jrt:/ is the current runtime,
      * otherwise the JDK home is located relative to jrt-fs.jar.
      */
     private static String findHome() {
-        CodeSource cs = SystemImages.class.getProtectionDomain().getCodeSource();
+        CodeSource cs = SystemImage.class.getProtectionDomain().getCodeSource();
         if (cs == null)
             return System.getProperty("java.home");
 
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
index 15688e1a573..234a86a9271 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
@@ -52,6 +52,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Properties;
 import java.util.Set;
 import java.util.Stack;
 import java.util.StringTokenizer;
@@ -69,6 +70,7 @@ import jdk.internal.util.jar.InvalidJarIndexError;
 import jdk.internal.util.jar.JarIndex;
 import sun.net.util.URLUtil;
 import sun.net.www.ParseUtil;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This class is used to maintain a search path of URLs for loading classes
@@ -78,20 +80,15 @@ import sun.net.www.ParseUtil;
  */
 public class URLClassPath {
     private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
-    private static final String JAVA_HOME;
     private static final String JAVA_VERSION;
     private static final boolean DEBUG;
     private static final boolean DISABLE_JAR_CHECKING;
 
     static {
-        JAVA_HOME = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("java.home"));
-        JAVA_VERSION = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("java.version"));
-        DEBUG        = (java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
-        String p = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
+        Properties props = GetPropertyAction.getProperties();
+        JAVA_VERSION = props.getProperty("java.version");
+        DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null);
+        String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking");
         DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
     }
 
diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java
index 7d315ba7057..58f235d6ccd 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java
@@ -33,6 +33,7 @@ import java.util.Locale;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import sun.security.util.SecurityConstants;
+import sun.security.action.GetPropertyAction;
 
 /**
  * Helper class used to load the {@link java.lang.System.LoggerFinder}.
@@ -79,9 +80,8 @@ public final class LoggerFinderLoader {
 
     // Get configuration error policy
     private static ErrorPolicy configurationErrorPolicy() {
-        final PrivilegedAction getConfigurationErrorPolicy =
-                () -> System.getProperty("jdk.logger.finder.error");
-        String errorPolicy = AccessController.doPrivileged(getConfigurationErrorPolicy);
+        String errorPolicy =
+                GetPropertyAction.getProperty("jdk.logger.finder.error");
         if (errorPolicy == null || errorPolicy.isEmpty()) {
             return ErrorPolicy.WARNING;
         }
@@ -95,9 +95,8 @@ public final class LoggerFinderLoader {
     // Whether multiple provider should be considered as an error.
     // This is further submitted to the configuration error policy.
     private static boolean ensureSingletonProvider() {
-        final PrivilegedAction ensureSingletonProvider =
-                () -> Boolean.getBoolean("jdk.logger.finder.singleton");
-        return AccessController.doPrivileged(ensureSingletonProvider);
+        return Boolean.parseBoolean(
+                GetPropertyAction.getProperty("jdk.logger.finder.singleton"));
     }
 
     private static Iterator findLoggerFinderProviders() {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java
index de4451fd35c..c90a7b24e38 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java
@@ -55,8 +55,8 @@ public class SimpleConsoleLogger extends LoggerConfiguration
             PlatformLogger.toPlatformLevel(DEFAULT_LEVEL);
 
     static Level getDefaultLevel() {
-        String levelName = AccessController.doPrivileged(
-                new GetPropertyAction("jdk.system.logger.level", "INFO"));
+        String levelName = GetPropertyAction
+                .getProperty("jdk.system.logger.level", "INFO");
         try {
             return Level.valueOf(levelName);
         } catch (IllegalArgumentException iae) {
@@ -425,8 +425,8 @@ public class SimpleConsoleLogger extends LoggerConfiguration
         // Make it easier to wrap Logger...
         static private final String[] skips;
         static {
-            String additionalPkgs = AccessController.doPrivileged(
-                new GetPropertyAction("jdk.logger.packages"));
+            String additionalPkgs =
+                    GetPropertyAction.getProperty("jdk.logger.packages");
             skips = additionalPkgs == null ? new String[0] : additionalPkgs.split(",");
         }
 
@@ -485,7 +485,7 @@ public class SimpleConsoleLogger extends LoggerConfiguration
             //    jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java
             // to fail - because that test has a testcase which somehow references
             // PlatformLogger and counts the number of generated lambda classes.
-            String format = AccessController.doPrivileged(new GetPropertyAction(key));
+            String format = GetPropertyAction.getProperty(key);
 
             if (format == null && defaultPropertyGetter != null) {
                 format = defaultPropertyGetter.apply(key);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
index 7ca99963791..f9699f7fdc1 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
@@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
 import jdk.internal.module.ServicesCatalog;
-import sun.reflect.ConstantPool;
+import jdk.internal.reflect.ConstantPool;
 import sun.reflect.annotation.AnnotationType;
 import sun.nio.ch.Interruptible;
 
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java
new file mode 100644
index 00000000000..c344f8adc7c
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.misc;
+
+import java.io.ObjectInputStream;
+
+/**
+ * The interface to specify methods for accessing {@code ObjectInputStream}
+ * @author sjiang
+ */
+public interface JavaObjectInputStreamAccess {
+    /**
+     * Sets a descriptor validating.
+     * @param ois stream to have the descriptors validated
+     * @param validator validator used to validate a descriptor.
+     */
+    public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator);
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java b/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java
new file mode 100644
index 00000000000..2b543a30721
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.misc;
+
+import java.io.ObjectStreamClass;
+
+/**
+ * A callback used by {@code ObjectInputStream} to do descriptor validation.
+ *
+ * @author sjiang
+ */
+public interface ObjectStreamClassValidator {
+    /**
+     * This method will be called by ObjectInputStream to
+     * check a descriptor just before creating an object described by this descriptor.
+     * The object will not be created if this method throws a {@code RuntimeException}.
+     * @param descriptor descriptor to be checked.
+     */
+    public void validateDescriptor(ObjectStreamClass descriptor);
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java
index 3246bde5be1..24dc4ce43a7 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,9 +29,9 @@ import java.lang.module.ModuleDescriptor;
 import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
+import java.io.ObjectInputStream;
 import java.security.ProtectionDomain;
 import java.security.AccessController;
-import jdk.internal.misc.Unsafe;
 
 /** A repository of "shared secrets", which are a mechanism for
     calling implementation-private methods in another package without
@@ -63,6 +63,7 @@ public class SharedSecrets {
     private static JavaAWTAccess javaAWTAccess;
     private static JavaAWTFontAccess javaAWTFontAccess;
     private static JavaBeansAccess javaBeansAccess;
+    private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -262,4 +263,15 @@ public class SharedSecrets {
     public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) {
         javaUtilResourceBundleAccess = access;
     }
+
+    public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() {
+        if (javaObjectInputStreamAccess == null) {
+            unsafe.ensureClassInitialized(ObjectInputStream.class);
+        }
+        return javaObjectInputStreamAccess;
+    }
+
+    public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
+        javaObjectInputStreamAccess = access;
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
index beb64fd5155..735d1b86143 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
@@ -28,8 +28,8 @@ package jdk.internal.misc;
 import java.lang.reflect.Field;
 import java.security.ProtectionDomain;
 
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
 import jdk.internal.misc.VM;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
@@ -58,7 +58,7 @@ public final class Unsafe {
     private static native void registerNatives();
     static {
         registerNatives();
-        sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
+        Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
     }
 
     private Unsafe() {}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java
index d40facdafa4..e6a7cded42f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java
@@ -70,6 +70,7 @@ package jdk.internal.org.objectweb.asm;
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
+@SuppressWarnings("deprecation") // for Integer(int) constructor
 public interface Opcodes {
 
     // ASM API versions
@@ -176,6 +177,8 @@ public interface Opcodes {
      */
     int F_SAME1 = 4;
 
+    // For reference comparison purposes, construct new instances
+    // instead of using valueOf() or autoboxing.
     Integer TOP = new Integer(0);
     Integer INTEGER = new Integer(1);
     Integer FLOAT = new Integer(2);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
index af0fe2b4fb4..f16da4bdd09 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
@@ -65,10 +65,10 @@ import jdk.internal.org.objectweb.asm.Opcodes;
 /**
  * An {@link AnnotationVisitor} adapter for type remapping.
  *
- * //@deprecated use {@link AnnotationRemapper} instead.
+ * @deprecated use {@link AnnotationRemapper} instead.
  * @author Eugene Kuleshov
  */
-//@Deprecated
+@Deprecated
 public class RemappingAnnotationAdapter extends AnnotationVisitor {
 
     protected final Remapper remapper;
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java
index f58963db6ef..7bd76903eb4 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java
@@ -69,10 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath;
 /**
  * A {@link LocalVariablesSorter} for type mapping.
  *
- * //@deprecated use {@link MethodRemapper} instead.
+ * @deprecated use {@link MethodRemapper} instead.
  * @author Eugene Kuleshov
  */
-//@Deprecated
+@Deprecated
 public class RemappingMethodAdapter extends LocalVariablesSorter {
 
     protected final Remapper remapper;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java
index 3b06f550f0f..83eb05fd389 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/AccessorGenerator.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/AccessorGenerator.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.*;
 import jdk.internal.misc.Unsafe;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/BootstrapConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/BootstrapConstructorAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/BootstrapConstructorAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/BootstrapConstructorAccessorImpl.java
index d44fc8904fe..bf42b857fba 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/BootstrapConstructorAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/BootstrapConstructorAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Constructor;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ByteVector.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVector.java
similarity index 97%
rename from jdk/src/java.base/share/classes/sun/reflect/ByteVector.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVector.java
index ad28ee3ab20..2a07b072982 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ByteVector.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVector.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 /** A growable array of bytes. */
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ByteVectorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java
similarity index 97%
rename from jdk/src/java.base/share/classes/sun/reflect/ByteVectorFactory.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java
index 64af68dd178..3557bd5c515 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ByteVectorFactory.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorFactory.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 class ByteVectorFactory {
     static ByteVector create() {
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ByteVectorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/ByteVectorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java
index efa1c8abc2e..b0f9d81f7cf 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ByteVectorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ByteVectorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 class ByteVectorImpl implements ByteVector {
     private byte[] data;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/CallerSensitive.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/CallerSensitive.java
similarity index 92%
rename from jdk/src/java.base/share/classes/sun/reflect/CallerSensitive.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/CallerSensitive.java
index 1822fbe66dd..73853198a0d 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/CallerSensitive.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/CallerSensitive.java
@@ -23,14 +23,14 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.annotation.*;
 import static java.lang.annotation.ElementType.*;
 
 /**
  * A method annotated @CallerSensitive is sensitive to its calling class,
- * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
+ * via {@link jdk.internal.reflect.Reflection#getCallerClass Reflection.getCallerClass},
  * or via some equivalent.
  *
  * @author John R. Rose
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ClassDefiner.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/ClassDefiner.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java
index b4d50095939..8bf8bf9d1d7 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ClassDefiner.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassDefiner.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ClassFileAssembler.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/ClassFileAssembler.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java
index 7f6ceccf6e8..aeef5e62f12 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ClassFileAssembler.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileAssembler.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 class ClassFileAssembler implements ClassFileConstants {
     private ByteVector vec;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/ClassFileConstants.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java
index 0bf391a09cb..3562a8d5c72 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ClassFileConstants.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ClassFileConstants.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 /** Minimal set of class file constants for assembly of field and
     method accessors. */
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java
index b813519bf2c..46d2e48c848 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.*;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessor.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessor.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessor.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessor.java
index 7aac26f81ab..30d8baf634c 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessor.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessor.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java
index 9b098312a61..36f73b29cc3 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/ConstructorAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ConstructorAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/DelegatingConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/DelegatingConstructorAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java
index 6ee4d5f4d7a..6b0f7f51b13 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/DelegatingConstructorAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/DelegatingMethodAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/DelegatingMethodAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java
index 115d9aa112b..1acab93eb42 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/DelegatingMethodAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.InvocationTargetException;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/FieldAccessor.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessor.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/FieldAccessor.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessor.java
index 7b974f6caf1..0df292afa60 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/FieldAccessor.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessor.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 /** This interface provides the declarations for the accessor methods
     of java.lang.reflect.Field. Each Field object is configured with a
diff --git a/jdk/src/java.base/share/classes/sun/reflect/FieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/FieldAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java
index cbfa3c1e853..b5121c860dc 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/FieldAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 /** Package-private implementation of the FieldAccessor interface
     which has access to all classes and all fields, regardless of
diff --git a/jdk/src/java.base/share/classes/sun/reflect/InstantiationExceptionConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/InstantiationExceptionConstructorAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/InstantiationExceptionConstructorAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/InstantiationExceptionConstructorAccessorImpl.java
index 854febe7b3f..7ec7dd32f76 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/InstantiationExceptionConstructorAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/InstantiationExceptionConstructorAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/Label.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Label.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/Label.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/Label.java
index bac62793bde..eb531530f4a 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/Label.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Label.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.util.List;
 import java.util.ArrayList;
diff --git a/jdk/src/java.base/share/classes/sun/reflect/LangReflectAccess.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/LangReflectAccess.java
similarity index 99%
rename from jdk/src/java.base/share/classes/sun/reflect/LangReflectAccess.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/LangReflectAccess.java
index 4da3bc87169..0fed09ff0c4 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/LangReflectAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/LangReflectAccess.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 import java.lang.reflect.*;
 
diff --git a/jdk/src/java.base/share/classes/sun/reflect/MagicAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java
similarity index 98%
rename from jdk/src/java.base/share/classes/sun/reflect/MagicAccessorImpl.java
rename to jdk/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java
index af1382f6a5e..e464e3b6584 100644
--- a/jdk/src/java.base/share/classes/sun/reflect/MagicAccessorImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/MagicAccessorImpl.java
@@ -23,7 +23,7 @@
  * questions.
  */
 
-package sun.reflect;
+package jdk.internal.reflect;
 
 /** 

MagicAccessorImpl (named for parity with FieldAccessorImpl and others, not because it actually implements an interface) is a diff --git a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessor.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessor.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/MethodAccessor.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessor.java index b38514aeebb..8ffc0233a96 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessor.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.InvocationTargetException; diff --git a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java similarity index 97% rename from jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java index 68e1a7c0c43..8efa2a9d4e6 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.security.AccessController; import java.security.PrivilegedAction; @@ -148,7 +148,7 @@ class MethodAccessorGenerator extends AccessorGenerator { // (^ = Only present if generating SerializationConstructorAccessor) // [UTF-8] [This class's name] // [CONSTANT_Class_info] for above - // [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" + // [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" // [CONSTANT_Class_info] for above // [UTF-8] [Target class's name] // [CONSTANT_Class_info] for above @@ -290,12 +290,12 @@ class MethodAccessorGenerator extends AccessorGenerator { if (isConstructor) { if (forSerialization) { asm.emitConstantPoolUTF8 - ("sun/reflect/SerializationConstructorAccessorImpl"); + ("jdk/internal/reflect/SerializationConstructorAccessorImpl"); } else { - asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl"); + asm.emitConstantPoolUTF8("jdk/internal/reflect/ConstructorAccessorImpl"); } } else { - asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl"); + asm.emitConstantPoolUTF8("jdk/internal/reflect/MethodAccessorImpl"); } asm.emitConstantPoolClass(asm.cpi()); superClass = asm.cpi(); @@ -767,14 +767,14 @@ class MethodAccessorGenerator extends AccessorGenerator { if (isConstructor) { if (forSerialization) { int num = ++serializationConstructorSymnum; - return "sun/reflect/GeneratedSerializationConstructorAccessor" + num; + return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num; } else { int num = ++constructorSymnum; - return "sun/reflect/GeneratedConstructorAccessor" + num; + return "jdk/internal/reflect/GeneratedConstructorAccessor" + num; } } else { int num = ++methodSymnum; - return "sun/reflect/GeneratedMethodAccessor" + num; + return "jdk/internal/reflect/GeneratedMethodAccessor" + num; } } } diff --git a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/MethodAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java index 14282fb67c5..91a02645f4e 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.InvocationTargetException; diff --git a/jdk/src/java.base/share/classes/sun/reflect/NativeConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/NativeConstructorAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java index 171521dd2ae..d0b36399e64 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/NativeConstructorAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.*; import sun.reflect.misc.ReflectUtil; diff --git a/jdk/src/java.base/share/classes/sun/reflect/NativeMethodAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/NativeMethodAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java index a33670fe8ce..403113a6fe2 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/NativeMethodAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.*; import sun.reflect.misc.ReflectUtil; diff --git a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java similarity index 95% rename from jdk/src/java.base/share/classes/sun/reflect/Reflection.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 084995f268b..636b0940345 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -23,17 +23,16 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.*; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; import java.util.Objects; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.VM; +import sun.security.action.GetPropertyAction; /** Common utility routines used by both java.lang and java.lang.reflect */ @@ -66,11 +65,11 @@ public class Reflection { public static native Class getCallerClass(); /** - * @deprecated This method will be removed in JDK 9. - * This method is a private JDK API and retained temporarily for - * existing code to run until a replacement API is defined. + * @deprecated This method will be removed. + * This method is a private JDK API and retained temporarily to + * simplify the implementation of sun.misc.Reflection.getCallerClass. */ - @Deprecated + @Deprecated(forRemoval=true) public static native Class getCallerClass(int depth); /** Retrieves the access flags written to the class file. For @@ -344,15 +343,10 @@ public class Reflection { private static void printStackTraceIfNeeded(Throwable e) { if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) { - // can't use method reference here, might be too early in startup - PrivilegedAction pa = new PrivilegedAction() { - public Boolean run() { - String s; - s = System.getProperty("sun.reflect.debugModuleAccessChecks"); - return (s != null && !s.equalsIgnoreCase("false")); - } - }; - printStackWhenAccessFails = AccessController.doPrivileged(pa); + String s = GetPropertyAction + .getProperty("sun.reflect.debugModuleAccessChecks"); + printStackWhenAccessFails = + (s != null && !s.equalsIgnoreCase("false")); printStackWhenAccessFailsSet = true; } if (printStackWhenAccessFails) { diff --git a/jdk/src/java.base/share/classes/sun/reflect/ReflectionFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java similarity index 90% rename from jdk/src/java.base/share/classes/sun/reflect/ReflectionFactory.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 24aa225b89e..b40c584efcd 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/ReflectionFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -23,17 +23,18 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; -import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; +import java.util.Properties; import sun.reflect.misc.ReflectUtil; +import sun.security.action.GetPropertyAction; /**

The master factory for all reflective objects, both those in java.lang.reflect (Fields, Methods, Constructors) as well as their @@ -382,41 +383,37 @@ public class ReflectionFactory { run, before the system properties are set up. */ private static void checkInitted() { if (initted) return; - AccessController.doPrivileged( - new PrivilegedAction<>() { - public Void run() { - // Tests to ensure the system properties table is fully - // initialized. This is needed because reflection code is - // called very early in the initialization process (before - // command-line arguments have been parsed and therefore - // these user-settable properties installed.) We assume that - // if System.out is non-null then the System class has been - // fully initialized and that the bulk of the startup code - // has been run. - if (System.out == null) { - // java.lang.System not yet fully initialized - return null; - } + // Tests to ensure the system properties table is fully + // initialized. This is needed because reflection code is + // called very early in the initialization process (before + // command-line arguments have been parsed and therefore + // these user-settable properties installed.) We assume that + // if System.out is non-null then the System class has been + // fully initialized and that the bulk of the startup code + // has been run. - String val = System.getProperty("sun.reflect.noInflation"); - if (val != null && val.equals("true")) { - noInflation = true; - } + if (System.out == null) { + // java.lang.System not yet fully initialized + return; + } - val = System.getProperty("sun.reflect.inflationThreshold"); - if (val != null) { - try { - inflationThreshold = Integer.parseInt(val); - } catch (NumberFormatException e) { - throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); - } - } + Properties props = GetPropertyAction.getProperties(); + String val = props.getProperty("sun.reflect.noInflation"); + if (val != null && val.equals("true")) { + noInflation = true; + } - initted = true; - return null; - } - }); + val = props.getProperty("sun.reflect.inflationThreshold"); + if (val != null) { + try { + inflationThreshold = Integer.parseInt(val); + } catch (NumberFormatException e) { + throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); + } + } + + initted = true; } private static LangReflectAccess langReflectAccess() { diff --git a/jdk/src/java.base/share/classes/sun/reflect/SerializationConstructorAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/SerializationConstructorAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java index a26d0664c56..9dbbf0d2c77 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/SerializationConstructorAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/SerializationConstructorAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; /**

Java serialization (in java.io) expects to be able to instantiate a class and invoke a no-arg constructor of that diff --git a/jdk/src/java.base/share/classes/sun/reflect/SignatureIterator.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/SignatureIterator.java similarity index 97% rename from jdk/src/java.base/share/classes/sun/reflect/SignatureIterator.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/SignatureIterator.java index ea7fd3c80f2..e0d35c02772 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/SignatureIterator.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/SignatureIterator.java @@ -23,11 +23,11 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; /** Assists in iterating down a method's signature */ -public class SignatureIterator { +class SignatureIterator { private final String sig; private int idx; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UTF8.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UTF8.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UTF8.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UTF8.java index ae482f329c9..446060dba8b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UTF8.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UTF8.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; /** It is necessary to use a "bootstrap" UTF-8 encoder for encoding constant pool entries because the character set converters rely on diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeBooleanFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeBooleanFieldAccessorImpl.java index cf929b762a9..32b33bed625 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeBooleanFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeByteFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeByteFieldAccessorImpl.java index 15564220ecf..df6a8be164b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeByteFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeCharacterFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeCharacterFieldAccessorImpl.java index bd27f00b1bd..4dcf0756eb1 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeCharacterFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeDoubleFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeDoubleFieldAccessorImpl.java index a43ac29368b..17b7377c6f0 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeDoubleFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorFactory.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java index 72689b3e5f3..b00306b3076 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorFactory.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java index d54c7f8a6f6..d75db5374cb 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFloatFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFloatFieldAccessorImpl.java index d2410987999..690fe8f4965 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeFloatFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeIntegerFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeIntegerFieldAccessorImpl.java index df802e3b2ad..c0993abeb23 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeIntegerFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeLongFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeLongFieldAccessorImpl.java index 8e76ea193fe..d92023dc079 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeLongFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeObjectFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeObjectFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeObjectFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeObjectFieldAccessorImpl.java index bb5b5b6cf6e..ea3c70045da 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeObjectFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeObjectFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java index cc31cb4910d..5144a8fbd79 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedByteFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedByteFieldAccessorImpl.java index ae239a807f4..7cd87931a52 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedByteFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java index e322e1d3e04..634f6abe0d2 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java index 1fb71f5c447..48b59ca7251 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFieldAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFieldAccessorImpl.java index 5cf6c5ee5c7..fcfa9f16b00 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java index 0b7906d4830..9b44e1379a0 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java index df737fd0119..f960425638d 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedLongFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedLongFieldAccessorImpl.java index b77d4d1d9e9..25434e84f00 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedLongFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java index 1a502ab72d8..fcb45289886 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedObjectFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedShortFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedShortFieldAccessorImpl.java index c5ea9bb6caa..1e68e3dad98 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedShortFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java index 65dabb0fba6..67d98280938 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java index 136728b4594..93ffb209a3a 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java index 6015baf82a8..8c9cfe03e41 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java index 5433b4ec82a..5178d639961 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java index 74b40571eab..c086fc3d3e9 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java index fe69684c1d8..410a99cd168 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java index 3e420f92a39..1411f364b5b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java index d25f4ac8a56..dc357e1f005 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java index 8bea19e829a..4b35509bb60 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticObjectFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java index 631bd7ae333..63285054497 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeShortFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeShortFieldAccessorImpl.java index 05ea337f49c..d864fb4b855 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeShortFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticBooleanFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticBooleanFieldAccessorImpl.java index b7572b54e31..26bb655cbea 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticBooleanFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticByteFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticByteFieldAccessorImpl.java index 78eeb86842f..c3e93ee38bb 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticByteFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticCharacterFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticCharacterFieldAccessorImpl.java index 2dd3a597681..7f2acd4e99c 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticCharacterFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticDoubleFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticDoubleFieldAccessorImpl.java index b07df4f987f..1f010ad9832 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticDoubleFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java similarity index 98% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java index e87ba31b543..3cfa97bc52c 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFloatFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFloatFieldAccessorImpl.java index 2929727b6ad..10ba9cdef39 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFloatFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticIntegerFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticIntegerFieldAccessorImpl.java index 963620a06fb..f6ae4e15650 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticIntegerFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticLongFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticLongFieldAccessorImpl.java index a8dedd060cc..a1d086b1931 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticLongFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticObjectFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticObjectFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticObjectFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticObjectFieldAccessorImpl.java index e8b4548e422..7381be2ca2f 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticObjectFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticObjectFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticShortFieldAccessorImpl.java similarity index 99% rename from jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java rename to jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticShortFieldAccessorImpl.java index 9ac6cd6533b..8e17a6f4ff1 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticShortFieldAccessorImpl.java @@ -23,7 +23,7 @@ * questions. */ -package sun.reflect; +package jdk.internal.reflect; import java.lang.reflect.Field; diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 2d1aae28616..942c0582ea0 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,9 +86,6 @@ module java.base { // see JDK-8044773 exports jdk.net; - // This will move to a jdk.internal module via JEP-260 - exports sun.reflect; - // the service types defined by the APIs in this module @@ -180,6 +177,14 @@ module java.base { jdk.jvmstat; exports jdk.internal.ref to java.desktop; + exports jdk.internal.reflect to + java.corba, + java.logging, + java.sql, + java.sql.rowset, + jdk.dynalink, + jdk.scripting.nashorn, + jdk.unsupported; exports jdk.internal.vm.annotation to jdk.unsupported; exports jdk.internal.util.jar to @@ -295,9 +300,5 @@ module java.base { provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider; - provides java.security.Provider with sun.security.provider.Sun; - provides java.security.Provider with sun.security.rsa.SunRsaSign; - provides java.security.Provider with com.sun.crypto.provider.SunJCE; - provides java.security.Provider with com.sun.net.ssl.internal.ssl.Provider; } diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index 2d6b234a63d..37cbede912a 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -28,7 +28,7 @@ package sun.invoke.util; import java.lang.reflect.Modifier; import static java.lang.reflect.Modifier.*; import java.lang.reflect.Module; -import sun.reflect.Reflection; +import jdk.internal.reflect.Reflection; /** * This class centralizes information about the JVM's linkage access control. @@ -231,22 +231,66 @@ public class VerifyAccess { * @param refc the class attempting to make the reference */ public static boolean isTypeVisible(Class type, Class refc) { - if (type == refc) return true; // easy check + if (type == refc) { + return true; // easy check + } while (type.isArray()) type = type.getComponentType(); - if (type.isPrimitive() || type == Object.class) return true; - ClassLoader parent = type.getClassLoader(); - if (parent == null) return true; - ClassLoader child = refc.getClassLoader(); - if (child == null) return false; - if (parent == child || loadersAreRelated(parent, child, true)) + if (type.isPrimitive() || type == Object.class) { return true; - // Do it the hard way: Look up the type name from the refc loader. - try { - Class res = child.loadClass(type.getName()); - return (type == res); - } catch (ClassNotFoundException ex) { + } + ClassLoader typeLoader = type.getClassLoader(); + ClassLoader refcLoader = refc.getClassLoader(); + if (typeLoader == refcLoader) { + return true; + } + if (refcLoader == null && typeLoader != null) { return false; } + if (typeLoader == null && type.getName().startsWith("java.")) { + // Note: The API for actually loading classes, ClassLoader.defineClass, + // guarantees that classes with names beginning "java." cannot be aliased, + // because class loaders cannot load them directly. + return true; + } + + // Do it the hard way: Look up the type name from the refc loader. + // + // Force the refc loader to report and commit to a particular binding for this type name (type.getName()). + // + // In principle, this query might force the loader to load some unrelated class, + // which would cause this query to fail (and the original caller to give up). + // This would be wasted effort, but it is expected to be very rare, occurring + // only when an attacker is attempting to create a type alias. + // In the normal case, one class loader will simply delegate to the other, + // and the same type will be visible through both, with no extra loading. + // + // It is important to go through Class.forName instead of ClassLoader.loadClass + // because Class.forName goes through the JVM system dictionary, which records + // the class lookup once for all. This means that even if a not-well-behaved class loader + // would "change its mind" about the meaning of the name, the Class.forName request + // will use the result cached in the JVM system dictionary. Note that the JVM system dictionary + // will record the first successful result. Unsuccessful results are not stored. + // + // We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary + // class loader about the binding of the proposed name (type.getName()). + // The looked up type ("res") is compared for equality against the proposed + // type ("type") and then is discarded. Thus, the worst that can happen to + // the "child" class loader is that it is bothered to load and report a class + // that differs from "type"; this happens once due to JVM system dictionary + // memoization. And the caller never gets to look at the alternate type binding + // ("res"), whether it exists or not. + final String name = type.getName(); + Class res = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<>() { + public Class run() { + try { + return Class.forName(name, false, refcLoader); + } catch (ClassNotFoundException | LinkageError e) { + return null; // Assume the class is not found + } + } + }); + return (type == res); } /** diff --git a/jdk/src/java.base/share/classes/sun/net/ResourceManager.java b/jdk/src/java.base/share/classes/sun/net/ResourceManager.java index 068b8484728..9c68d7c6bed 100644 --- a/jdk/src/java.base/share/classes/sun/net/ResourceManager.java +++ b/jdk/src/java.base/share/classes/sun/net/ResourceManager.java @@ -53,9 +53,8 @@ public class ResourceManager { private static final AtomicInteger numSockets; static { - String prop = java.security.AccessController.doPrivileged( - new GetPropertyAction("sun.net.maxDatagramSockets") - ); + String prop = + GetPropertyAction.getProperty("sun.net.maxDatagramSockets"); int defmax = DEFAULT_MAX_SOCKETS; try { if (prop != null) { diff --git a/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java b/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java index d24a7fed491..797bc7fed50 100644 --- a/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java +++ b/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java @@ -31,6 +31,7 @@ import java.security.AccessController; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaIOFileDescriptorAccess; +import sun.security.action.GetPropertyAction; /** @@ -39,8 +40,7 @@ import jdk.internal.misc.JavaIOFileDescriptorAccess; */ public final class SdpSupport { - private static final String os = AccessController - .doPrivileged(new sun.security.action.GetPropertyAction("os.name")); + private static final String os = GetPropertyAction.getProperty("os.name"); private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux"))); private static final JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); diff --git a/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java b/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java index fda15ea9234..ac3f7b8a43f 100644 --- a/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java +++ b/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java @@ -25,10 +25,10 @@ package sun.net.smtp; -import java.util.StringTokenizer; import java.io.*; import java.net.*; import sun.net.TransferProtocolClient; +import sun.security.action.GetPropertyAction; /** * This class implements the SMTP client. @@ -157,8 +157,7 @@ public class SmtpClient extends TransferProtocolClient { } try { String s; - mailhost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("mail.host")); + mailhost = GetPropertyAction.getProperty("mail.host"); if (mailhost != null) { openServer(mailhost); return; @@ -184,8 +183,7 @@ public class SmtpClient extends TransferProtocolClient { setConnectTimeout(to); try { String s; - mailhost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("mail.host")); + mailhost = GetPropertyAction.getProperty("mail.host"); if (mailhost != null) { openServer(mailhost); return; diff --git a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java index d95ca3774ba..ba26f96e52e 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java +++ b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java @@ -27,6 +27,7 @@ package sun.net.www; import java.net.URL; import java.io.*; import java.util.StringTokenizer; +import sun.security.action.GetPropertyAction; class MimeLauncher extends Thread { java.net.URLConnection uc; @@ -182,8 +183,7 @@ class MimeLauncher extends Thread { } String execPathList; - execPathList = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("exec.path")); + execPathList = GetPropertyAction.getProperty("exec.path"); if (execPathList == null) { // exec.path property not set return false; diff --git a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java index 02c9f98b7a6..392d9ea52dc 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -28,6 +28,7 @@ package sun.net.www.http; import java.io.*; import java.net.*; import java.util.Locale; +import java.util.Properties; import sun.net.NetworkClient; import sun.net.ProgressSource; import sun.net.www.MessageHeader; @@ -37,6 +38,7 @@ import sun.net.www.ParseUtil; import sun.net.www.protocol.http.HttpURLConnection; import sun.util.logging.PlatformLogger; import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*; +import sun.security.action.GetPropertyAction; /** * @author Herb Jellinek @@ -143,20 +145,18 @@ public class HttpClient extends NetworkClient { } static { - String keepAlive = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.keepAlive")); - - String retryPost = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.net.http.retryPost")); + Properties props = GetPropertyAction.getProperties(); + String keepAlive = props.getProperty("http.keepAlive"); + String retryPost = props.getProperty("sun.net.http.retryPost"); if (keepAlive != null) { - keepAliveProp = Boolean.valueOf(keepAlive).booleanValue(); + keepAliveProp = Boolean.parseBoolean(keepAlive); } else { keepAliveProp = true; } if (retryPost != null) { - retryPostProp = Boolean.valueOf(retryPost).booleanValue(); + retryPostProp = Boolean.parseBoolean(retryPost); } else retryPostProp = true; diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java index 38d64d23009..b397ba1243f 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java @@ -46,6 +46,7 @@ import java.net.ProxySelector; import java.util.StringTokenizer; import java.util.Iterator; import java.security.Permission; +import java.util.Properties; import sun.net.NetworkClient; import sun.net.www.MessageHeader; import sun.net.www.MeteredStream; @@ -277,11 +278,10 @@ public class FtpURLConnection extends URLConnection { if (user == null) { user = "anonymous"; - String vers = java.security.AccessController.doPrivileged( - new GetPropertyAction("java.version")); - password = java.security.AccessController.doPrivileged( - new GetPropertyAction("ftp.protocol.user", - "Java" + vers + "@")); + Properties props = GetPropertyAction.getProperties(); + String vers = props.getProperty("java.version"); + password = props.getProperty("ftp.protocol.user", + "Java" + vers + "@"); } try { ftp = FtpClient.create(); diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java index 42f692c3738..b6168d0c2c5 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java @@ -25,9 +25,10 @@ package sun.net.www.protocol.http; -import sun.net.www.*; import java.util.Iterator; import java.util.HashMap; +import sun.net.www.*; +import sun.security.action.GetPropertyAction; /** * This class is used to parse the information in WWW-Authenticate: and Proxy-Authenticate: @@ -93,8 +94,7 @@ public class AuthenticationHeader { } static { - authPref = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.preference")); + authPref = GetPropertyAction.getProperty("http.auth.preference"); // http.auth.preference can be set to SPNEGO or Kerberos. // In fact they means "Negotiate with SPNEGO" and "Negotiate with diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 5754c047219..ebabc26182e 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -52,7 +52,6 @@ import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; import java.io.*; -import java.net.*; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -78,12 +77,15 @@ import java.text.SimpleDateFormat; import java.util.TimeZone; import java.net.MalformedURLException; import java.nio.ByteBuffer; +import java.util.Properties; import static sun.net.www.protocol.http.AuthScheme.BASIC; import static sun.net.www.protocol.http.AuthScheme.DIGEST; import static sun.net.www.protocol.http.AuthScheme.NTLM; import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE; import static sun.net.www.protocol.http.AuthScheme.KERBEROS; import static sun.net.www.protocol.http.AuthScheme.UNKNOWN; +import sun.security.action.GetIntegerAction; +import sun.security.action.GetPropertyAction; /** * A class to represent an HTTP connection to a remote object. @@ -205,46 +207,38 @@ public class HttpURLConnection extends java.net.HttpURLConnection { }; static { - maxRedirects = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "http.maxRedirects", defaultmaxRedirects)).intValue(); - version = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.version")); - String agent = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.agent")); + Properties props = GetPropertyAction.getProperties(); + maxRedirects = GetIntegerAction.getProperty("http.maxRedirects", + defaultmaxRedirects); + version = props.getProperty("java.version"); + String agent = props.getProperty("http.agent"); if (agent == null) { agent = "Java/"+version; } else { agent = agent + " Java/"+version; } userAgent = agent; - validateProxy = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "http.auth.digest.validateProxy")).booleanValue(); - validateServer = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "http.auth.digest.validateServer")).booleanValue(); + validateProxy = Boolean.parseBoolean( + props.getProperty("http.auth.digest.validateProxy")); + validateServer = Boolean.parseBoolean( + props.getProperty("http.auth.digest.validateServer")); - enableESBuffer = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "sun.net.http.errorstream.enableBuffering")).booleanValue(); - timeout4ESBuffer = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "sun.net.http.errorstream.timeout", 300)).intValue(); + enableESBuffer = Boolean.parseBoolean( + props.getProperty("sun.net.http.errorstream.enableBuffering")); + timeout4ESBuffer = GetIntegerAction + .getProperty("sun.net.http.errorstream.timeout", 300); if (timeout4ESBuffer <= 0) { timeout4ESBuffer = 300; // use the default } - bufSize4ES = java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction( - "sun.net.http.errorstream.bufferSize", 4096)).intValue(); + bufSize4ES = GetIntegerAction + .getProperty("sun.net.http.errorstream.bufferSize", 4096); if (bufSize4ES <= 0) { bufSize4ES = 4096; // use the default } - allowRestrictedHeaders = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "sun.net.http.allowRestrictedHeaders")).booleanValue(); + allowRestrictedHeaders = Boolean.parseBoolean( + props.getProperty("sun.net.http.allowRestrictedHeaders")); if (!allowRestrictedHeaders) { restrictedHeaderSet = new HashSet<>(restrictedHeaders.length); for (int i=0; i < restrictedHeaders.length; i++) { diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index 3aecc419cb2..437c3969148 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -41,7 +41,6 @@ import java.security.Principal; import java.security.cert.*; import java.util.StringTokenizer; import java.util.Vector; -import java.security.AccessController; import javax.security.auth.x500.X500Principal; @@ -139,8 +138,8 @@ final class HttpsClient extends HttpClient // If ciphers are assigned, sort them into an array. // String ciphers []; - String cipherString = AccessController.doPrivileged( - new GetPropertyAction("https.cipherSuites")); + String cipherString = + GetPropertyAction.getProperty("https.cipherSuites"); if (cipherString == null || "".equals(cipherString)) { ciphers = null; @@ -163,8 +162,8 @@ final class HttpsClient extends HttpClient // If protocols are assigned, sort them into an array. // String protocols []; - String protocolString = AccessController.doPrivileged( - new GetPropertyAction("https.protocols")); + String protocolString = + GetPropertyAction.getProperty("https.protocols"); if (protocolString == null || "".equals(protocolString)) { protocols = null; @@ -184,8 +183,7 @@ final class HttpsClient extends HttpClient } private String getUserAgent() { - String userAgent = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("https.agent")); + String userAgent = GetPropertyAction.getProperty("https.agent"); if (userAgent == null || userAgent.length() == 0) { userAgent = "JSSE"; } diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java index cde9d438714..f58ce457f7a 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java @@ -32,10 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessController; import java.security.Permission; -import java.security.PrivilegedAction; -import java.util.List; import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; @@ -45,6 +42,7 @@ import jdk.internal.loader.URLClassPath; import jdk.internal.loader.Resource; import sun.net.www.ParseUtil; import sun.net.www.URLConnection; +import sun.security.action.GetPropertyAction; /** * URLConnection implementation that can be used to connect to resources @@ -163,11 +161,7 @@ public class JavaRuntimeURLConnection extends URLConnection { public Permission getPermission() throws IOException { Permission p = permission; if (p == null) { - // using lambda expression here leads to recursive initialization - PrivilegedAction pa = new PrivilegedAction() { - public String run() { return System.getProperty("java.home"); } - }; - String home = AccessController.doPrivileged(pa); + String home = GetPropertyAction.getProperty("java.home"); p = new FilePermission(home + File.separator + "-", "read"); permission = p; } diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java index fbcddcb826b..81139707655 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java @@ -40,6 +40,7 @@ import java.net.MalformedURLException; import java.net.URLStreamHandler; import java.io.InputStream; import java.io.IOException; +import sun.security.action.GetPropertyAction; public class Handler extends URLStreamHandler { static URL base; @@ -54,12 +55,10 @@ public class Handler extends URLStreamHandler { URLConnection uc = null; URL ru; - Boolean tmp = java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction("newdoc.localonly")); - boolean localonly = tmp.booleanValue(); + boolean localonly = Boolean.parseBoolean( + GetPropertyAction.getProperty("newdoc.localonly")); - String docurl = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("doc.url")); + String docurl = GetPropertyAction.getProperty("doc.url"); String file = u.getFile(); if (!localonly) { diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 671fe79efcc..8a287bc2839 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1019,9 +1019,8 @@ public class FileChannelImpl if (!propertyChecked) { synchronized (FileChannelImpl.class) { if (!propertyChecked) { - String value = AccessController.doPrivileged( - new GetPropertyAction( - "sun.nio.ch.disableSystemWideOverlappingFileLockCheck")); + String value = GetPropertyAction.getProperty( + "sun.nio.ch.disableSystemWideOverlappingFileLockCheck"); isSharedFileLockTable = ((value == null) || value.equals("false")); propertyChecked = true; } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java index 062ce35468e..9a5c4dcb6f8 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java @@ -33,6 +33,7 @@ import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; import sun.net.ExtendedOptionsImpl; +import sun.security.action.GetPropertyAction; public class Net { @@ -382,13 +383,8 @@ public class Net { } public static boolean isFastTcpLoopbackRequested() { - String loopbackProp = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.net.useFastTcpLoopback"); - } - }); + String loopbackProp = + GetPropertyAction.getProperty("jdk.net.useFastTcpLoopback"); boolean enable; if ("".equals(loopbackProp)) { enable = true; @@ -647,16 +643,9 @@ public class Net { int availLevel = isExclusiveBindAvailable(); if (availLevel >= 0) { String exclBindProp = - java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty( - "sun.net.useExclusiveBind"); - } - }); + GetPropertyAction.getProperty("sun.net.useExclusiveBind"); if (exclBindProp != null) { - exclusiveBind = exclBindProp.length() == 0 ? + exclusiveBind = exclBindProp.isEmpty() ? true : Boolean.parseBoolean(exclBindProp); } else if (availLevel == 1) { exclusiveBind = true; diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java index af89eca4544..e71e628ede1 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java @@ -64,13 +64,7 @@ public class Util { * for potential future-proofing. */ private static long getMaxCachedBufferSize() { - String s = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.nio.maxCachedBufferSize"); - } - }); + String s = GetPropertyAction.getProperty("jdk.nio.maxCachedBufferSize"); if (s != null) { try { long m = Long.parseLong(s); @@ -471,8 +465,7 @@ public class Util { if (bugLevel == null) { if (!jdk.internal.misc.VM.isBooted()) return false; - String value = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.ch.bugLevel")); + String value = GetPropertyAction.getProperty("sun.nio.ch.bugLevel"); bugLevel = (value != null) ? value : ""; } return bugLevel.equals(bl); diff --git a/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template b/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template index dd4d3994240..2ad055e50ec 100644 --- a/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template +++ b/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template @@ -34,8 +34,7 @@ import java.nio.charset.spi.CharsetProvider; import java.util.Iterator; import java.util.Locale; import java.util.Map; -import java.security.AccessController; -import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; public class StandardCharsets extends CharsetProvider { @@ -201,15 +200,7 @@ public class StandardCharsets extends CharsetProvider { } private static String getProperty(String key) { - // this method may be called during initialization of - // system class loader and thus not using lambda - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty(key); - } - }); + return GetPropertyAction.getProperty(key); } diff --git a/jdk/src/java.base/share/classes/sun/nio/fs/Util.java b/jdk/src/java.base/share/classes/sun/nio/fs/Util.java index 2d5c8cb6443..45d90b99222 100644 --- a/jdk/src/java.base/share/classes/sun/nio/fs/Util.java +++ b/jdk/src/java.base/share/classes/sun/nio/fs/Util.java @@ -28,8 +28,7 @@ package sun.nio.fs; import java.util.*; import java.nio.file.*; import java.nio.charset.Charset; -import java.security.*; -import sun.security.action.*; +import sun.security.action.GetPropertyAction; /** * Utility methods @@ -39,7 +38,7 @@ class Util { private Util() { } private static final Charset jnuEncoding = Charset.forName( - AccessController.doPrivileged(new GetPropertyAction("sun.jnu.encoding"))); + GetPropertyAction.getProperty("sun.jnu.encoding")); /** * Returns {@code Charset} corresponding to the sun.jnu.encoding property diff --git a/jdk/src/java.base/share/classes/sun/reflect/FieldInfo.java b/jdk/src/java.base/share/classes/sun/reflect/FieldInfo.java deleted file mode 100644 index 72abd07b861..00000000000 --- a/jdk/src/java.base/share/classes/sun/reflect/FieldInfo.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.reflect; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -/** NOTE: obsolete as of JDK 1.4 B75 and should be removed from the - workspace (FIXME) */ - -public class FieldInfo { - // Set by the VM directly. Do not move these fields around or add - // others before (or after) them without also modifying the VM's code. - private String name; - private String signature; - private int modifiers; - // This is compatible with the old reflection implementation's - // "slot" value to allow jdk.internal.misc.Unsafe to work - private int slot; - - // Not really necessary to provide a constructor since the VM - // creates these directly - FieldInfo() { - } - - public String name() { - return name; - } - - /** This is in "external" format, i.e. having '.' as separator - rather than '/' */ - public String signature() { - return signature; - } - - public int modifiers() { - return modifiers; - } - - public int slot() { - return slot; - } - - /** Convenience routine */ - public boolean isPublic() { - return (Modifier.isPublic(modifiers())); - } -} diff --git a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 02a5a3f480b..20f911098cd 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -32,7 +32,7 @@ import java.nio.BufferUnderflowException; import java.lang.reflect.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool; import sun.reflect.generics.parser.SignatureParser; import sun.reflect.generics.tree.TypeSignature; diff --git a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java index ee3a6c6d0c0..98d46526326 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java +++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java @@ -37,7 +37,7 @@ import java.util.Objects; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaLangAccess; -import sun.reflect.ReflectionFactory; +import jdk.internal.reflect.ReflectionFactory; public final class AnnotationSupport { private static final JavaLangAccess LANG_ACCESS = SharedSecrets.getJavaLangAccess(); diff --git a/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java index c18c14c1b7b..2873db8e1b3 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java +++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -36,7 +36,7 @@ import java.util.LinkedHashMap; import java.util.Map; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaLangAccess; -import sun.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool; import static sun.reflect.annotation.TypeAnnotation.*; /** diff --git a/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java b/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java index 97bd9c2e303..07f53c490b5 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java +++ b/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java @@ -30,7 +30,7 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; -import sun.reflect.Reflection; +import jdk.internal.reflect.Reflection; import sun.security.util.SecurityConstants; public final class ReflectUtil { diff --git a/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java b/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java index ff2b2019b48..c454b431861 100644 --- a/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java +++ b/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java @@ -25,6 +25,8 @@ package sun.security.action; +import java.security.AccessController; + /** * A convenience class for retrieving the integer value of a system property * as a privileged action. @@ -67,7 +69,7 @@ public class GetIntegerAction implements java.security.PrivilegedAction { private String theProp; private int defaultVal; - private boolean defaultSet = false; + private boolean defaultSet; /** * Constructor that takes the name of the system property whose integer @@ -110,4 +112,39 @@ public class GetIntegerAction return defaultVal; return value; } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + */ + public static Integer getProperty(String theProp) { + if (System.getSecurityManager() == null) { + return Integer.getInteger(theProp); + } else { + return AccessController.doPrivileged( + new GetIntegerAction(theProp)); + } + } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + * @param defaultVal the default value. + */ + public static Integer getProperty(String theProp, int defaultVal) { + Integer value; + if (System.getSecurityManager() == null) { + value = Integer.getInteger(theProp); + } else { + value = AccessController.doPrivileged( + new GetIntegerAction(theProp)); + } + return (value != null) ? value : defaultVal; + } } diff --git a/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java b/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java index 95a113c3bef..bba172b06bc 100644 --- a/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java +++ b/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java @@ -25,6 +25,10 @@ package sun.security.action; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Properties; + /** * A convenience class for retrieving the string value of a system * property as a privileged action. @@ -46,8 +50,7 @@ package sun.security.action; * @since 1.2 */ -public class GetPropertyAction - implements java.security.PrivilegedAction { +public class GetPropertyAction implements PrivilegedAction { private String theProp; private String defaultVal; @@ -84,4 +87,57 @@ public class GetPropertyAction String value = System.getProperty(theProp); return (value == null) ? defaultVal : value; } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + */ + public static String getProperty(String theProp) { + if (System.getSecurityManager() == null) { + return System.getProperty(theProp); + } else { + return AccessController.doPrivileged( + new GetPropertyAction(theProp)); + } + } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * @param theProp the name of the system property. + * @param defaultVal the default value. + */ + public static String getProperty(String theProp, String defaultVal) { + if (System.getSecurityManager() == null) { + return System.getProperty(theProp, defaultVal); + } else { + return AccessController.doPrivileged( + new GetPropertyAction(theProp, defaultVal)); + } + } + + /** + * Convenience method to call System.getProperties without + * having to go through doPrivileged if no security manager is present. + * This is unsafe for inclusion in a public API but allowable here since + * this class is now encapsulated. + */ + public static Properties getProperties() { + if (System.getSecurityManager() == null) { + return System.getProperties(); + } else { + return AccessController.doPrivileged( + new PrivilegedAction() { + public Properties run() { + return System.getProperties(); + } + } + ); + } + } } diff --git a/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java b/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java index 4ab324914bd..bf65180af6f 100644 --- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java +++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -236,9 +236,8 @@ final class ProviderConfig { if (debug != null) { debug.println("Loading provider " + ProviderConfig.this); } - ProviderLoader pl = new ProviderLoader(); try { - Provider p = pl.load(provName); + Provider p = ProviderLoader.INSTANCE.load(provName); if (p != null) { if (hasArgument()) { p = p.configure(argument); @@ -303,9 +302,11 @@ final class ProviderConfig { // Inner class for loading security providers listed in java.security file private static final class ProviderLoader { + static final ProviderLoader INSTANCE = new ProviderLoader(); + private final ServiceLoader services; - ProviderLoader() { + private ProviderLoader() { // VM should already been booted at this point, if not // - Only providers in java.base should be loaded, don't use // ServiceLoader diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java index 6f8c27a38c0..a25949742bb 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java @@ -106,6 +106,18 @@ abstract class DSA extends SignatureSpi { this.p1363Format = p1363Format; } + private static void checkKey(DSAParams params, int digestLen, String mdAlgo) + throws InvalidKeyException { + // FIPS186-3 states in sec4.2 that a hash function which provides + // a lower security strength than the (L, N) pair ordinarily should + // not be used. + int valueN = params.getQ().bitLength(); + if (valueN > digestLen) { + throw new InvalidKeyException("The security strength of " + + mdAlgo + " digest algorithm is not sufficient for this key size"); + } + } + /** * Initialize the DSA object with a DSA private key. * @@ -130,6 +142,12 @@ abstract class DSA extends SignatureSpi { throw new InvalidKeyException("DSA private key lacks parameters"); } + // check key size against hash output size for signing + // skip this check for verification to minimize impact on existing apps + if (md.getAlgorithm() != "NullDigest20") { + checkKey(params, md.getDigestLength()*8, md.getAlgorithm()); + } + this.params = params; this.presetX = priv.getX(); this.presetY = null; @@ -160,7 +178,6 @@ abstract class DSA extends SignatureSpi { if (params == null) { throw new InvalidKeyException("DSA public key lacks parameters"); } - this.params = params; this.presetY = pub.getY(); this.presetX = null; @@ -406,20 +423,13 @@ abstract class DSA extends SignatureSpi { return t5.mod(q); } - // NOTE: This following impl is defined in FIPS 186-3 AppendixB.2.2. - // Original DSS algos such as SHA1withDSA and RawDSA uses a different - // algorithm defined in FIPS 186-1 Sec3.2, and thus need to override this. + // NOTE: This following impl is defined in FIPS 186-4 AppendixB.2.1. protected BigInteger generateK(BigInteger q) { SecureRandom random = getSigningRandom(); - byte[] kValue = new byte[q.bitLength()/8]; + byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8]; - while (true) { - random.nextBytes(kValue); - BigInteger k = new BigInteger(1, kValue).mod(q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - return k; - } - } + random.nextBytes(kValue); + return new BigInteger(1, kValue).mod(q.subtract(BigInteger.ONE)).add(BigInteger.ONE); } // Use the application-specified SecureRandom Object if provided. @@ -504,222 +514,10 @@ abstract class DSA extends SignatureSpi { } } - static class LegacyDSA extends DSA { - /* The random seed used to generate k */ - private int[] kSeed; - /* The random seed used to generate k (specified by application) */ - private byte[] kSeedAsByteArray; - /* - * The random seed used to generate k - * (prevent the same Kseed from being used twice in a row - */ - private int[] kSeedLast; - - public LegacyDSA(MessageDigest md) throws NoSuchAlgorithmException { - this(md, false); - } - - private LegacyDSA(MessageDigest md, boolean p1363Format) - throws NoSuchAlgorithmException { - super(md, p1363Format); - } - - @Deprecated - protected void engineSetParameter(String key, Object param) { - if (key.equals("KSEED")) { - if (param instanceof byte[]) { - kSeed = byteArray2IntArray((byte[])param); - kSeedAsByteArray = (byte[])param; - } else { - debug("unrecognized param: " + key); - throw new InvalidParameterException("kSeed not a byte array"); - } - } else { - throw new InvalidParameterException("Unsupported parameter"); - } - } - - @Deprecated - protected Object engineGetParameter(String key) { - if (key.equals("KSEED")) { - return kSeedAsByteArray; - } else { - return null; - } - } - - /* - * Please read bug report 4044247 for an alternative, faster, - * NON-FIPS approved method to generate K - */ - @Override - protected BigInteger generateK(BigInteger q) { - BigInteger k = null; - - // The application specified a kSeed for us to use. - // Note: we dis-allow usage of the same Kseed twice in a row - if (kSeed != null && !Arrays.equals(kSeed, kSeedLast)) { - k = generateKUsingKSeed(kSeed, q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - kSeedLast = kSeed.clone(); - return k; - } - } - - // The application did not specify a Kseed for us to use. - // We'll generate a new Kseed by getting random bytes from - // a SecureRandom object. - SecureRandom random = getSigningRandom(); - - while (true) { - int[] seed = new int[5]; - - for (int i = 0; i < 5; i++) seed[i] = random.nextInt(); - - k = generateKUsingKSeed(seed, q); - if (k.signum() > 0 && k.compareTo(q) < 0) { - kSeedLast = seed; - return k; - } - } - } - - /** - * Compute k for the DSA signature as defined in the original DSS, - * i.e. FIPS186. - * - * @param seed the seed for generating k. This seed should be - * secure. This is what is referred to as the KSEED in the DSA - * specification. - * - * @param g the g parameter from the DSA key pair. - */ - private BigInteger generateKUsingKSeed(int[] seed, BigInteger q) { - - // check out t in the spec. - int[] t = { 0xEFCDAB89, 0x98BADCFE, 0x10325476, - 0xC3D2E1F0, 0x67452301 }; - // - int[] tmp = SHA_7(seed, t); - byte[] tmpBytes = new byte[tmp.length * 4]; - for (int i = 0; i < tmp.length; i++) { - int k = tmp[i]; - for (int j = 0; j < 4; j++) { - tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8))); - } - } - BigInteger k = new BigInteger(1, tmpBytes).mod(q); - return k; - } - - // Constants for each round - private static final int round1_kt = 0x5a827999; - private static final int round2_kt = 0x6ed9eba1; - private static final int round3_kt = 0x8f1bbcdc; - private static final int round4_kt = 0xca62c1d6; - - /** - * Computes set 1 thru 7 of SHA-1 on m1. */ - static int[] SHA_7(int[] m1, int[] h) { - - int[] W = new int[80]; - System.arraycopy(m1,0,W,0,m1.length); - int temp = 0; - - for (int t = 16; t <= 79; t++){ - temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; - W[t] = ((temp << 1) | (temp >>>(32 - 1))); - } - - int a = h[0],b = h[1],c = h[2], d = h[3], e = h[4]; - for (int i = 0; i < 20; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - ((b&c)|((~b)&d))+ e + W[i] + round1_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 2 - for (int i = 20; i < 40; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - (b ^ c ^ d) + e + W[i] + round2_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 3 - for (int i = 40; i < 60; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - ((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - - // Round 4 - for (int i = 60; i < 80; i++) { - temp = ((a<<5) | (a>>>(32-5))) + - (b ^ c ^ d) + e + W[i] + round4_kt; - e = d; - d = c; - c = ((b<<30) | (b>>>(32-30))); - b = a; - a = temp; - } - int[] md = new int[5]; - md[0] = h[0] + a; - md[1] = h[1] + b; - md[2] = h[2] + c; - md[3] = h[3] + d; - md[4] = h[4] + e; - return md; - } - - /* - * Utility routine for converting a byte array into an int array - */ - private int[] byteArray2IntArray(byte[] byteArray) { - - int j = 0; - byte[] newBA; - int mod = byteArray.length % 4; - - // guarantee that the incoming byteArray is a multiple of 4 - // (pad with 0's) - switch (mod) { - case 3: newBA = new byte[byteArray.length + 1]; break; - case 2: newBA = new byte[byteArray.length + 2]; break; - case 1: newBA = new byte[byteArray.length + 3]; break; - default: newBA = new byte[byteArray.length + 0]; break; - } - System.arraycopy(byteArray, 0, newBA, 0, byteArray.length); - - // copy each set of 4 bytes in the byte array into an integer - int[] newSeed = new int[newBA.length / 4]; - for (int i = 0; i < newBA.length; i += 4) { - newSeed[j] = newBA[i + 3] & 0xFF; - newSeed[j] |= (newBA[i + 2] << 8) & 0xFF00; - newSeed[j] |= (newBA[i + 1] << 16) & 0xFF0000; - newSeed[j] |= (newBA[i + 0] << 24) & 0xFF000000; - j++; - } - - return newSeed; - } - } - /** * Standard SHA1withDSA implementation. */ - public static final class SHA1withDSA extends LegacyDSA { + public static final class SHA1withDSA extends DSA { public SHA1withDSA() throws NoSuchAlgorithmException { super(MessageDigest.getInstance("SHA-1")); } @@ -728,7 +526,7 @@ abstract class DSA extends SignatureSpi { /** * SHA1withDSA implementation that uses the IEEE P1363 format. */ - public static final class SHA1withDSAinP1363Format extends LegacyDSA { + public static final class SHA1withDSAinP1363Format extends DSA { public SHA1withDSAinP1363Format() throws NoSuchAlgorithmException { super(MessageDigest.getInstance("SHA-1"), true); } @@ -741,7 +539,7 @@ abstract class DSA extends SignatureSpi { * not, a SignatureException is thrown when sign()/verify() is called * per JCA spec. */ - static class Raw extends LegacyDSA { + static class Raw extends DSA { // Internal special-purpose MessageDigest impl for RawDSA // Only override whatever methods used // NOTE: no clone support diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java index 72797aea18b..731f6b13e45 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java @@ -70,8 +70,7 @@ public class DSAKeyFactory extends KeyFactorySpi { * By default this is false. * This incompatibility was introduced by 4532506. */ - String prop = AccessController.doPrivileged - (new GetPropertyAction(SERIAL_PROP, null)); + String prop = GetPropertyAction.getProperty(SERIAL_PROP); SERIAL_INTEROP = "true".equalsIgnoreCase(prop); } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyPairGenerator.java b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyPairGenerator.java index e4be7594be2..f162b595f4b 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyPairGenerator.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ import sun.security.jca.JCAUtil; * */ public class DSAKeyPairGenerator extends KeyPairGenerator -implements java.security.interfaces.DSAKeyPairGenerator { + implements java.security.interfaces.DSAKeyPairGenerator { /* Length for prime P and subPrime Q in bits */ private int plen; @@ -74,6 +74,8 @@ implements java.security.interfaces.DSAKeyPairGenerator { // N=160 } else if (sizeP == 2048 && (sizeQ == 224 || sizeQ == 256)) { // L=2048, N=224 or 256 + } else if (sizeP == 3072 && sizeQ == 256) { + // L=3072, N=256 } else { throw new InvalidParameterException ("Unsupported prime and subprime size combination: " + @@ -91,12 +93,17 @@ implements java.security.interfaces.DSAKeyPairGenerator { * Initializes the DSA key pair generator. If genParams * is false, a set of pre-computed parameters is used. */ - public void initialize(int modlen, boolean genParams, SecureRandom random) { + @Override + public void initialize(int modlen, boolean genParams, SecureRandom random) + throws InvalidParameterException { + int subPrimeLen = -1; if (modlen <= 1024) { subPrimeLen = 160; } else if (modlen == 2048) { subPrimeLen = 224; + } else if (modlen == 3072) { + subPrimeLen = 256; } checkStrength(modlen, subPrimeLen); if (genParams) { @@ -122,7 +129,10 @@ implements java.security.interfaces.DSAKeyPairGenerator { * * @param params a fully initialized DSA parameter object. */ - public void initialize(DSAParams params, SecureRandom random) { + @Override + public void initialize(DSAParams params, SecureRandom random) + throws InvalidParameterException { + if (params == null) { throw new InvalidParameterException("Params must not be null"); } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java b/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java index a8d4803dcbb..220b5989f52 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,11 +68,6 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { // the source of randomness private SecureRandom random; - // useful constants - private static final BigInteger ZERO = BigInteger.valueOf(0); - private static final BigInteger ONE = BigInteger.valueOf(1); - private static final BigInteger TWO = BigInteger.valueOf(2); - public DSAParameterGenerator() { } @@ -83,16 +78,18 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { * @param strength the strength (size of prime) in bits * @param random the source of randomness */ + @Override protected void engineInit(int strength, SecureRandom random) { if ((strength >= 512) && (strength <= 1024) && (strength % 64 == 0)) { this.valueN = 160; } else if (strength == 2048) { this.valueN = 224; -// } else if (strength == 3072) { -// this.valueN = 256; + } else if (strength == 3072) { + this.valueN = 256; } else { - throw new InvalidParameterException - ("Prime size should be 512 - 1024, or 2048"); + throw new InvalidParameterException( + "Unexpected strength (size of prime): " + strength + ". " + + "Prime size should be 512 - 1024, or 2048, 3072"); } this.valueL = strength; this.seedLen = valueN; @@ -103,26 +100,24 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { * Initializes this parameter generator with a set of * algorithm-specific parameter generation values. * - * @param genParamSpec the set of algorithm-specific parameter generation values + * @param genParamSpec the set of algorithm-specific parameter + * generation values * @param random the source of randomness * * @exception InvalidAlgorithmParameterException if the given parameter * generation values are inappropriate for this parameter generator */ + @Override protected void engineInit(AlgorithmParameterSpec genParamSpec, - SecureRandom random) - throws InvalidAlgorithmParameterException { + SecureRandom random) throws InvalidAlgorithmParameterException { + if (!(genParamSpec instanceof DSAGenParameterSpec)) { throw new InvalidAlgorithmParameterException("Invalid parameter"); } - DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec) genParamSpec; - int primePLen = dsaGenParams.getPrimePLength(); - if (primePLen > 2048) { - throw new InvalidParameterException - ("No support for prime size " + primePLen); - } + DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec; + // directly initialize using the already validated values - this.valueL = primePLen; + this.valueL = dsaGenParams.getPrimePLength(); this.valueN = dsaGenParams.getSubprimeQLength(); this.seedLen = dsaGenParams.getSeedLength(); this.random = random; @@ -133,6 +128,7 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { * * @return the new AlgorithmParameters object */ + @Override protected AlgorithmParameters engineGenerateParameters() { AlgorithmParameters algParams = null; try { @@ -209,12 +205,12 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { int n = (valueL - 1) / outLen; int b = (valueL - 1) % outLen; byte[] seedBytes = new byte[seedLen/8]; - BigInteger twoSl = TWO.pow(seedLen); + BigInteger twoSl = BigInteger.TWO.pow(seedLen); int primeCertainty = 80; // for 1024-bit prime P if (valueL == 2048) { primeCertainty = 112; - //} else if (valueL == 3072) { - // primeCertainty = 128; + } else if (valueL == 3072) { + primeCertainty = 128; } BigInteger resultP, resultQ, seed = null; @@ -227,14 +223,17 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { /* Step 6 */ BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)). - mod(TWO.pow(valueN - 1)); + mod(BigInteger.TWO.pow(valueN - 1)); /* Step 7 */ - resultQ = TWO.pow(valueN - 1).add(U).add(ONE). subtract(U.mod(TWO)); + resultQ = BigInteger.TWO.pow(valueN - 1) + .add(U) + .add(BigInteger.ONE) + .subtract(U.mod(BigInteger.TWO)); } while (!resultQ.isProbablePrime(primeCertainty)); /* Step 10 */ - BigInteger offset = ONE; + BigInteger offset = BigInteger.ONE; /* Step 11 */ for (counter = 0; counter < 4*valueL; counter++) { BigInteger[] V = new BigInteger[n + 1]; @@ -248,15 +247,16 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { /* Step 11.2 */ BigInteger W = V[0]; for (int i = 1; i < n; i++) { - W = W.add(V[i].multiply(TWO.pow(i * outLen))); + W = W.add(V[i].multiply(BigInteger.TWO.pow(i * outLen))); } - W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * outLen))); + W = W.add((V[n].mod(BigInteger.TWO.pow(b))) + .multiply(BigInteger.TWO.pow(n * outLen))); /* Step 11.3 */ - BigInteger twoLm1 = TWO.pow(valueL - 1); + BigInteger twoLm1 = BigInteger.TWO.pow(valueL - 1); BigInteger X = W.add(twoLm1); /* Step 11.4, 11.5 */ - BigInteger c = X.mod(resultQ.multiply(TWO)); - resultP = X.subtract(c.subtract(ONE)); + BigInteger c = X.mod(resultQ.multiply(BigInteger.TWO)); + resultP = X.subtract(c.subtract(BigInteger.ONE)); /* Step 11.6, 11.7 */ if (resultP.compareTo(twoLm1) > -1 && resultP.isProbablePrime(primeCertainty)) { @@ -266,7 +266,7 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { return result; } /* Step 11.9 */ - offset = offset.add(BigInteger.valueOf(n)).add(ONE); + offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE); } } @@ -281,14 +281,14 @@ public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { * @param the g */ private static BigInteger generateG(BigInteger p, BigInteger q) { - BigInteger h = ONE; + BigInteger h = BigInteger.ONE; /* Step 1 */ - BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q); - BigInteger resultG = ONE; - while (resultG.compareTo(TWO) < 0) { + BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q); + BigInteger resultG = BigInteger.ONE; + while (resultG.compareTo(BigInteger.TWO) < 0) { /* Step 3 */ resultG = h.modPow(pMinusOneOverQ, p); - h = h.add(ONE); + h = h.add(BigInteger.ONE); } return resultG; } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/ParameterCache.java b/jdk/src/java.base/share/classes/sun/security/provider/ParameterCache.java index e688572e16e..93859701646 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/ParameterCache.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/ParameterCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public final class ParameterCache { // case#1: (512 <= p <= 1024) AND q=160 // case#2: p=2048 AND q=224 // case#3: p=2048 AND q=256 - // (NOT-YET-SUPPORTED)case#4: p=3072 AND q=256 + // case#4: p=3072 AND q=256 return dsaCache.get(Integer.valueOf(primeLen+subprimeLen)); } @@ -90,6 +90,8 @@ public final class ParameterCache { return getDSAParameterSpec(primeLen, 160, random); } else if (primeLen == 2048) { return getDSAParameterSpec(primeLen, 224, random); + } else if (primeLen == 3072) { + return getDSAParameterSpec(primeLen, 256, random); } else { return null; } @@ -165,8 +167,8 @@ public final class ParameterCache { /* * We support precomputed parameter for legacy 512, 768 bit moduli, - * and (L, N) combinations of (1024, 160), (2048, 224), (2048, 256). - * In this file we provide both the seed and counter + * and (L, N) combinations of (1024, 160), (2048, 224), (2048, 256), + * (3072, 256). In this file we provide both the seed and counter * value of the generation process for each of these seeds, * for validation purposes. We also include the test vectors * from the DSA specification, FIPS 186, and the FIPS 186 @@ -288,12 +290,14 @@ public final class ParameterCache { "af02112b0d1f02da30973224fe27aeda8b9d4b2922" + "d9ba8be39ed9e103a63c52810bc688b7e2ed4316e1" + "ef17dbde", 16); + dsaCache.put(Integer.valueOf(2048+224), new DSAParameterSpec(p2048_224, q2048_224, g2048_224)); /* * L = 2048, N = 256 - * SEED = b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536 + * SEED = b0b4417601b59cbc9d8ac8f935cadaec \ + * 4f5fbb2f23785609ae466748d9b5a536 * counter = 497 */ BigInteger p2048_256 = @@ -329,14 +333,245 @@ public final class ParameterCache { "8d15bbac65212a55239cfc7e58fae38d7250ab9991" + "ffbc97134025fe8ce04c4399ad96569be91a546f49" + "78693c7a", 16); + dsaCache.put(Integer.valueOf(2048+256), - new DSAParameterSpec(p2048_256, q2048_256, g2048_256)); + new DSAParameterSpec(p2048_256, q2048_256, g2048_256)); - // use DSA parameters for DH as well + + /* + * L = 3072, N = 256 + * SEED = 9fe304be4d6b9919559f39d5911d12e9 \ + * 5158d6946598cd59775b8f3b8fff3a3f + * counter = 1186 + */ + BigInteger p3072_256 = new BigInteger( + "ea9cda9f5fbda66dd830494609405687ab7cf38538e058d1" + + "e2f68dea95364866e1c05beacded24227edee28cad80bcec" + + "ad39913be3b713267b3b96c8d9f0f6a03b5dfc9222d5cfe4" + + "afcc9982f33784f760c3b759aebe3bbe9098a6b84c96f1fd" + + "e44ce11c084c2a082c7a76a0ef142928b4f328406ab9beb2" + + "4f84577dd0f46ce86fd8f08488269998bf4742d6425f7a0e" + + "c75d8660c5dd6f4e3b3d3bee81b2c21afe8c9e8b84b87192" + + "e2cc20f961d2bcd8133afcf3675ab80681cb374c78f33e29" + + "d1011083d89f9c5728b94676fccb1b57bc60288c15d85ae8" + + "38ae1941c5a20ae2b2049b3583fe30da455ddb3e6ad9b995" + + "5cd9bb5681431622beb0f92da533fcab496cebc447aa1bb5" + + "a8039522f2da98ff416289323a64df626ab6881870927dce" + + "e387f13b5c9d24d6cba1d82ed375a082506ee87bc7ae3006" + + "7f4a94e2ee363d992c40f2725b5db4b3525ebde22bbbfd0f" + + "a124a588b0f5a4acb3a86951aff09f8c8198fb5b53da0c93" + + "1cedc598b4f835b779d04d99026c7ba08c4b27f118ac1e3d", 16); + + BigInteger q3072_256 = new BigInteger( + "c4eeac2bbab79bd831946d717a56a6e687547aa8e9c5494a" + + "5a4b2f4ca13d6c11", 16); + + BigInteger g3072_256 = new BigInteger( + "42e5fa7844f8fa9d8998d830d004e7b15b1d276bcbe5f12c" + + "35ec90c1a25f5832018a6724bd9cdbe803b675509bed167f" + + "3d7cf8599fc865c6d5a0f79158c1bc918f00a944d0ad0f38" + + "f520fb91d85d82674d0d5f874faa5fcdfe56cd178c1afdc7" + + "ce8795727b7dee966ed0b3c5cedcef8aca628befebf2d105" + + "c7aff8eb0da9c9610737dd64dce1237b82c1b2bc8608d55f" + + "fda98d7189444e65883315669c05716bde36c78b130aa3df" + + "2e4d609914c7c8dc470f4e300187c775f81e7b1a9c0dce40" + + "5d6eab2cbb9d9c4ef44412ba573dd403c4ed7bc2364772f5" + + "6a30c48de78f5003f9371c55262d2c8ac2246ade3b02fdcf" + + "cf5cbfde74fbcbfe6e0e0fdf3160764f84d311c179a40af6" + + "79a8f47ab13c8f706893245eb11edcce451fa2ab98001998" + + "7f125d8dc96622d419ba0d71f16c6024dce9d364c3b26d8e" + + "c1a3c828f6c9d14b1d0333b95db77bfdbe3c6bce5337a1a5" + + "a7ace10111219448447197e2a344cc423be768bb89e27be6" + + "cbd22085614a5a3360be23b1bfbb6e6e6471363d32c85d31", 16); + + dsaCache.put(Integer.valueOf(3072+256), + new DSAParameterSpec(p3072_256, q3072_256, g3072_256)); + + // + // Diffie-Hellman Groups + // + + // the common generator + BigInteger dhG = BigInteger.TWO; + + // + // From RFC 7296 + + // The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + BigInteger dhP768 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + // The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + BigInteger dhP1024 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + + // + // From RFC 3526 + + // The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } + BigInteger dhP1536 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + + // This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } + BigInteger dhP2048 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + + // This prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } + BigInteger dhP3072 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16); + + // This prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } + BigInteger dhP4096 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF", 16); + + // This prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } + BigInteger dhP6144 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF", 16); + + // This prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } + BigInteger dhP8192 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); + + // use DSA parameters for DH for sizes not defined in RFC 7296, 3526 dhCache.put(Integer.valueOf(512), new DHParameterSpec(p512, g512)); - dhCache.put(Integer.valueOf(768), new DHParameterSpec(p768, g768)); - dhCache.put(Integer.valueOf(1024), new DHParameterSpec(p1024, g1024)); - dhCache.put(Integer.valueOf(2048), new DHParameterSpec(p2048_224, g2048_224)); - } + dhCache.put(Integer.valueOf(768), new DHParameterSpec(dhP768, dhG)); + dhCache.put(Integer.valueOf(1024), new DHParameterSpec(dhP1024, dhG)); + dhCache.put(Integer.valueOf(1536), new DHParameterSpec(dhP1536, dhG)); + dhCache.put(Integer.valueOf(2048), new DHParameterSpec(dhP2048, dhG)); + dhCache.put(Integer.valueOf(3072), new DHParameterSpec(dhP3072, dhG)); + dhCache.put(Integer.valueOf(4096), new DHParameterSpec(dhP4096, dhG)); + dhCache.put(Integer.valueOf(6144), new DHParameterSpec(dhP6144, dhG)); + dhCache.put(Integer.valueOf(8192), new DHParameterSpec(dhP8192, dhG)); + } } diff --git a/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java b/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java index d869a8aaca4..d3497aea557 100644 --- a/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java +++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java @@ -84,9 +84,8 @@ public final class RSAKeyFactory extends KeyFactorySpi { public static final int MAX_RESTRICTED_EXPLEN = 64; private static final boolean restrictExpLen = - "true".equalsIgnoreCase(AccessController.doPrivileged( - new GetPropertyAction( - "sun.security.rsa.restrictRSAExponent", "true"))); + "true".equalsIgnoreCase(GetPropertyAction.getProperty( + "sun.security.rsa.restrictRSAExponent", "true")); // instance used for static translateKey(); private static final RSAKeyFactory INSTANCE = new RSAKeyFactory(); diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java index 8da221961a0..8f849f8d54f 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java @@ -50,10 +50,7 @@ public interface ClientKeyExchangeService { providers = new HashMap<>(); static { - final String key = "java.home"; - String path = AccessController.doPrivileged( - new GetPropertyAction(key), null, - new PropertyPermission(key, "read")); + String path = GetPropertyAction.getProperty("java.home"); ServiceLoader sc = AccessController.doPrivileged( (PrivilegedAction>) diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java b/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java index 4fd224beec7..f7dadcaf66d 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,7 +151,7 @@ final class DHCrypt { params.getP(), params.getG()); } try { - KeyFactory factory = JsseJce.getKeyFactory("DH"); + KeyFactory factory = JsseJce.getKeyFactory("DiffieHellman"); return factory.getKeySpec(key, DHPublicKeySpec.class); } catch (Exception e) { throw new RuntimeException(e); @@ -283,8 +283,6 @@ final class DHCrypt { // // Default DH ephemeral parameters // - private static final BigInteger g2 = BigInteger.valueOf(2); - private static final BigInteger p512 = new BigInteger( // generated "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" + "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" + @@ -302,7 +300,16 @@ final class DHCrypt { "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + "FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p2048 = new BigInteger( // TLS FEDHE + private static final BigInteger p1536 = new BigInteger( // RFC 3526 + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p2048 = new BigInteger( // TLS FFDHE "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + @@ -314,9 +321,126 @@ final class DHCrypt { "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B423861285C97FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p3072 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p4096 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + + "FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p6144 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p8192 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16); private static final BigInteger[] supportedPrimes = { - p512, p768, p1024, p2048}; + p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192}; // a measure of the uncertainty that prime modulus p is not a prime // @@ -401,7 +525,8 @@ final class DHCrypt { for (BigInteger p : supportedPrimes) { int primeLen = p.bitLength(); - defaultParams.putIfAbsent(primeLen, new DHParameterSpec(p, g2)); + defaultParams.putIfAbsent(primeLen, + new DHParameterSpec(p, BigInteger.TWO)); } definedParams = diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java index 494dd3257ba..c05505edf4a 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java @@ -26,7 +26,6 @@ package sun.security.ssl; import java.io.PrintStream; -import java.security.AccessController; import java.util.Locale; import sun.security.util.HexDumpEncoder; @@ -46,8 +45,7 @@ public class Debug { private static String args; static { - args = java.security.AccessController.doPrivileged( - new GetPropertyAction("javax.net.debug", "")); + args = GetPropertyAction.getProperty("javax.net.debug", ""); args = args.toLowerCase(Locale.ENGLISH); if (args.equals("help")) { Help(); @@ -184,8 +182,7 @@ public class Debug { */ static boolean getBooleanProperty(String propName, boolean defaultValue) { // if set, require value of either true or false - String b = AccessController.doPrivileged( - new GetPropertyAction(propName)); + String b = GetPropertyAction.getProperty(propName); if (b == null) { return defaultValue; } else if (b.equalsIgnoreCase("false")) { diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index 903f6fb376a..f3384c5b746 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -656,8 +656,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { // the provider service. Instead, please handle the initialization // exception in the caller's constructor. static { - String property = AccessController.doPrivileged( - new GetPropertyAction(PROPERTY_NAME)); + String property = GetPropertyAction.getProperty(PROPERTY_NAME); if (property != null && property.length() != 0) { // remove double quote marks from beginning/end of the property if (property.length() > 1 && property.charAt(0) == '"' && diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java index a4c119faf25..5ce147a3af3 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java @@ -119,8 +119,8 @@ final class ServerHandshaker extends Handshaker { private long statusRespTimeout; static { - String property = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.ephemeralDHKeySize")); + String property = + GetPropertyAction.getProperty("jdk.tls.ephemeralDHKeySize"); if (property == null || property.length() == 0) { useLegacyEphemeralDHKeys = false; useSmartEphemeralDHKeys = false; @@ -138,11 +138,17 @@ final class ServerHandshaker extends Handshaker { useSmartEphemeralDHKeys = false; try { + // DH parameter generation can be extremely slow, best to + // use one of the supported pre-computed DH parameters + // (see DHCrypt class). customizedDHKeySize = Integer.parseUnsignedInt(property); - if (customizedDHKeySize < 1024 || customizedDHKeySize > 2048) { + if (customizedDHKeySize < 1024 || customizedDHKeySize > 8192 || + (customizedDHKeySize & 0x3f) != 0) { throw new IllegalArgumentException( - "Customized DH key size should be positive integer " + - "between 1024 and 2048 bits, inclusive"); + "Unsupported customized DH key size: " + + customizedDHKeySize + ". " + + "The key size must be multiple of 64, " + + "and can only range from 1024 to 8192 (inclusive)"); } } catch (NumberFormatException nfe) { throw new IllegalArgumentException( @@ -1520,15 +1526,11 @@ final class ServerHandshaker extends Handshaker { * Applications may also want to customize the ephemeral DH key size * to a fixed length for non-exportable cipher suites. This can be * approached by setting system property "jdk.tls.ephemeralDHKeySize" - * to a valid positive integer between 1024 and 2048 bits, inclusive. + * to a valid positive integer between 1024 and 8192 bits, inclusive. * * Note that the minimum acceptable key size is 1024 bits except * exportable cipher suites or legacy mode. * - * Note that the maximum acceptable key size is 2048 bits because - * DH keys bigger than 2048 are not always supported by underlying - * JCE providers. - * * Note that per RFC 2246, the key size limit of DH is 512 bits for * exportable cipher suites. Because of the weakness, exportable * cipher suites are deprecated since TLS v1.1 and they are not @@ -1543,10 +1545,17 @@ final class ServerHandshaker extends Handshaker { } else if (useSmartEphemeralDHKeys) { // matched mode if (key != null) { int ks = KeyUtil.getKeySize(key); - // Note that SunJCE provider only supports 2048 bits DH - // keys bigger than 1024. Please DON'T use value other - // than 1024 and 2048 at present. We may improve the - // underlying providers and key size here in the future. + + // DH parameter generation can be extremely slow, make + // sure to use one of the supported pre-computed DH + // parameters (see DHCrypt class). + // + // Old deployed applications may not be ready to support + // DH key sizes bigger than 2048 bits. Please DON'T use + // value other than 1024 and 2048 at present. May improve + // the underlying providers and key size limit in the + // future when the compatibility and interoperability + // impact is limited. // // keySize = ks <= 1024 ? 1024 : (ks >= 2048 ? 2048 : ks); keySize = ks <= 1024 ? 1024 : 2048; diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java index b618ab31a13..3e21616e48e 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java @@ -73,8 +73,8 @@ final class StatusResponseManager { DEFAULT_CACHE_LIFETIME)); cacheLifetime = life > 0 ? life : 0; - String uriStr = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.stapling.responderURI")); + String uriStr = + GetPropertyAction.getProperty("jdk.tls.stapling.responderURI"); URI tmpURI; try { tmpURI = ((uriStr != null && !uriStr.isEmpty()) ? diff --git a/jdk/src/java.base/share/classes/sun/security/util/Debug.java b/jdk/src/java.base/share/classes/sun/security/util/Debug.java index 35ce8d66348..514608dc73c 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/Debug.java +++ b/jdk/src/java.base/share/classes/sun/security/util/Debug.java @@ -29,6 +29,7 @@ import java.math.BigInteger; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Locale; +import sun.security.action.GetPropertyAction; /** * A utility class for debuging. @@ -42,13 +43,10 @@ public class Debug { private static String args; static { - args = java.security.AccessController.doPrivileged - (new sun.security.action.GetPropertyAction - ("java.security.debug")); + args = GetPropertyAction.getProperty("java.security.debug"); - String args2 = java.security.AccessController.doPrivileged - (new sun.security.action.GetPropertyAction - ("java.security.auth.debug")); + String args2 = + GetPropertyAction.getProperty("java.security.auth.debug"); if (args == null) { args = args2; diff --git a/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java b/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java index 989ec564bf1..0e9bd41a71c 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java +++ b/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -619,8 +619,7 @@ class ObjectIdentifier implements Serializable } } private static void checkFirstComponent(BigInteger first) throws IOException { - if (first.signum() == -1 || - first.compareTo(BigInteger.valueOf(2)) == 1) { + if (first.signum() == -1 || first.compareTo(BigInteger.TWO) > 0) { throw new IOException("ObjectIdentifier() -- " + "First oid component is invalid "); } diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java index 10cbbdceee1..90389c73252 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java @@ -27,6 +27,7 @@ package sun.util.calendar; import java.security.AccessController; import java.util.TimeZone; +import sun.security.action.GetPropertyAction; /** * @@ -142,8 +143,8 @@ public class LocalGregorianCalendar extends BaseCalendar { } // Append an era to the predefined eras if it's given by the property. - String prop = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("jdk.calendar.japanese.supplemental.era")); + String prop = GetPropertyAction + .getProperty("jdk.calendar.japanese.supplemental.era"); if (prop != null) { Era era = parseEraEntry(prop); if (era != null) { 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 365e0e7967c..58c0c5bbe01 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 @@ -245,11 +245,12 @@ public final class ZoneInfoFile { }; static { - String oldmapping = AccessController.doPrivileged( - new GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT); + String oldmapping = GetPropertyAction + .getProperty("sun.timezone.ids.oldmapping", "false") + .toLowerCase(Locale.ROOT); USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { try { String libDir = System.getProperty("java.home") + File.separator + "lib"; try (DataInputStream dis = new DataInputStream( diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index e19a6c8c531..75f235c73e7 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -25,7 +25,6 @@ package sun.util.locale.provider; -import java.security.AccessController; import java.text.spi.BreakIteratorProvider; import java.text.spi.CollatorProvider; import java.text.spi.DateFormatProvider; @@ -47,6 +46,7 @@ import java.util.spi.CurrencyNameProvider; import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; +import sun.security.action.GetPropertyAction; import sun.util.spi.CalendarProvider; /** @@ -116,8 +116,7 @@ public abstract class LocaleProviderAdapter { adapterCache = new ConcurrentHashMap<>(); static { - String order = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.locale.providers")); + String order = GetPropertyAction.getProperty("java.locale.providers"); List typeList = new ArrayList<>(); // Check user specified adapter preference diff --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index 2e8356b1f52..6a9803bf425 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -271,7 +271,6 @@ package.access=sun.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ - jdk.rmi.rmic.,\ jdk.tools.jimage.,\ com.sun.activation.registries.,\ com.sun.java.accessibility.util.internal.,\ @@ -328,7 +327,6 @@ package.definition=sun.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ - jdk.rmi.rmic.,\ jdk.tools.jimage.,\ com.sun.activation.registries.,\ com.sun.java.accessibility.util.internal.,\ diff --git a/jdk/src/java.base/share/native/launcher/defines.h b/jdk/src/java.base/share/native/launcher/defines.h index e3b18882df4..3b63e038f9d 100644 --- a/jdk/src/java.base/share/native/launcher/defines.h +++ b/jdk/src/java.base/share/native/launcher/defines.h @@ -45,7 +45,11 @@ #ifdef JAVA_ARGS #define HAS_JAVA_ARGS JNI_TRUE -static const char* const_progname = "java"; +#ifdef PROGNAME +static const char* const_progname = PROGNAME; +#else +static char* const_progname = NULL; +#endif static const char* const_jargs[] = JAVA_ARGS; /* * ApplicationHome is prepended to each of these entries; the resulting @@ -59,11 +63,7 @@ static const char* const_appclasspath[] = APP_CLASSPATH; #endif /* APP_CLASSPATH */ #else /* !JAVA_ARGS */ #define HAS_JAVA_ARGS JNI_FALSE -#ifdef PROGNAME -static const char* const_progname = PROGNAME; -#else -static char* const_progname = NULL; -#endif +static const char* const_progname = "java"; static const char** const_jargs = NULL; static const char* const_appclasspath[] = { NULL }; #endif /* JAVA_ARGS */ diff --git a/jdk/src/java.base/share/native/libjava/Class.c b/jdk/src/java.base/share/native/libjava/Class.c index 07a3f6db716..6a812c49036 100644 --- a/jdk/src/java.base/share/native/libjava/Class.c +++ b/jdk/src/java.base/share/native/libjava/Class.c @@ -43,7 +43,7 @@ extern jboolean VerifyFixClassname(char *utf_name); #define OBJ "Ljava/lang/Object;" #define CLS "Ljava/lang/Class;" -#define CPL "Lsun/reflect/ConstantPool;" +#define CPL "Ljdk/internal/reflect/ConstantPool;" #define STR "Ljava/lang/String;" #define FLD "Ljava/lang/reflect/Field;" #define MHD "Ljava/lang/reflect/Method;" diff --git a/jdk/src/java.base/share/native/libjava/ConstantPool.c b/jdk/src/java.base/share/native/libjava/ConstantPool.c index f7f744144e3..3fb7b74e518 100644 --- a/jdk/src/java.base/share/native/libjava/ConstantPool.c +++ b/jdk/src/java.base/share/native/libjava/ConstantPool.c @@ -24,111 +24,111 @@ */ #include "jvm.h" -#include "sun_reflect_ConstantPool.h" +#include "jdk_internal_reflect_ConstantPool.h" -JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getSize0 +JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getSize0 (JNIEnv *env, jobject unused, jobject jcpool) { return JVM_ConstantPoolGetSize(env, unused, jcpool); } -JNIEXPORT jclass JNICALL Java_sun_reflect_ConstantPool_getClassAt0 +JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetClassAt(env, unused, jcpool, index); } -JNIEXPORT jclass JNICALL Java_sun_reflect_ConstantPool_getClassAtIfLoaded0 +JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAtIfLoaded0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetClassAtIfLoaded(env, unused, jcpool, index); } -JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getClassRefIndexAt0 +JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getClassRefIndexAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetClassRefIndexAt(env, unused, jcpool, index); } -JNIEXPORT jobject JNICALL Java_sun_reflect_ConstantPool_getMethodAt0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetMethodAt(env, unused, jcpool, index); } -JNIEXPORT jobject JNICALL Java_sun_reflect_ConstantPool_getMethodAtIfLoaded0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAtIfLoaded0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetMethodAtIfLoaded(env, unused, jcpool, index); } -JNIEXPORT jobject JNICALL Java_sun_reflect_ConstantPool_getFieldAt0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetFieldAt(env, unused, jcpool, index); } -JNIEXPORT jobject JNICALL Java_sun_reflect_ConstantPool_getFieldAtIfLoaded0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAtIfLoaded0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetFieldAtIfLoaded(env, unused, jcpool, index); } -JNIEXPORT jobjectArray JNICALL Java_sun_reflect_ConstantPool_getMemberRefInfoAt0 +JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getMemberRefInfoAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetMemberRefInfoAt(env, unused, jcpool, index); } -JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getNameAndTypeRefIndexAt0 +JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefIndexAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, unused, jcpool, index); } -JNIEXPORT jobjectArray JNICALL Java_sun_reflect_ConstantPool_getNameAndTypeRefInfoAt0 +JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefInfoAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, unused, jcpool, index); } -JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getIntAt0 +JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getIntAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetIntAt(env, unused, jcpool, index); } -JNIEXPORT jlong JNICALL Java_sun_reflect_ConstantPool_getLongAt0 +JNIEXPORT jlong JNICALL Java_jdk_internal_reflect_ConstantPool_getLongAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetLongAt(env, unused, jcpool, index); } -JNIEXPORT jfloat JNICALL Java_sun_reflect_ConstantPool_getFloatAt0 +JNIEXPORT jfloat JNICALL Java_jdk_internal_reflect_ConstantPool_getFloatAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetFloatAt(env, unused, jcpool, index); } -JNIEXPORT jdouble JNICALL Java_sun_reflect_ConstantPool_getDoubleAt0 +JNIEXPORT jdouble JNICALL Java_jdk_internal_reflect_ConstantPool_getDoubleAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetDoubleAt(env, unused, jcpool, index); } -JNIEXPORT jstring JNICALL Java_sun_reflect_ConstantPool_getStringAt0 +JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getStringAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetStringAt(env, unused, jcpool, index); } -JNIEXPORT jstring JNICALL Java_sun_reflect_ConstantPool_getUTF8At0 +JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getUTF8At0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetUTF8At(env, unused, jcpool, index); } -JNIEXPORT jbyte JNICALL Java_sun_reflect_ConstantPool_getTagAt0 +JNIEXPORT jbyte JNICALL Java_jdk_internal_reflect_ConstantPool_getTagAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { return JVM_ConstantPoolGetTagAt(env, unused, jcpool, index); diff --git a/jdk/src/java.base/share/native/libjava/NativeAccessors.c b/jdk/src/java.base/share/native/libjava/NativeAccessors.c index e904cf98fcd..53714124502 100644 --- a/jdk/src/java.base/share/native/libjava/NativeAccessors.c +++ b/jdk/src/java.base/share/native/libjava/NativeAccessors.c @@ -24,16 +24,16 @@ */ #include "jvm.h" -#include "sun_reflect_NativeConstructorAccessorImpl.h" -#include "sun_reflect_NativeMethodAccessorImpl.h" +#include "jdk_internal_reflect_NativeConstructorAccessorImpl.h" +#include "jdk_internal_reflect_NativeMethodAccessorImpl.h" -JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_NativeMethodAccessorImpl_invoke0 (JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args) { return JVM_InvokeMethod(env, m, obj, args); } -JNIEXPORT jobject JNICALL Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0 +JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_NativeConstructorAccessorImpl_newInstance0 (JNIEnv *env, jclass unused, jobject c, jobjectArray args) { return JVM_NewInstanceFromConstructor(env, c, args); diff --git a/jdk/src/java.base/share/native/libjava/Reflection.c b/jdk/src/java.base/share/native/libjava/Reflection.c index 02b90138bcc..0a5327eb1fa 100644 --- a/jdk/src/java.base/share/native/libjava/Reflection.c +++ b/jdk/src/java.base/share/native/libjava/Reflection.c @@ -25,22 +25,22 @@ #include "jni.h" #include "jvm.h" -#include "sun_reflect_Reflection.h" +#include "jdk_internal_reflect_Reflection.h" JNIEXPORT jclass JNICALL -Java_sun_reflect_Reflection_getCallerClass__(JNIEnv *env, jclass unused) +Java_jdk_internal_reflect_Reflection_getCallerClass__(JNIEnv *env, jclass unused) { return JVM_GetCallerClass(env, JVM_CALLER_DEPTH); } JNIEXPORT jclass JNICALL -Java_sun_reflect_Reflection_getCallerClass__I(JNIEnv *env, jclass unused, jint depth) +Java_jdk_internal_reflect_Reflection_getCallerClass__I(JNIEnv *env, jclass unused, jint depth) { return JVM_GetCallerClass(env, depth); } JNIEXPORT jint JNICALL -Java_sun_reflect_Reflection_getClassAccessFlags(JNIEnv *env, jclass unused, jclass cls) +Java_jdk_internal_reflect_Reflection_getClassAccessFlags(JNIEnv *env, jclass unused, jclass cls) { return JVM_GetClassAccessFlags(env, cls); } diff --git a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java index 8b4177e3fde..140473283c8 100644 --- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java +++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java @@ -28,7 +28,6 @@ package sun.nio.fs; import java.nio.file.*; import java.io.IOException; import java.util.*; -import java.security.AccessController; import sun.security.action.GetPropertyAction; import static sun.nio.fs.SolarisNativeDispatcher.*; @@ -43,8 +42,7 @@ class SolarisFileSystem extends UnixFileSystem { super(provider, dir); // check os.version - String osversion = AccessController - .doPrivileged(new GetPropertyAction("os.version")); + String osversion = GetPropertyAction.getProperty("os.version"); String[] vers = Util.split(osversion, '.'); assert vers.length >= 2; int majorVersion = Integer.parseInt(vers[0]); diff --git a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java index 4fcb617a200..affdfb96c7f 100644 --- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java +++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java @@ -29,7 +29,6 @@ import java.nio.file.*; import java.nio.file.attribute.*; import java.nio.file.spi.FileTypeDetector; import java.io.IOException; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -85,8 +84,8 @@ public class SolarisFileSystemProvider extends UnixFileSystemProvider { @Override FileTypeDetector getFileTypeDetector() { - Path userMimeTypes = Paths.get(AccessController.doPrivileged( - new GetPropertyAction("user.home")), ".mime.types"); + Path userMimeTypes = Paths.get( + GetPropertyAction.getProperty("user.home"), ".mime.types"); Path etcMimeTypes = Paths.get("/etc/mime.types"); return chain(new GioFileTypeDetector(), diff --git a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java index c0ca02dd4ad..c829994cc85 100644 --- a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java +++ b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java @@ -25,7 +25,7 @@ package java.io; -import java.security.AccessController; +import java.util.Properties; import sun.security.action.GetPropertyAction; @@ -36,12 +36,10 @@ class UnixFileSystem extends FileSystem { private final String javaHome; public UnixFileSystem() { - slash = AccessController.doPrivileged( - new GetPropertyAction("file.separator")).charAt(0); - colon = AccessController.doPrivileged( - new GetPropertyAction("path.separator")).charAt(0); - javaHome = AccessController.doPrivileged( - new GetPropertyAction("java.home")); + Properties props = GetPropertyAction.getProperties(); + slash = props.getProperty("file.separator").charAt(0); + colon = props.getProperty("path.separator").charAt(0); + javaHome = props.getProperty("java.home"); } diff --git a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java index 5f9a546f4bd..8a1b8ca085e 100644 --- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java +++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java @@ -46,8 +46,10 @@ import static java.security.AccessController.doPrivileged; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Properties; import jdk.internal.misc.JavaIOFileDescriptorAccess; import jdk.internal.misc.SharedSecrets; +import sun.security.action.GetPropertyAction; /** * java.lang.Process subclass in the UNIX environment. @@ -123,11 +125,9 @@ final class ProcessImpl extends Process { } String helperPath() { - return AccessController.doPrivileged( - (PrivilegedAction) () -> - helperPath(System.getProperty("java.home"), - System.getProperty("os.arch")) - ); + Properties props = GetPropertyAction.getProperties(); + return helperPath(props.getProperty("java.home"), + props.getProperty("os.arch")); } LaunchMechanism launchMechanism() { @@ -159,9 +159,7 @@ final class ProcessImpl extends Process { } static Platform get() { - String osName = AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("os.name") - ); + String osName = GetPropertyAction.getProperty("os.name"); if (osName.equals("Linux")) { return LINUX; } if (osName.contains("OS X")) { return BSD; } diff --git a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java index ad62c582691..dd1a6548d6a 100644 --- a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java +++ b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java @@ -24,7 +24,7 @@ */ package java.net; -import java.security.AccessController; +import sun.security.action.GetPropertyAction; /** * This class defines a factory for creating DatagramSocketImpls. It defaults @@ -40,8 +40,7 @@ class DefaultDatagramSocketImplFactory { static { String prefix = null; try { - prefix = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("impl.prefix", null)); + prefix = GetPropertyAction.getProperty("impl.prefix", null); if (prefix != null) prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl"); } catch (Exception e) { diff --git a/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java b/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java index 2b1c3fd841e..a9f15a617f0 100644 --- a/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java +++ b/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java @@ -34,7 +34,6 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintStream; -import java.security.AccessController; import sun.net.sdp.SdpSupport; import sun.security.action.GetPropertyAction; @@ -57,8 +56,7 @@ public class SdpProvider extends NetHooks.Provider { public SdpProvider() { // if this property is not defined then there is nothing to do. - String file = AccessController.doPrivileged( - new GetPropertyAction("com.sun.sdp.conf")); + String file = GetPropertyAction.getProperty("com.sun.sdp.conf"); if (file == null) { this.enabled = false; this.rules = null; @@ -77,8 +75,7 @@ public class SdpProvider extends NetHooks.Provider { // check if debugging is enabled PrintStream out = null; - String logfile = AccessController.doPrivileged( - new GetPropertyAction("com.sun.sdp.debug")); + String logfile = GetPropertyAction.getProperty("com.sun.sdp.debug"); if (logfile != null) { out = System.out; if (logfile.length() > 0) { diff --git a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0e067d0681f..f205eaf7545 100644 --- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -39,6 +39,7 @@ import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; import sun.net.www.protocol.http.AuthScheme; import sun.net.www.protocol.http.HttpURLConnection; +import sun.security.action.GetPropertyAction; /** * NTLMAuthentication: @@ -73,12 +74,9 @@ public class NTLMAuthentication extends AuthenticationInfo { NTLMAuthenticationCallback.getNTLMAuthenticationCallback(); private String hostname; - private static String defaultDomain; /* Domain to use if not specified by user */ - - static { - defaultDomain = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", "")); - }; + /* Domain to use if not specified by user */ + private static String defaultDomain = + GetPropertyAction.getProperty("http.auth.ntlm.domain", ""); public static boolean supportsTransparentAuth () { return false; @@ -143,8 +141,7 @@ public class NTLMAuthentication extends AuthenticationInfo { password = pw.getPassword(); init0(); try { - String version = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("ntlm.version")); + String version = GetPropertyAction.getProperty("ntlm.version"); client = new Client(version, hostname, username, ntdomain, password); } catch (NTLMException ne) { try { diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java index 7a0ce392299..9018f0fe6a0 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -26,7 +26,6 @@ package sun.nio.ch; import java.nio.channels.spi.AsynchronousChannelProvider; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -60,8 +59,7 @@ public class DefaultAsynchronousChannelProvider { * Returns the default AsynchronousChannelProvider. */ public static AsynchronousChannelProvider create() { - String osname = AccessController - .doPrivileged(new GetPropertyAction("os.name")); + String osname = GetPropertyAction.getProperty("os.name"); if (osname.equals("SunOS")) return createProvider("sun.nio.ch.SolarisAsynchronousChannelProvider"); if (osname.equals("Linux")) diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java index 2bb712e7867..8e52936ccb0 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java @@ -168,7 +168,7 @@ class InheritedChannel { Class paramTypes[] = { int.class }; Constructor ctr = Reflect.lookupConstructor("java.io.FileDescriptor", paramTypes); - Object args[] = { new Integer(fdVal) }; + Object args[] = { Integer.valueOf(fdVal) }; FileDescriptor fd = (FileDescriptor)Reflect.invoke(ctr, args); diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index 3307c40d8c5..f8c31b5ac94 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -31,7 +31,6 @@ import java.net.*; import java.util.concurrent.*; import java.io.IOException; import java.io.FileDescriptor; -import java.security.AccessController; import sun.net.NetHooks; import sun.security.action.GetPropertyAction; @@ -47,8 +46,8 @@ class UnixAsynchronousSocketChannelImpl private static final boolean disableSynchronousRead; static { - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.ch.disableSynchronousRead", "false"); disableSynchronousRead = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); } diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java index 595f3c6d187..62f6d5ce145 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java +++ b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -26,7 +26,6 @@ package sun.nio.fs; import java.nio.file.spi.FileSystemProvider; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -55,8 +54,7 @@ public class DefaultFileSystemProvider { * Returns the default FileSystemProvider. */ public static FileSystemProvider create() { - String osname = AccessController - .doPrivileged(new GetPropertyAction("os.name")); + String osname = GetPropertyAction.getProperty("os.name"); if (osname.equals("SunOS")) return createProvider("sun.nio.fs.SolarisFileSystemProvider"); if (osname.equals("Linux")) diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java index d394ac10173..7cf295b0d6d 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java +++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java @@ -31,7 +31,6 @@ import java.nio.file.spi.*; import java.io.IOException; import java.util.*; import java.util.regex.Pattern; -import java.security.AccessController; import sun.security.action.GetPropertyAction; /** @@ -57,8 +56,8 @@ abstract class UnixFileSystem // if process-wide chdir is allowed or default directory is not the // process working directory then paths must be resolved against the // default directory. - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.fs.chdirAllowed", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.fs.chdirAllowed", "false"); boolean chdirAllowed = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); if (chdirAllowed) { diff --git a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java index 9ee66bf4169..50ccacc3d1e 100644 --- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -25,8 +25,8 @@ package java.io; -import java.security.AccessController; import java.util.Locale; +import java.util.Properties; import sun.security.action.GetPropertyAction; /** @@ -42,10 +42,9 @@ class WinNTFileSystem extends FileSystem { private final char semicolon; public WinNTFileSystem() { - slash = AccessController.doPrivileged( - new GetPropertyAction("file.separator")).charAt(0); - semicolon = AccessController.doPrivileged( - new GetPropertyAction("path.separator")).charAt(0); + Properties props = GetPropertyAction.getProperties(); + slash = props.getProperty("file.separator").charAt(0); + semicolon = props.getProperty("path.separator").charAt(0); altSlash = (this.slash == '\\') ? '/' : '\\'; } diff --git a/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java b/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java index fb632a4a816..c12378da67d 100644 --- a/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java +++ b/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java @@ -24,8 +24,7 @@ */ package java.net; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.util.Properties; import sun.security.action.GetPropertyAction; /** @@ -57,12 +56,11 @@ class DefaultDatagramSocketImplFactory static { Class prefixImplClassLocal = null; + Properties props = GetPropertyAction.getProperties(); preferIPv4Stack = Boolean.parseBoolean( - AccessController.doPrivileged( - new GetPropertyAction("java.net.preferIPv4Stack"))); + props.getProperty("java.net.preferIPv4Stack")); - String exclBindProp = AccessController.doPrivileged( - new GetPropertyAction("sun.net.useExclusiveBind", "")); + String exclBindProp = props.getProperty("sun.net.useExclusiveBind", ""); exclusiveBind = (exclBindProp.isEmpty()) ? true : Boolean.parseBoolean(exclBindProp); @@ -70,8 +68,7 @@ class DefaultDatagramSocketImplFactory // impl.prefix String prefix = null; try { - prefix = AccessController.doPrivileged( - new GetPropertyAction("impl.prefix", null)); + prefix = props.getProperty("impl.prefix"); if (prefix != null) prefixImplClassLocal = Class.forName("java.net."+prefix+"DatagramSocketImpl"); } catch (Exception e) { diff --git a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java index 8f464ddfd07..294cd5985bf 100644 --- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java @@ -220,7 +220,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl case IP_TOS : case SO_RCVBUF : case SO_SNDBUF : - returnValue = new Integer(value); + returnValue = Integer.valueOf(value); break; default: /* shouldn't get here */ throw new SocketException("Option not supported"); diff --git a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java index 259a39ac195..84dd3d4b515 100644 --- a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java @@ -25,7 +25,9 @@ package java.net; import java.io.*; +import java.security.AccessController; import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; /* * This class PlainSocketImpl simply delegates to the appropriate real @@ -45,55 +47,29 @@ class PlainSocketImpl extends AbstractPlainSocketImpl { private AbstractPlainSocketImpl impl; - /* the windows version. */ - private static float version; - /* java.net.preferIPv4Stack */ - private static boolean preferIPv4Stack = false; - - /* If the version supports a dual stack TCP implementation */ - private static boolean useDualStackImpl = false; - - /* sun.net.useExclusiveBind */ - private static String exclBindProp; + private static final boolean preferIPv4Stack; /* True if exclusive binding is on for Windows */ - private static boolean exclusiveBind = true; + private static final boolean exclusiveBind; static { - java.security.AccessController.doPrivileged( new PrivilegedAction() { - public Object run() { - version = 0; - try { - version = Float.parseFloat(System.getProperties().getProperty("os.version")); - preferIPv4Stack = Boolean.parseBoolean( - System.getProperties().getProperty("java.net.preferIPv4Stack")); - exclBindProp = System.getProperty("sun.net.useExclusiveBind"); - } catch (NumberFormatException e ) { - assert false : e; - } - return null; // nothing to return - } }); + preferIPv4Stack = Boolean.parseBoolean( + AccessController.doPrivileged( + new GetPropertyAction("java.net.preferIPv4Stack"))); - // (version >= 6.0) implies Vista or greater. - if (version >= 6.0 && !preferIPv4Stack) { - useDualStackImpl = true; - } - - if (exclBindProp != null) { - // sun.net.useExclusiveBind is true - exclusiveBind = exclBindProp.length() == 0 ? true - : Boolean.parseBoolean(exclBindProp); - } else if (version < 6.0) { - exclusiveBind = false; - } + String exclBindProp = AccessController.doPrivileged( + new GetPropertyAction("sun.net.useExclusiveBind", "")); + exclusiveBind = (exclBindProp.isEmpty()) + ? true + : Boolean.parseBoolean(exclBindProp); } /** * Constructs an empty instance. */ PlainSocketImpl() { - if (useDualStackImpl) { + if (!preferIPv4Stack) { impl = new DualStackPlainSocketImpl(exclusiveBind); } else { impl = new TwoStacksPlainSocketImpl(exclusiveBind); @@ -104,7 +80,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl * Constructs an instance with the given file descriptor. */ PlainSocketImpl(FileDescriptor fd) { - if (useDualStackImpl) { + if (!preferIPv4Stack) { impl = new DualStackPlainSocketImpl(fd, exclusiveBind); } else { impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind); diff --git a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0e17de44b4c..5583842d0cb 100644 --- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -34,6 +34,7 @@ import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; import sun.net.www.protocol.http.AuthScheme; import sun.net.www.protocol.http.HttpURLConnection; +import sun.security.action.GetPropertyAction; /** * NTLMAuthentication: @@ -52,9 +53,8 @@ public class NTLMAuthentication extends AuthenticationInfo { private static String defaultDomain; /* Domain to use if not specified by user */ static { - defaultDomain = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", - "domain")); + defaultDomain = GetPropertyAction.getProperty("http.auth.ntlm.domain", + "domain"); }; private void init0() { diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java index 4b812d35a4d..5390b55a3ab 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -27,9 +27,9 @@ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; -import java.security.PrivilegedAction; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaIOFileDescriptorAccess; +import sun.security.action.GetPropertyAction; class FileDispatcherImpl extends FileDispatcher { @@ -119,13 +119,8 @@ class FileDispatcherImpl extends FileDispatcher { } static boolean isFastFileTransferRequested() { - String fileTransferProp = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.nio.enableFastFileTransfer"); - } - }); + String fileTransferProp = GetPropertyAction + .getProperty("jdk.nio.enableFastFileTransfer"); boolean enable; if ("".equals(fileTransferProp)) { enable = true; diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/Iocp.java b/jdk/src/java.base/windows/classes/sun/nio/ch/Iocp.java index 715046a0ede..7a2516437bf 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/Iocp.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/Iocp.java @@ -34,8 +34,6 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.security.AccessController; -import sun.security.action.GetPropertyAction; import jdk.internal.misc.Unsafe; /** @@ -46,7 +44,6 @@ import jdk.internal.misc.Unsafe; class Iocp extends AsynchronousChannelGroupImpl { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long INVALID_HANDLE_VALUE = -1L; - private static final boolean supportsThreadAgnosticIo; // maps completion key to channel private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock(); @@ -90,13 +87,6 @@ class Iocp extends AsynchronousChannelGroupImpl { PendingFuture getByOverlapped(long overlapped); } - /** - * Indicates if this operating system supports thread agnostic I/O. - */ - static boolean supportsThreadAgnosticIo() { - return supportsThreadAgnosticIo; - } - // release all resources void implClose() { synchronized (this) { @@ -445,11 +435,5 @@ class Iocp extends AsynchronousChannelGroupImpl { static { IOUtil.load(); initIDs(); - - // thread agnostic I/O on Vista/2008 or newer - String osversion = AccessController.doPrivileged( - new GetPropertyAction("os.version")); - String vers[] = osversion.split("\\."); - supportsThreadAgnosticIo = Integer.parseInt(vers[0]) >= 6; } } diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index 6a5879f6a2e..30f62f22f71 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -318,20 +318,7 @@ public class WindowsAsynchronousFileChannelImpl result.setContext(lockTask); // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - lockTask.run(); - } else { - boolean executed = false; - try { - Invoker.invokeOnThreadInThreadPool(this, lockTask); - executed = true; - } finally { - if (!executed) { - // rollback - removeFromFileLockTable(fli); - } - } - } + lockTask.run(); return result; } @@ -556,11 +543,7 @@ public class WindowsAsynchronousFileChannelImpl result.setContext(readTask); // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - readTask.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, readTask); - } + readTask.run(); return result; } @@ -730,11 +713,7 @@ public class WindowsAsynchronousFileChannelImpl result.setContext(writeTask); // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - writeTask.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, writeTask); - } + writeTask.run(); return result; } diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java index 9d5945364b9..8a735547ff8 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java @@ -342,11 +342,7 @@ class WindowsAsynchronousServerSocketChannelImpl throw new AcceptPendingException(); // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - task.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, task); - } + task.run(); return result; } diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index 3e96279de41..d03f0f3680b 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -378,11 +378,7 @@ class WindowsAsynchronousSocketChannelImpl result.setContext(task); // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - task.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, task); - } + task.run(); return result; } @@ -653,11 +649,7 @@ class WindowsAsynchronousSocketChannelImpl } // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - readTask.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, readTask); - } + readTask.run(); return result; } @@ -910,13 +902,8 @@ class WindowsAsynchronousSocketChannelImpl result.setTimeoutTask(timeoutTask); } - // initiate I/O (can only be done from thread in thread pool) // initiate I/O - if (Iocp.supportsThreadAgnosticIo()) { - writeTask.run(); - } else { - Invoker.invokeOnThreadInThreadPool(this, writeTask); - } + writeTask.run(); return result; } diff --git a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index cb74298d3dc..8e01c9e7332 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -87,13 +87,13 @@ final class WindowsSelectorImpl extends SelectorImpl { private static final class FdMap extends HashMap { static final long serialVersionUID = 0L; private MapEntry get(int desc) { - return get(new Integer(desc)); + return get(Integer.valueOf(desc)); } private MapEntry put(SelectionKeyImpl ski) { - return put(new Integer(ski.channel.getFDVal()), new MapEntry(ski)); + return put(Integer.valueOf(ski.channel.getFDVal()), new MapEntry(ski)); } private MapEntry remove(SelectionKeyImpl ski) { - Integer fd = new Integer(ski.channel.getFDVal()); + Integer fd = Integer.valueOf(ski.channel.getFDVal()); MapEntry x = get(fd); if ((x != null) && (x.ski.channel == ski.channel)) return remove(fd); diff --git a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 02226053f8d..4d2d3e97c4c 100644 --- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -27,7 +27,6 @@ package sun.nio.fs; import java.nio.file.attribute.*; import java.util.concurrent.TimeUnit; -import java.security.AccessController; import jdk.internal.misc.Unsafe; import sun.security.action.GetPropertyAction; @@ -115,8 +114,8 @@ class WindowsFileAttributes // indicates if accurate metadata is required (interesting on NTFS only) private static final boolean ensureAccurateMetadata; static { - String propValue = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.fs.ensureAccurateMetadata", "false")); + String propValue = GetPropertyAction + .getProperty("sun.nio.fs.ensureAccurateMetadata", "false"); ensureAccurateMetadata = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); } diff --git a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 8f70ebe0c12..30b2a93ffcc 100644 --- a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -275,6 +275,151 @@ Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, return JNU_NewStringPlatform(env, hp->h_name); } +static jboolean +tcp_ping4(JNIEnv *env, + jbyteArray addrArray, + jint timeout, + jbyteArray ifArray, + jint ttl) +{ + jint addr; + jbyte caddr[4]; + jint fd; + struct sockaddr_in him; + struct sockaddr_in* netif = NULL; + struct sockaddr_in inf; + int len = 0; + WSAEVENT hEvent; + int connect_rv = -1; + int sz; + + /** + * Convert IP address from byte array to integer + */ + sz = (*env)->GetArrayLength(env, addrArray); + if (sz != 4) { + return JNI_FALSE; + } + memset((char *) &him, 0, sizeof(him)); + memset((char *) caddr, 0, sizeof(caddr)); + (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); + addr = ((caddr[0]<<24) & 0xff000000); + addr |= ((caddr[1] <<16) & 0xff0000); + addr |= ((caddr[2] <<8) & 0xff00); + addr |= (caddr[3] & 0xff); + addr = htonl(addr); + /** + * Socket address + */ + him.sin_addr.s_addr = addr; + him.sin_family = AF_INET; + len = sizeof(him); + + /** + * If a network interface was specified, let's convert its address + * as well. + */ + if (!(IS_NULL(ifArray))) { + memset((char *) caddr, 0, sizeof(caddr)); + (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr); + addr = ((caddr[0]<<24) & 0xff000000); + addr |= ((caddr[1] <<16) & 0xff0000); + addr |= ((caddr[2] <<8) & 0xff00); + addr |= (caddr[3] & 0xff); + addr = htonl(addr); + inf.sin_addr.s_addr = addr; + inf.sin_family = AF_INET; + inf.sin_port = 0; + netif = &inf; + } + + /* + * Can't create a raw socket, so let's try a TCP socket + */ + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + /* note: if you run out of fds, you may not be able to load + * the exception class, and get a NoClassDefFoundError + * instead. + */ + NET_ThrowNew(env, WSAGetLastError(), "Can't create socket"); + return JNI_FALSE; + } + if (ttl > 0) { + setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl)); + } + /* + * A network interface was specified, so let's bind to it. + */ + if (netif != NULL) { + if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { + NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket"); + closesocket(fd); + return JNI_FALSE; + } + } + + /* + * Make the socket non blocking so we can use select/poll. + */ + hEvent = WSACreateEvent(); + WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); + + /* no need to use NET_Connect as non-blocking */ + him.sin_port = htons(7); /* Echo */ + connect_rv = connect(fd, (struct sockaddr *)&him, len); + + /** + * connection established or refused immediately, either way it means + * we were able to reach the host! + */ + if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) { + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_TRUE; + } else { + int optlen; + + switch (WSAGetLastError()) { + case WSAEHOSTUNREACH: /* Host Unreachable */ + case WSAENETUNREACH: /* Network Unreachable */ + case WSAENETDOWN: /* Network is down */ + case WSAEPFNOSUPPORT: /* Protocol Family unsupported */ + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; + } + + if (WSAGetLastError() != WSAEWOULDBLOCK) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", + "connect failed"); + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; + } + + timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); + + /* has connection been established */ + + if (timeout >= 0) { + optlen = sizeof(connect_rv); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, + &optlen) <0) { + connect_rv = WSAGetLastError(); + } + + if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) { + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_TRUE; + } + } + } + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; +} /** * ping implementation. @@ -286,23 +431,17 @@ static jboolean ping4(JNIEnv *env, unsigned long src_addr, unsigned long dest_addr, - jint timeout) + jint timeout, + HANDLE hIcmpFile) { // See https://msdn.microsoft.com/en-us/library/aa366050%28VS.85%29.aspx - HANDLE hIcmpFile; DWORD dwRetVal = 0; char SendData[32] = {0}; LPVOID ReplyBuffer = NULL; DWORD ReplySize = 0; jboolean ret = JNI_FALSE; - hIcmpFile = IcmpCreateFile(); - if (hIcmpFile == INVALID_HANDLE_VALUE) { - NET_ThrowNew(env, WSAGetLastError(), "Unable to open handle"); - return JNI_FALSE; - } - ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData); ReplyBuffer = (VOID*) malloc(ReplySize); if (ReplyBuffer == NULL) { @@ -366,6 +505,7 @@ Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this, jint dest_addr = 0; jbyte caddr[4]; int sz; + HANDLE hIcmpFile; /** * Convert IP address from byte array to integer @@ -396,6 +536,18 @@ Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this, src_addr = htonl(src_addr); } - return ping4(env, src_addr, dest_addr, timeout); + hIcmpFile = IcmpCreateFile(); + if (hIcmpFile == INVALID_HANDLE_VALUE) { + int err = WSAGetLastError(); + if (err == ERROR_ACCESS_DENIED) { + // fall back to TCP echo if access is denied to ICMP + return tcp_ping4(env, addrArray, timeout, ifArray, ttl); + } else { + NET_ThrowNew(env, err, "Unable to create ICMP file handle"); + return JNI_FALSE; + } + } else { + return ping4(env, src_addr, dest_addr, timeout, hIcmpFile); + } } diff --git a/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c index f00a87241bf..7c7515d47f8 100644 --- a/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -326,6 +326,109 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, #ifdef AF_INET6 +/** + * ping implementation using tcp port 7 (echo) + */ +static jboolean +tcp_ping6(JNIEnv *env, + jint timeout, + jint ttl, + struct sockaddr_in6 him6, + struct sockaddr_in6* netif, + int len) +{ + jint fd; + WSAEVENT hEvent; + int connect_rv = -1; + + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); + if (fd == SOCKET_ERROR) { + /* note: if you run out of fds, you may not be able to load + * the exception class, and get a NoClassDefFoundError + * instead. + */ + NET_ThrowNew(env, errno, "Can't create socket"); + return JNI_FALSE; + } + + /** + * A TTL was specified, let's set the socket option. + */ + if (ttl > 0) { + setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)); + } + + /** + * A network interface was specified, let's bind to it. + */ + if (netif != NULL) { + if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) { + NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); + closesocket(fd); + return JNI_FALSE; + } + } + + /** + * Make the socket non blocking. + */ + hEvent = WSACreateEvent(); + WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); + + /* no need to use NET_Connect as non-blocking */ + him6.sin6_port = htons((short) 7); /* Echo port */ + connect_rv = connect(fd, (struct sockaddr *)&him6, len); + + /** + * connection established or refused immediately, either way it means + * we were able to reach the host! + */ + if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) { + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_TRUE; + } else { + int optlen; + + switch (WSAGetLastError()) { + case WSAEHOSTUNREACH: /* Host Unreachable */ + case WSAENETUNREACH: /* Network Unreachable */ + case WSAENETDOWN: /* Network is down */ + case WSAEPFNOSUPPORT: /* Protocol Family unsupported */ + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; + } + + if (WSAGetLastError() != WSAEWOULDBLOCK) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", + "connect failed"); + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; + } + + timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); + + if (timeout >= 0) { + /* has connection been established? */ + optlen = sizeof(connect_rv); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, + &optlen) <0) { + connect_rv = WSAGetLastError(); + } + + if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) { + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_TRUE; + } + } + } + WSACloseEvent(hEvent); + closesocket(fd); + return JNI_FALSE; +} /** * ping implementation. @@ -337,9 +440,9 @@ static jboolean ping6(JNIEnv *env, struct sockaddr_in6* src, struct sockaddr_in6* dest, - jint timeout) + jint timeout, + HANDLE hIcmpFile) { - HANDLE hIcmpFile; DWORD dwRetVal = 0; char SendData[32] = {0}; LPVOID ReplyBuffer = NULL; @@ -347,12 +450,6 @@ ping6(JNIEnv *env, IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL}; struct sockaddr_in6 sa6Source; - hIcmpFile = Icmp6CreateFile(); - if (hIcmpFile == INVALID_HANDLE_VALUE) { - NET_ThrowNew(env, WSAGetLastError(), "Unable to open handle"); - return JNI_FALSE; - } - ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData); ReplyBuffer = (VOID*) malloc(ReplySize); if (ReplyBuffer == NULL) { @@ -411,7 +508,7 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, struct sockaddr_in6* netif = NULL; struct sockaddr_in6 inf6; int len = 0; - int connect_rv = -1; + HANDLE hIcmpFile; /* * If IPv6 is not enable, then we can't reach an IPv6 address, can we? @@ -456,7 +553,19 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, netif = &inf6; } - return ping6(env, netif, &him6, timeout); + hIcmpFile = Icmp6CreateFile(); + if (hIcmpFile == INVALID_HANDLE_VALUE) { + int err = WSAGetLastError(); + if (err == ERROR_ACCESS_DENIED) { + // fall back to TCP echo if access is denied to ICMP + return tcp_ping6(env, timeout, ttl, him6, netif, len); + } else { + NET_ThrowNew(env, err, "Unable to create ICMP file handle"); + return JNI_FALSE; + } + } else { + return ping6(env, netif, &him6, timeout, hIcmpFile); + } #endif /* AF_INET6 */ return JNI_FALSE; diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java index 05eddcea4d8..f6f1df47ff7 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java @@ -35,7 +35,6 @@ import javax.swing.event.ListDataEvent; import javax.swing.filechooser.FileSystemView; import javax.swing.table.AbstractTableModel; -import sun.misc.ManagedLocalsThread; /** * NavServices-like implementation of a file Table * @@ -393,7 +392,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi this.currentDirectory = currentDirectory; this.fid = fid; String name = "Aqua L&F File Loading Thread"; - this.loadThread = new ManagedLocalsThread(this, name); + this.loadThread = new Thread(null, this, name, 0, false); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java index a24faef499a..af2aaf05ed6 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameDockIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,28 +40,28 @@ import sun.swing.SwingUtilities2; * From MacDockIconUI * * A JRSUI L&F implementation of JInternalFrame.JDesktopIcon - * @author - * @version */ -public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseListener, MouseMotionListener, ComponentListener { - private static final String CACHED_FRAME_ICON_KEY = "apple.laf.internal.frameIcon"; +public final class AquaInternalFrameDockIconUI extends DesktopIconUI + implements MouseListener, MouseMotionListener { - protected JInternalFrame.JDesktopIcon fDesktopIcon; - protected JInternalFrame fFrame; - protected ScaledImageLabel fIconPane; - protected DockLabel fDockLabel; - protected boolean fTrackingIcon = false; + private JInternalFrame.JDesktopIcon fDesktopIcon; + private JInternalFrame fFrame; + private ScaledImageLabel fIconPane; + private DockLabel fDockLabel; + private boolean fTrackingIcon; public static ComponentUI createUI(final JComponent c) { return new AquaInternalFrameDockIconUI(); } + @Override public void installUI(final JComponent c) { fDesktopIcon = (JInternalFrame.JDesktopIcon)c; installComponents(); installListeners(); } + @Override public void uninstallUI(final JComponent c) { uninstallComponents(); uninstallListeners(); @@ -69,55 +69,54 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL fFrame = null; } - protected void installComponents() { + private void installComponents() { fFrame = fDesktopIcon.getInternalFrame(); fIconPane = new ScaledImageLabel(); fDesktopIcon.setLayout(new BorderLayout()); fDesktopIcon.add(fIconPane, BorderLayout.CENTER); } - protected void uninstallComponents() { + private void uninstallComponents() { fDesktopIcon.setLayout(null); fDesktopIcon.remove(fIconPane); } - protected void installListeners() { + private void installListeners() { fDesktopIcon.addMouseListener(this); fDesktopIcon.addMouseMotionListener(this); - fFrame.addComponentListener(this); } - protected void uninstallListeners() { - fFrame.removeComponentListener(this); + private void uninstallListeners() { fDesktopIcon.removeMouseMotionListener(this); fDesktopIcon.removeMouseListener(this); } + @Override public Dimension getMinimumSize(final JComponent c) { return new Dimension(32, 32); } + @Override public Dimension getMaximumSize(final JComponent c) { return new Dimension(128, 128); } + @Override public Dimension getPreferredSize(final JComponent c) { return new Dimension(64, 64); //$ Dock preferred size } - public Insets getInsets(final JComponent c) { - return new Insets(0, 0, 0, 0); - } - void updateIcon() { fIconPane.updateIcon(); } + @Override public void mousePressed(final MouseEvent e) { fTrackingIcon = fIconPane.mouseInIcon(e); if (fTrackingIcon) fIconPane.repaint(); } + @Override public void mouseReleased(final MouseEvent e) {// only when it's actually in the image if (fFrame.isIconifiable() && fFrame.isIcon()) { if (fTrackingIcon) { @@ -137,6 +136,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL if (fDockLabel != null && !fIconPane.getBounds().contains(e.getX(), e.getY())) fDockLabel.hide(); } + @Override public void mouseEntered(final MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) return; String title = fFrame.getTitle(); @@ -145,41 +145,27 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL fDockLabel.show(fDesktopIcon); } + @Override public void mouseExited(final MouseEvent e) { if (fDockLabel != null && (e.getModifiers() & InputEvent.BUTTON1_MASK) == 0) fDockLabel.hide(); } + @Override public void mouseClicked(final MouseEvent e) { } + @Override public void mouseDragged(final MouseEvent e) { } + @Override public void mouseMoved(final MouseEvent e) { } - public void componentHidden(final ComponentEvent e) { } - - public void componentMoved(final ComponentEvent e) { } - - public void componentResized(final ComponentEvent e) { - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, null); - } - - public void componentShown(final ComponentEvent e) { - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, null); - } - @SuppressWarnings("serial") // Superclass is not serializable across versions - class ScaledImageLabel extends JLabel { + private final class ScaledImageLabel extends JLabel { ScaledImageLabel() { super(null, null, CENTER); } void updateIcon() { - final Object priorIcon = fFrame.getClientProperty(CACHED_FRAME_ICON_KEY); - if (priorIcon instanceof ImageIcon) { - setIcon((ImageIcon)priorIcon); - return; - } - int width = fFrame.getWidth(); int height = fFrame.getHeight(); @@ -196,11 +182,10 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL final float scale = (float)fDesktopIcon.getWidth() / (float)Math.max(width, height) * 0.89f; // Sending in -1 for width xor height causes it to maintain aspect ratio - final ImageIcon icon = new ImageIcon(fImage.getScaledInstance((int)(width * scale), -1, Image.SCALE_SMOOTH)); - fFrame.putClientProperty(CACHED_FRAME_ICON_KEY, icon); - setIcon(icon); + setIcon(new ImageIcon(fImage.getScaledInstance((int)(width * scale), -1, Image.SCALE_SMOOTH))); } + @Override public void paint(final Graphics g) { if (getIcon() == null) updateIcon(); @@ -222,13 +207,14 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL return getBounds().contains(e.getX(), e.getY()); } + @Override public Dimension getPreferredSize() { return new Dimension(64, 64); //$ Dock preferred size } } @SuppressWarnings("serial") // Superclass is not serializable across versions - class DockLabel extends JLabel { + private static final class DockLabel extends JLabel { static final int NUB_HEIGHT = 7; static final int ROUND_ADDITIONAL_HEIGHT = 8; static final int ROUND_ADDITIONAL_WIDTH = 12; @@ -243,6 +229,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL setSize(SwingUtilities.computeStringWidth(metrics, getText()) + ROUND_ADDITIONAL_WIDTH * 2, metrics.getAscent() + NUB_HEIGHT + ROUND_ADDITIONAL_HEIGHT); } + @Override public void paint(final Graphics g) { final int width = getWidth(); final int height = getHeight(); @@ -303,6 +290,7 @@ public class AquaInternalFrameDockIconUI extends DesktopIconUI implements MouseL } } + @Override @Deprecated public void hide() { final Container parent = getParent(); diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java index 92df95b6db2..d85ed9e8f67 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java @@ -2183,50 +2183,21 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing } protected int preferredTabAreaHeight(final int tabPlacement, final int width) { - final FontMetrics metrics = getFontMetrics(); final int tabCount = tabPane.getTabCount(); int total = 0; if (tabCount > 0) { - int rows = 1; - int x = 0; - final int maxTabHeight = calculateMaxTabHeight(tabPlacement); - - for (int i = 0; i < tabCount; i++) { - final int tabWidth = calculateTabWidth(tabPlacement, i, metrics); - - if (x != 0 && x + tabWidth > width) { - rows++; - x = 0; - } - x += tabWidth; - } - total = calculateTabAreaHeight(tabPlacement, rows, maxTabHeight); + total = calculateTabAreaHeight(tabPlacement, 1, maxTabHeight); } return total; } protected int preferredTabAreaWidth(final int tabPlacement, final int height) { - final FontMetrics metrics = getFontMetrics(); final int tabCount = tabPane.getTabCount(); int total = 0; if (tabCount > 0) { - int columns = 1; - int y = 0; - final int fontHeight = metrics.getHeight(); - maxTabWidth = calculateMaxTabWidth(tabPlacement); - - for (int i = 0; i < tabCount; i++) { - final int tabHeight = calculateTabHeight(tabPlacement, i, fontHeight); - - if (y != 0 && y + tabHeight > height) { - columns++; - y = 0; - } - y += tabHeight; - } - total = calculateTabAreaWidth(tabPlacement, columns, maxTabWidth); + total = calculateTabAreaWidth(tabPlacement, 1, maxTabWidth); } return total; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java index 9e883938e46..0c505b28576 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java @@ -42,7 +42,6 @@ import sun.awt.FontConfiguration; import sun.awt.HeadlessToolkit; import sun.awt.util.ThreadGroupUtils; import sun.lwawt.macosx.*; -import sun.misc.ManagedLocalsThread; public final class CFontManager extends SunFontManager { private static Hashtable genericFonts = new Hashtable(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java index 59101b74006..e2dfcf20d73 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/IntegerNIORaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public class IntegerNIORaster extends SunWritableRaster { ") cannot be <= 0"); } // This is cribbed from java.awt.image.Raster. - DataBuffer db = new DataBufferNIOInt(w * h); + DataBufferNIOInt db = new DataBufferNIOInt(w * h); if (location == null) { location = new Point(0, 0); } @@ -48,13 +48,11 @@ public class IntegerNIORaster extends SunWritableRaster { return new IntegerNIORaster(sppsm, db, location); } - public IntegerNIORaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + public IntegerNIORaster(SampleModel sampleModel, DataBufferNIOInt dataBuffer, Point origin) { // This is all cribbed from sun.awt.image.IntegerInterleavedRaster & sun.awt.image.IntegerComponentRaster super(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), sampleModel.getHeight()), origin, null); - if (!(dataBuffer instanceof DataBufferNIOInt)) { - throw new RasterFormatException("IntegerNIORasters must have DataBufferNIOInt DataBuffers"); - } - this.data = ((DataBufferNIOInt)dataBuffer).getBuffer(); + + this.data = dataBuffer.getBuffer(); } public WritableRaster createCompatibleWritableRaster() { diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java index b74719f149b..b7262a5a402 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java @@ -35,7 +35,6 @@ import java.security.*; import java.util.*; import sun.awt.*; -import sun.misc.ManagedLocalsThread; import sun.print.*; import sun.awt.util.ThreadGroupUtils; @@ -77,13 +76,14 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { shutdown(); waitForRunState(STATE_CLEANUP); }; - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable, + "AWT-Shutdown", 0, false); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); String name = "AWT-LW"; - Thread toolkitThread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread toolkitThread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, 0, false); toolkitThread.setDaemon(true); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); toolkitThread.start(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java index 10aef016b0c..0c8d4afc08f 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java @@ -44,7 +44,6 @@ import sun.awt.dnd.*; import sun.lwawt.LWComponentPeer; import sun.lwawt.LWWindowPeer; import sun.lwawt.PlatformWindow; -import sun.misc.ManagedLocalsThread; public final class CDragSourceContextPeer extends SunDragSourceContextPeer { @@ -181,7 +180,7 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { } } }; - new ManagedLocalsThread(dragRunnable).start(); + new Thread(null, dragRunnable, "Drag", 0, false).start(); } catch (Exception e) { final long nativeDragSource = getNativeContext(); setNativeContext(0); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java index 459afae179d..34651baba70 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java @@ -37,7 +37,6 @@ import java.io.*; import sun.awt.CausedFocusEvent.Cause; import sun.awt.AWTAccessor; import sun.java2d.pipe.Region; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetBooleanAction; class CFileDialog implements FileDialogPeer { @@ -120,7 +119,7 @@ class CFileDialog implements FileDialogPeer { if (visible) { // Java2 Dialog class requires peer to run code in a separate thread // and handles keeping the call modal - new ManagedLocalsThread(new Task()).start(); + new Thread(null, new Task(), "FileDialog", 0, false).start(); } // We hide ourself before "show" returns - setVisible(false) // doesn't apply diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java index 1837feb0ccd..cb1ee148707 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java @@ -29,7 +29,6 @@ import java.awt.*; import java.awt.dnd.*; import sun.lwawt.*; -import sun.misc.ManagedLocalsThread; public class CPrinterDialogPeer extends LWWindowPeer { static { @@ -59,7 +58,7 @@ public class CPrinterDialogPeer extends LWWindowPeer { printerDialog.setRetVal(printerDialog.showDialog()); printerDialog.setVisible(false); }; - new ManagedLocalsThread(task).start(); + new Thread(null, task, "PrintDialog", 0, false).start(); } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 491b257765f..a22f0c3d15e 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -36,6 +36,7 @@ import java.security.PrivilegedAction; import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; @@ -43,7 +44,6 @@ import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; import sun.java2d.*; -import sun.misc.ManagedLocalsThread; import sun.print.*; public final class CPrinterJob extends RasterPrinterJob { @@ -194,10 +194,37 @@ public final class CPrinterJob extends RasterPrinterJob { // setPageRange will set firstPage and lastPage as called in getFirstPage // and getLastPage setPageRange(range[0][0] - 1, range[0][1] - 1); + } else { + // if rangeSelect is SunPageSelection.ALL + // then setPageRange appropriately + setPageRange(-1, -1); } } } + private void setPageRangeAttribute(int from, int to, boolean isRangeSet) { + if (attributes != null) { + // since native Print use zero-based page indices, + // we need to store in 1-based format in attributes set + // but setPageRange again uses zero-based indices so it should be + // 1 less than pageRanges attribute + if (isRangeSet) { + attributes.add(new PageRanges(from+1, to+1)); + attributes.add(SunPageSelection.RANGE); + setPageRange(from, to); + } else { + attributes.add(SunPageSelection.ALL); + } + } + } + + private void setCopiesAttribute(int copies) { + if (attributes != null) { + attributes.add(new Copies(copies)); + super.setCopies(copies); + } + } + volatile boolean onEventThread; @Override @@ -691,9 +718,15 @@ public final class CPrinterJob extends RasterPrinterJob { if (pageFormat != null) { Printable printable = pageable.getPrintable(pageIndex); if (printable != null) { - BufferedImage bimg = new BufferedImage((int)Math.round(pageFormat.getWidth()), (int)Math.round(pageFormat.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); - PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); - Rectangle2D pageFormatArea = getPageFormatArea(pageFormat); + BufferedImage bimg = + new BufferedImage( + (int)Math.round(pageFormat.getWidth()), + (int)Math.round(pageFormat.getHeight()), + BufferedImage.TYPE_INT_ARGB_PRE); + PeekGraphics peekGraphics = + createPeekGraphics(bimg.createGraphics(), printerJob); + Rectangle2D pageFormatArea = + getPageFormatArea(pageFormat); initPrinterGraphics(peekGraphics, pageFormatArea); // Do the assignment here! @@ -741,7 +774,8 @@ public final class CPrinterJob extends RasterPrinterJob { // upcall from native private static void detachPrintLoop(final long target, final long arg) { - new ManagedLocalsThread(() -> _safePrintLoop(target, arg)).start(); + new Thread(null, () -> _safePrintLoop(target, arg), + "PrintLoop", 0, false).start(); } private static native void _safePrintLoop(long target, long arg); diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 165e7029497..03a32ddd8e7 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -312,9 +312,9 @@ static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobjec static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable) { static JNF_MEMBER_CACHE(jm_setService, sjc_CPrinterJob, "setPrinterServiceFromNative", "(Ljava/lang/String;)V"); - static JNF_MEMBER_CACHE(jm_setCopies, sjc_CPrinterJob, "setCopies", "(I)V"); + static JNF_MEMBER_CACHE(jm_setCopiesAttribute, sjc_CPrinterJob, "setCopiesAttribute", "(I)V"); static JNF_MEMBER_CACHE(jm_setCollated, sjc_CPrinterJob, "setCollated", "(Z)V"); - static JNF_MEMBER_CACHE(jm_setPageRange, sjc_CPrinterJob, "setPageRange", "(II)V"); + static JNF_MEMBER_CACHE(jm_setPageRangeAttribute, sjc_CPrinterJob, "setPageRangeAttribute", "(IIZ)V"); // get the selected printer's name, and set the appropriate PrintService on the Java side NSString *name = [[src printer] name]; @@ -327,7 +327,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies]; if ([nsCopies respondsToSelector:@selector(integerValue)]) { - JNFCallVoidMethod(env, dstPrinterJob, jm_setCopies, [nsCopies integerValue]); // AWT_THREADING Safe (known object) + JNFCallVoidMethod(env, dstPrinterJob, jm_setCopiesAttribute, [nsCopies integerValue]); // AWT_THREADING Safe (known object) } NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate]; @@ -340,6 +340,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d if ([nsPrintAllPages respondsToSelector:@selector(boolValue)]) { jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES; + jboolean isRangeSet = false; if (![nsPrintAllPages boolValue]) { NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage]; @@ -353,9 +354,12 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d { jLastPage = [nsLastPage integerValue] - 1; } - } + isRangeSet = true; + } + JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRangeAttribute, + jFirstPage, jLastPage, isRangeSet); + // AWT_THREADING Safe (known object) - JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRange, jFirstPage, jLastPage); // AWT_THREADING Safe (known object) } } @@ -368,6 +372,8 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj static JNF_MEMBER_CACHE(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z"); static JNF_MEMBER_CACHE(jm_getFromPage, sjc_CPrinterJob, "getFromPageAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getToPage, sjc_CPrinterJob, "getToPageAttrib", "()I"); + static JNF_MEMBER_CACHE(jm_getMinPage, sjc_CPrinterJob, "getMinPageAttrib", "()I"); + static JNF_MEMBER_CACHE(jm_getMaxPage, sjc_CPrinterJob, "getMaxPageAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getSelectAttrib, sjc_CPrinterJob, "getSelectAttrib", "()I"); static JNF_MEMBER_CACHE(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I"); static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;"); @@ -379,31 +385,33 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj jboolean collated = JNFCallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object) [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate]; - jint jNumPages = JNFCallIntMethod(env, srcPageable, jm_getNumberOfPages); // AWT_THREADING Safe (!appKit) - if (jNumPages != java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES) - { - jint selectID = JNFCallIntMethod(env, srcPrinterJob, jm_getSelectAttrib); - if (selectID ==0) { - [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; - } else if (selectID == 2) { - // In Mac 10.7, Print ALL is deselected if PrintSelection is YES whether - // NSPrintAllPages is YES or NO - [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; - [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly]; - } else { - [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; - } - - jint fromPage = JNFCallIntMethod(env, srcPrinterJob, jm_getFromPage); - jint toPage = JNFCallIntMethod(env, srcPrinterJob, jm_getToPage); - // setting fromPage and toPage will not be shown in the dialog if printing All pages - [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage]; - [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage]; - } - else - { + jint selectID = JNFCallIntMethod(env, srcPrinterJob, jm_getSelectAttrib); + jint fromPage = JNFCallIntMethod(env, srcPrinterJob, jm_getFromPage); + jint toPage = JNFCallIntMethod(env, srcPrinterJob, jm_getToPage); + if (selectID ==0) { [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; + } else if (selectID == 2) { + // In Mac 10.7, Print ALL is deselected if PrintSelection is YES whether + // NSPrintAllPages is YES or NO + [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; + [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly]; + } else { + jint minPage = JNFCallIntMethod(env, srcPrinterJob, jm_getMinPage); + jint maxPage = JNFCallIntMethod(env, srcPrinterJob, jm_getMaxPage); + + // for PD_SELECTION or PD_NOSELECTION, check from/to page + // to determine which radio button to select + if (fromPage > minPage || toPage < maxPage) { + [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages]; + } else { + [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages]; + } } + + // setting fromPage and toPage will not be shown in the dialog if printing All pages + [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage]; + [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage]; + jobject page = JNFCallObjectMethod(env, srcPrinterJob, jm_getPageFormat); if (page != NULL) { javaPageFormatToNSPrintInfo(env, NULL, page, dst); diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m index 73d4c2f7896..36d13667f55 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,18 +39,21 @@ * If the image of the specified size won't fit into the status bar, * then scale it down proprtionally. Otherwise, leave it as is. */ -static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { +static NSSize ScaledImageSizeForStatusBar(NSSize imageSize, BOOL autosize) { NSRect imageRect = NSMakeRect(0.0, 0.0, imageSize.width, imageSize.height); // There is a black line at the bottom of the status bar // that we don't want to cover with image pixels. - CGFloat desiredHeight = [[NSStatusBar systemStatusBar] thickness] - 1.0; - CGFloat scaleFactor = MIN(1.0, desiredHeight/imageSize.height); - - imageRect.size.width *= scaleFactor; - imageRect.size.height *= scaleFactor; + CGFloat desiredSize = [[NSStatusBar systemStatusBar] thickness] - 1.0; + if (autosize) { + imageRect.size.width = desiredSize; + imageRect.size.height = desiredSize; + } else { + CGFloat scaleFactor = MIN(1.0, desiredSize/imageSize.height); + imageRect.size.width *= scaleFactor; + imageRect.size.height *= scaleFactor; + } imageRect = NSIntegralRect(imageRect); - return imageRect.size; } @@ -101,9 +104,9 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { return peer; } -- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize{ +- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize { NSSize imageSize = [imagePtr size]; - NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize); + NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize, autosize); if (imageSize.width != scaledSize.width || imageSize.height != scaledSize.height) { [imagePtr setSize: scaledSize]; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 32fa02fe175..f71a481a700 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -26,7 +26,6 @@ package com.sun.imageio.stream; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import java.io.IOException; import java.security.AccessController; @@ -92,8 +91,8 @@ public class StreamCloser { * Make its parent the top-level thread group. */ ThreadGroup tg = ThreadGroupUtils.getRootThreadGroup(); - streamCloser = new ManagedLocalsThread(tg, - streamCloserRunnable); + streamCloser = new Thread(tg, streamCloserRunnable, + "StreamCloser", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index 5b57582bee9..d27205f3eaf 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -64,7 +64,6 @@ import sun.awt.SunToolkit; import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; import sun.font.FontUtilities; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; @@ -2053,7 +2052,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel if (audioRunnable != null) { // Runnable appears to block until completed playing, hence // start up another thread to handle playing. - new ManagedLocalsThread(audioRunnable).start(); + new Thread(null, audioRunnable, "Audio", 0, false).start(); } } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java index 910e2dc8352..77930d05657 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.media.sound; import java.nio.ByteBuffer; @@ -319,8 +320,10 @@ public abstract class AudioFloatConverter { float[] out_buff, int out_offset, int out_len) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < out_len; i++) - out_buff[ox++] = in_buff[ix++] * (1.0f / 127.0f); + for (int i = 0; i < out_len; i++) { + byte x = in_buff[ix++]; + out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; + } return out_buff; } @@ -328,8 +331,10 @@ public abstract class AudioFloatConverter { byte[] out_buff, int out_offset) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < in_len; i++) - out_buff[ox++] = (byte) (in_buff[ix++] * 127.0f); + for (int i = 0; i < in_len; i++) { + final float x = in_buff[ix++]; + out_buff[ox++] = (byte) (x > 0 ? x * 127 : x * 128); + } return out_buff; } } @@ -340,9 +345,10 @@ public abstract class AudioFloatConverter { float[] out_buff, int out_offset, int out_len) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < out_len; i++) - out_buff[ox++] = ((in_buff[ix++] & 0xFF) - 127) - * (1.0f / 127.0f); + for (int i = 0; i < out_len; i++) { + byte x = (byte) (in_buff[ix++] - 128); + out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; + } return out_buff; } @@ -350,8 +356,10 @@ public abstract class AudioFloatConverter { byte[] out_buff, int out_offset) { int ix = in_offset; int ox = out_offset; - for (int i = 0; i < in_len; i++) - out_buff[ox++] = (byte) (127 + in_buff[ix++] * 127.0f); + for (int i = 0; i < in_len; i++) { + float x = in_buff[ix++]; + out_buff[ox++] = (byte) (128 + (x > 0 ? x * 127 : x * 128)); + } return out_buff; } } @@ -369,10 +377,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int len = out_offset + out_len; for (int ox = out_offset; ox < len; ox++) { - out_buff[ox] = ((short) ((in_buff[ix++] & 0xFF) | - (in_buff[ix++] << 8))) * (1.0f / 32767.0f); + short x = (short) (in_buff[ix++] & 0xFF | (in_buff[ix++] << 8)); + out_buff[ox] = x > 0 ? x / 32767.0f : x / 32768.0f; } - return out_buff; } @@ -381,7 +388,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; int len = in_offset + in_len; for (int ix = in_offset; ix < len; ix++) { - int x = (int) (in_buff[ix] * 32767.0); + float f = in_buff[ix]; + short x = (short) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); } @@ -396,8 +404,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < out_len; i++) { - out_buff[ox++] = ((short) ((in_buff[ix++] << 8) | - (in_buff[ix++] & 0xFF))) * (1.0f / 32767.0f); + short x = (short) ((in_buff[ix++] << 8) | (in_buff[ix++] & 0xFF)); + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -407,7 +415,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + short x = (short) (f > 0 ? f * 32767.0f : f * 32768.0f); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; } @@ -423,7 +432,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < out_len; i++) { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8); - out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f); + x -= 32768; + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -433,7 +443,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = 32767 + (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); } @@ -449,7 +460,8 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < out_len; i++) { int x = ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f); + x -= 32768; + out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; } return out_buff; } @@ -459,7 +471,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = 32767 + (int) (in_buff[ix++] * 32767.0); + float f = in_buff[ix++]; + int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; } @@ -484,7 +497,7 @@ public abstract class AudioFloatConverter { | ((in_buff[ix++] & 0xFF) << 16); if (x > 0x7FFFFF) x -= 0x1000000; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -494,7 +507,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); if (x < 0) x += 0x1000000; out_buff[ox++] = (byte) x; @@ -516,7 +530,7 @@ public abstract class AudioFloatConverter { | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); if (x > 0x7FFFFF) x -= 0x1000000; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -526,7 +540,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); if (x < 0) x += 0x1000000; out_buff[ox++] = (byte) (x >>> 16); @@ -546,8 +561,8 @@ public abstract class AudioFloatConverter { for (int i = 0; i < out_len; i++) { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16); - x -= 0x7FFFFF; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + x -= 0x800000; + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -557,8 +572,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); - x += 0x7FFFFF; + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); + x += 0x800000; out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) (x >>> 16); @@ -576,8 +592,8 @@ public abstract class AudioFloatConverter { for (int i = 0; i < out_len; i++) { int x = ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - x -= 0x7FFFFF; - out_buff[ox++] = x * (1.0f / (float)0x7FFFFF); + x -= 0x800000; + out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; } return out_buff; } @@ -587,8 +603,9 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * (float)0x7FFFFF); - x += 0x7FFFFF; + float f = in_buff[ix++]; + int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); + x += 8388608; out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) x; @@ -673,7 +690,7 @@ public abstract class AudioFloatConverter { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 24); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -685,7 +702,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; out_buff[ox++] = (byte) x; out_buff[ox++] = (byte) (x >>> 8); out_buff[ox++] = (byte) (x >>> 16); @@ -706,7 +723,7 @@ public abstract class AudioFloatConverter { int x = ((in_buff[ix++] & 0xFF) << 24) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -718,7 +735,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; out_buff[ox++] = (byte) (x >>> 24); out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); @@ -737,7 +754,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, signed, little-endian private static class AudioFloatConversion32xSL extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xSL(int xbytes) { this.xbytes = xbytes; @@ -778,7 +795,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, signed, big-endian private static class AudioFloatConversion32xSB extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xSB(int xbytes) { this.xbytes = xbytes; @@ -820,7 +837,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, unsigned, little-endian private static class AudioFloatConversion32xUL extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xUL(int xbytes) { this.xbytes = xbytes; @@ -835,7 +852,7 @@ public abstract class AudioFloatConverter { int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 24); - x -= 0x7FFFFFFF; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); } return out_buff; @@ -847,7 +864,7 @@ public abstract class AudioFloatConverter { int ox = out_offset; for (int i = 0; i < in_len; i++) { int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); - x += 0x7FFFFFFF; + x += 0x80000000; for (int j = 0; j < xbytes; j++) { out_buff[ox++] = 0; } @@ -863,7 +880,7 @@ public abstract class AudioFloatConverter { // PCM 32+ bit, unsigned, big-endian private static class AudioFloatConversion32xUB extends AudioFloatConverter { - final int xbytes; + private final int xbytes; AudioFloatConversion32xUB(int xbytes) { this.xbytes = xbytes; @@ -878,7 +895,7 @@ public abstract class AudioFloatConverter { ((in_buff[ix++] & 0xFF) << 16) | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); ix += xbytes; - x -= 2147483647; + x -= 0x80000000; out_buff[ox++] = x * (1.0f / 2147483647.0f); } return out_buff; @@ -889,8 +906,8 @@ public abstract class AudioFloatConverter { int ix = in_offset; int ox = out_offset; for (int i = 0; i < in_len; i++) { - int x = (int) (in_buff[ix++] * 2147483647.0); - x += 2147483647; + int x = (int) (in_buff[ix++] * 2147483647.0f); + x += 0x80000000; out_buff[ox++] = (byte) (x >>> 24); out_buff[ox++] = (byte) (x >>> 16); out_buff[ox++] = (byte) (x >>> 8); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java index 738704facf4..d59118889c2 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java @@ -25,8 +25,6 @@ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedInputStream; import java.io.InputStream; import java.io.File; @@ -145,12 +143,11 @@ final class JSSecurityManager { static Thread createThread(final Runnable runnable, final String threadName, final boolean isDaemon, final int priority, - final boolean doStart) { - Thread thread = new ManagedLocalsThread(runnable); + final boolean doStart) + { + String name = (threadName != null) ? threadName : "JSSM Thread"; + Thread thread = new Thread(null, runnable, threadName, 0, false); - if (threadName != null) { - thread.setName(threadName); - } thread.setDaemon(isDaemon); if (priority >= 0) { thread.setPriority(priority); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java index 1ac0a54a3d8..ca9ac9c9122 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,7 +232,7 @@ public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, L } else if (sequencer != null) { try { sequencerloop = false; - sequencer.addMetaEventListener(this); + sequencer.removeMetaEventListener(this); sequencer.stop(); } catch (Exception e3) { if (Printer.err) e3.printStackTrace(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java index 87f4852714c..3a5e6d9dc1b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java @@ -24,8 +24,6 @@ */ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.IOException; import javax.sound.sampled.AudioInputStream; @@ -55,7 +53,7 @@ public final class SoftAudioPusher implements Runnable { if (active) return; active = true; - audiothread = new ManagedLocalsThread(this); + audiothread = new Thread(null, this, "AudioPusher", 0, false); audiothread.setDaemon(true); audiothread.setPriority(Thread.MAX_PRIORITY); audiothread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java index f845a369e0b..61cdf7cdf25 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java @@ -24,8 +24,6 @@ */ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import java.io.EOFException; @@ -216,7 +214,7 @@ public final class SoftJitterCorrector extends AudioInputStream { } }; - thread = new ManagedLocalsThread(runnable); + thread = new Thread(null, runnable, "JitterCorrector", 0, false); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index ef2182d6c9e..41b0cffa3df 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -25,8 +25,6 @@ package com.sun.media.sound; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -141,7 +139,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, pusher = null; jitter_stream = null; sourceDataLine = null; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "Synthesizer",0,false).start(); } return len; } diff --git a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java index 67b4ad852df..d4bead31360 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java @@ -31,7 +31,6 @@ import java.awt.event.WindowEvent; import java.util.ArrayList; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import sun.awt.dnd.SunDragSourceContextPeer; @@ -55,7 +54,7 @@ import sun.awt.dnd.SunDragSourceContextPeer; * * @since 1.1 */ -class EventDispatchThread extends ManagedLocalsThread { +class EventDispatchThread extends Thread { private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread"); @@ -66,8 +65,16 @@ class EventDispatchThread extends ManagedLocalsThread { private ArrayList eventFilters = new ArrayList(); + /** + * Must always call 5 args super-class constructor passing false + * to indicate not to inherit locals. + */ + private EventDispatchThread() { + throw new UnsupportedOperationException("Must erase locals"); + } + EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { - super(group, name); + super(group, null, name, 0, false); setEventQueue(queue); } diff --git a/jdk/src/java.desktop/share/classes/java/awt/Font.java b/jdk/src/java.desktop/share/classes/java/awt/Font.java index 8edd2227bad..29ce9f1a084 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Font.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Font.java @@ -765,6 +765,49 @@ public class Font implements java.io.Serializable this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); } + /** + * Returns true if any part of the specified text is from a + * complex script for which the implementation will need to invoke + * layout processing in order to render correctly when using + * {@link Graphics#drawString(String,int,int) drawString(String,int,int)} + * and other text rendering methods. Measurement of the text + * may similarly need the same extra processing. + * The {@code start} and {@code end} indices are provided so that + * the application can request only a subset of the text be considered. + * The last char index examined is at {@code "end-1"}, + * i.e a request to examine the entire array would be + *
+     * {@code Font.textRequiresLayout(chars, 0, chars.length);}
+     * 
+ * An application may find this information helpful in + * performance sensitive code. + *

+ * Note that even if this method returns {@code false}, layout processing + * may still be invoked when used with any {@code Font} + * for which {@link #hasLayoutAttributes()} returns {@code true}, + * so that method will need to be consulted for the specific font, + * in order to obtain an answer which accounts for such font attributes. + * + * @param chars the text. + * @param start the index of the first char to examine. + * @param end the ending index, exclusive. + * @return {@code true} if the specified text will need special layout. + * @throws NullPointerException if {@code chars} is null. + * @throws ArrayIndexOutOfBoundsException if {@code start} is negative or + * {@code end} is greater than the length of the {@code chars} array. + * @since 9 + */ + public static boolean textRequiresLayout(char[] chars, + int start, int end) { + if (chars == null) { + throw new NullPointerException("null char array"); + } + if (start < 0 || end > chars.length) { + throw new ArrayIndexOutOfBoundsException("start < 0 or end > len"); + } + return FontUtilities.isComplexScript(chars, start, end); + } + /** * Returns a {@code Font} appropriate to the attributes. * If {@code attributes} contains a {@code FONT} attribute diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java b/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java index c5e8ec8d3ab..0db6ff17441 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java @@ -404,9 +404,6 @@ public abstract class PackedColorModel extends ColorModel { PackedColorModel cm = (PackedColorModel) obj; int numC = cm.getNumComponents(); - if (numC != numComponents) { - return false; - } for(int i=0; i < numC; i++) { if (maskArray[i] != cm.getMask(i)) { return false; diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java b/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java index f5a36d10a47..c7aca57eed8 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/Raster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -629,7 +629,8 @@ public class Raster { int scanlineStride, int pixelStride, int bandOffsets[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -645,15 +646,26 @@ public class Raster { bandOffsets); switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(csm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteInterleavedRaster(csm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(csm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortInterleavedRaster(csm, + (DataBufferUShort) dataBuffer, location); + } + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(csm, dataBuffer, location); } /** @@ -691,7 +703,8 @@ public class Raster { int scanlineStride, int bankIndices[], int bandOffsets[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -713,18 +726,29 @@ public class Raster { switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteBandedRaster(bsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteBandedRaster(bsm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortBandedRaster(bsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortBandedRaster(bsm, + (DataBufferUShort) dataBuffer, location); + } + break; case DataBuffer.TYPE_INT: - return new SunWritableRaster(bsm, dataBuffer, location); + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(bsm, dataBuffer, location); } /** @@ -761,7 +785,8 @@ public class Raster { int w, int h, int scanlineStride, int bandMasks[], - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -776,18 +801,33 @@ public class Raster { switch(dataType) { case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte) { + return new ByteInterleavedRaster(sppsm, + (DataBufferByte) dataBuffer, location); + } + break; case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sppsm, + (DataBufferUShort) dataBuffer, location); + } + break; case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sppsm, + (DataBufferInt) dataBuffer, location); + } + break; default: throw new IllegalArgumentException("Unsupported data type " + dataType); } + + // Create the generic raster + return new SunWritableRaster(sppsm, dataBuffer, location); } /** @@ -821,7 +861,8 @@ public class Raster { public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, int bitsPerPixel, - Point location) { + Point location) + { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } @@ -846,9 +887,10 @@ public class Raster { MultiPixelPackedSampleModel mppsm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); - if (dataType == DataBuffer.TYPE_BYTE && - (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) { - return new BytePackedRaster(mppsm, dataBuffer, location); + if (dataBuffer instanceof DataBufferByte && + (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) + { + return new BytePackedRaster(mppsm, (DataBufferByte) dataBuffer, location); } else { return new SunWritableRaster(mppsm, dataBuffer, location); } @@ -878,7 +920,8 @@ public class Raster { */ public static Raster createRaster(SampleModel sm, DataBuffer db, - Point location) { + Point location) + { if ((sm == null) || (db == null)) { throw new NullPointerException("SampleModel and DataBuffer cannot be null"); } @@ -890,32 +933,53 @@ public class Raster { if (sm instanceof PixelInterleavedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; } } else if (sm instanceof SinglePixelPackedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; - case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_INT: + if (db instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sm, + (DataBufferInt) db, location); + } + break; } } else if (sm instanceof MultiPixelPackedSampleModel && dataType == DataBuffer.TYPE_BYTE && - sm.getSampleSize(0) < 8) { - return new BytePackedRaster(sm, db, location); + db instanceof DataBufferByte && + sm.getSampleSize(0) < 8) + { + return new BytePackedRaster(sm, (DataBufferByte) db, location); } // we couldn't do anything special - do the generic thing - - return new Raster(sm,db,location); + return new Raster(sm, db, location); } /** @@ -964,7 +1028,8 @@ public class Raster { */ public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, - Point location) { + Point location) + { if ((sm == null) || (db == null)) { throw new NullPointerException("SampleModel and DataBuffer cannot be null"); } @@ -976,32 +1041,53 @@ public class Raster { if (sm instanceof PixelInterleavedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; } } else if (sm instanceof SinglePixelPackedSampleModel) { switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_BYTE: + if (db instanceof DataBufferByte) { + return new ByteInterleavedRaster(sm, + (DataBufferByte) db, location); + } + break; - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_USHORT: + if (db instanceof DataBufferUShort) { + return new ShortInterleavedRaster(sm, + (DataBufferUShort) db, location); + } + break; - case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sm, db, location); + case DataBuffer.TYPE_INT: + if (db instanceof DataBufferInt) { + return new IntegerInterleavedRaster(sm, + (DataBufferInt) db, location); + } + break; } } else if (sm instanceof MultiPixelPackedSampleModel && dataType == DataBuffer.TYPE_BYTE && - sm.getSampleSize(0) < 8) { - return new BytePackedRaster(sm, db, location); + db instanceof DataBufferByte && + sm.getSampleSize(0) < 8) + { + return new BytePackedRaster(sm, (DataBufferByte) db, location); } // we couldn't do anything special - do the generic thing - - return new SunWritableRaster(sm,db,location); + return new SunWritableRaster(sm, db, location); } /** diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java index 77d0b281b43..3eccc740aab 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java @@ -35,8 +35,6 @@ package java.awt.image.renderable; -import sun.misc.ManagedLocalsThread; - import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.ImageConsumer; @@ -137,7 +135,7 @@ public class RenderableImageProducer implements ImageProducer, Runnable { addConsumer(ic); // Need to build a runnable object for the Thread. String name = "RenderableImageProducer Thread"; - Thread thread = new ManagedLocalsThread(this, name); + Thread thread = new Thread(null, this, name, 0, false); thread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java index ae480b9c002..7af7b77be77 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -1294,7 +1294,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(File input) throws IOException { if (input == null) { @@ -1344,7 +1345,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(InputStream input) throws IOException { if (input == null) { @@ -1352,6 +1354,9 @@ public final class ImageIO { } ImageInputStream stream = createImageInputStream(input); + if (stream == null) { + throw new IIOException("Can't create an ImageInputStream!"); + } BufferedImage bi = read(stream); if (bi == null) { stream.close(); @@ -1384,7 +1389,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @exception IOException if an error occurs during reading or when not + * able to create required ImageInputStream. */ public static BufferedImage read(URL input) throws IOException { if (input == null) { @@ -1398,6 +1404,14 @@ public final class ImageIO { throw new IIOException("Can't get input stream from URL!", e); } ImageInputStream stream = createImageInputStream(istream); + if (stream == null) { + /* close the istream when stream is null so that if user has + * given filepath as URL he can delete it, otherwise stream will + * be open to that file and he will not be able to delete it. + */ + istream.close(); + throw new IIOException("Can't create an ImageInputStream!"); + } BufferedImage bi; try { bi = read(stream); @@ -1510,7 +1524,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing. + * @exception IOException if an error occurs during writing or when not + * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, String formatName, @@ -1518,7 +1533,6 @@ public final class ImageIO { if (output == null) { throw new IllegalArgumentException("output == null!"); } - ImageOutputStream stream = null; ImageWriter writer = getWriter(im, formatName); if (writer == null) { @@ -1528,13 +1542,11 @@ public final class ImageIO { return false; } - try { - output.delete(); - stream = createImageOutputStream(output); - } catch (IOException e) { - throw new IIOException("Can't create output stream!", e); + output.delete(); + ImageOutputStream stream = createImageOutputStream(output); + if (stream == null) { + throw new IIOException("Can't create an ImageOutputStream!"); } - try { return doWrite(im, writer, stream); } finally { @@ -1562,7 +1574,8 @@ public final class ImageIO { * * @exception IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing. + * @exception IOException if an error occurs during writing or when not + * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, String formatName, @@ -1570,13 +1583,10 @@ public final class ImageIO { if (output == null) { throw new IllegalArgumentException("output == null!"); } - ImageOutputStream stream = null; - try { - stream = createImageOutputStream(output); - } catch (IOException e) { - throw new IIOException("Can't create output stream!", e); + ImageOutputStream stream = createImageOutputStream(output); + if (stream == null) { + throw new IIOException("Can't create an ImageOutputStream!"); } - try { return doWrite(im, getWriter(im, formatName), stream); } finally { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java index 01edf5d0486..b37dd05050a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,12 @@ package javax.swing; import javax.swing.event.*; import javax.swing.filechooser.*; +import javax.swing.filechooser.FileFilter; import javax.swing.plaf.FileChooserUI; import javax.accessibility.*; -import java.io.File; -import java.io.ObjectOutputStream; -import java.io.IOException; +import java.io.*; import java.util.Vector; import java.awt.AWTEvent; @@ -51,8 +50,6 @@ import java.beans.JavaBean; import java.beans.BeanProperty; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; import java.lang.ref.WeakReference; /** @@ -390,19 +387,7 @@ public class JFileChooser extends JComponent implements Accessible { } private void installHierarchyListener() { - addHierarchyListener(new HierarchyListener() { - @Override - public void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) - == HierarchyEvent.PARENT_CHANGED) { - JFileChooser fc = JFileChooser.this; - JRootPane rootPane = SwingUtilities.getRootPane(fc); - if (rootPane != null) { - rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc)); - } - } - } - }); + addHierarchyListener(new FCHierarchyListener()); } private void installShowFilesListener() { @@ -2055,4 +2040,18 @@ public class JFileChooser extends JComponent implements Accessible { } // inner class AccessibleJFileChooser + private class FCHierarchyListener implements HierarchyListener, + Serializable { + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) + == HierarchyEvent.PARENT_CHANGED) { + JFileChooser fc = JFileChooser.this; + JRootPane rootPane = SwingUtilities.getRootPane(fc); + if (rootPane != null) { + rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc)); + } + } + } + } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java b/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java index c9a279a5ed0..643f2c85ecb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JMenu.java @@ -1296,7 +1296,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @return the array of menu items */ private MenuElement[] buildMenuElementArray(JMenu leaf) { - Vector elements = new Vector(); + Vector elements = new Vector<>(); Component current = leaf.getPopupMenu(); JPopupMenu pop; JMenu menu; @@ -1314,11 +1314,14 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement } else if (current instanceof JMenuBar) { bar = (JMenuBar) current; elements.insertElementAt(bar, 0); - MenuElement me[] = new MenuElement[elements.size()]; - elements.copyInto(me); - return me; + break; + } else { + break; } } + MenuElement me[] = new MenuElement[elements.size()]; + elements.copyInto(me); + return me; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java index a0111c36c0d..9ca12ea6ee1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java @@ -56,7 +56,6 @@ import java.util.List; import javax.print.attribute.*; import javax.print.PrintService; -import sun.misc.ManagedLocalsThread; import sun.reflect.misc.ReflectUtil; import sun.swing.SwingUtilities2; @@ -6375,7 +6374,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable }; // start printing on another thread - Thread th = new ManagedLocalsThread(runnable); + Thread th = new Thread(null, runnable, "JTablePrint", 0, false); th.start(); printingStatus.showModal(true); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java index 5f05a3b6beb..9160b956e95 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java @@ -36,7 +36,6 @@ import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicLong; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * Internal class to manage all Timers using one thread. @@ -101,8 +100,8 @@ class TimerQueue implements Runnable final ThreadGroup threadGroup = AppContext.getAppContext().getThreadGroup(); AccessController.doPrivileged((PrivilegedAction) () -> { String name = "TimerQueue"; - Thread timerThread = new ManagedLocalsThread(threadGroup, - this, name); + Thread timerThread = + new Thread(threadGroup, this, name, 0, false); timerThread.setDaemon(true); timerThread.setPriority(Thread.NORM_PRIORITY); timerThread.start(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index d263907f742..a95c82d20fe 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -26,7 +26,6 @@ package javax.swing.plaf.basic; import sun.awt.shell.ShellFolder; -import sun.misc.ManagedLocalsThread; import javax.swing.*; import javax.swing.event.ListDataEvent; @@ -271,7 +270,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr this.currentDirectory = currentDirectory; this.fid = fid; String name = "Basic L&F File Loading Thread"; - this.loadThread = new ManagedLocalsThread(this, name); + this.loadThread = new Thread(null, this, name, 0, false); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index 4a4d0baf32b..1b6c56c2fc0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -797,9 +797,11 @@ public class BasicPopupMenuUI extends PopupMenuUI { if (invoker instanceof JPopupMenu) { invoker = ((JPopupMenu)invoker).getInvoker(); } - grabbedWindow = invoker instanceof Window? - (Window)invoker : - SwingUtilities.getWindowAncestor(invoker); + grabbedWindow = (invoker == null) + ? null + : ((invoker instanceof Window) + ? (Window) invoker + : SwingUtilities.getWindowAncestor(invoker)); if(grabbedWindow != null) { if(tk instanceof sun.awt.SunToolkit) { ((sun.awt.SunToolkit)tk).grab(grabbedWindow); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java index 7fdbe384f57..ef49aab21a4 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -995,16 +995,7 @@ public final class NimbusStyle extends SynthStyle { // StateInfo match, otherwise a StateInfo with // SELECTED | ENABLED would match ENABLED, which we // don't want. - - // This comes from BigInteger.bitCnt - int bitCount = oState; - bitCount -= (0xaaaaaaaa & bitCount) >>> 1; - bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & - 0x33333333); - bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; - bitCount += bitCount >>> 8; - bitCount += bitCount >>> 16; - bitCount = bitCount & 0xff; + int bitCount = Integer.bitCount(oState); if (bitCount > bestCount) { bestIndex = counter; bestCount = bitCount; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java index bf41d10dff1..56744c2a03b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java @@ -775,7 +775,7 @@ public abstract class SynthStyle { if (disabledColor == null || disabledColor instanceof UIResource) { return getColorForState(context, type); } - } else if (c instanceof JLabel && + } else if ((c instanceof JLabel || c instanceof JMenuItem) && (type == ColorType.FOREGROUND || type == ColorType.TEXT_FOREGROUND)) { return getColorForState(context, type); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index 571745be89d..3d31a0d1936 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -70,7 +70,6 @@ import javax.print.attribute.*; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; import sun.swing.PrintingStatus; import sun.swing.SwingUtilities2; import sun.swing.text.TextComponentPrintable; @@ -2353,7 +2352,8 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A runnablePrinting.run(); } else { if (isEventDispatchThread) { - new ManagedLocalsThread(runnablePrinting).start(); + new Thread(null, runnablePrinting, + "JTextComponentPrint", 0, false ).start(); printingStatus.showModal(true); } else { printingStatus.showModal(false); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java index 7109005c721..6801a84da5b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java @@ -26,7 +26,6 @@ package javax.swing.text; import java.util.Vector; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * A queue of text layout tasks. @@ -92,7 +91,7 @@ public class LayoutQueue { } } while (work != null); }; - worker = new ManagedLocalsThread(workerRunnable, "text-layout"); + worker = new Thread(null, workerRunnable, "text-layout", 0, false); worker.setPriority(Thread.MIN_PRIORITY); worker.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 85cf2a8d16f..06a8ebf6534 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1522,8 +1522,16 @@ public class CSS implements Serializable { current++; } last = current; - while (current < length && !Character.isWhitespace - (value.charAt(current))) { + int inParentheses = 0; + char ch; + while (current < length && ( + !Character.isWhitespace(ch = value.charAt(current)) + || inParentheses > 0)) { + if (ch == '(') { + inParentheses++; + } else if (ch == ')') { + inParentheses--; + } current++; } if (last != current) { diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java index a778ca6c769..38a4e93415e 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java @@ -52,7 +52,6 @@ import java.security.Permission; import java.security.PermissionCollection; import sun.awt.AppContext; import sun.awt.SunToolkit; -import sun.misc.ManagedLocalsThread; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -858,13 +857,20 @@ public void grab() { * this operation to complete before continuing, wait for the notifyAll() * operation on the syncObject to occur. */ -class AppContextCreator extends ManagedLocalsThread { +class AppContextCreator extends Thread { Object syncObject = new Object(); AppContext appContext = null; volatile boolean created = false; + /** + * Must call the 5-args super-class constructor to erase locals. + */ + private AppContextCreator() { + throw new UnsupportedOperationException("Must erase locals"); + } + AppContextCreator(ThreadGroup group) { - super(group, "AppContextCreator"); + super(group, null, "AppContextCreator", 0, false); } public void run() { diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java index 7ef9e111171..404131827fe 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java @@ -44,7 +44,6 @@ import sun.awt.AppContext; import sun.awt.EmbeddedFrame; import sun.awt.SunToolkit; import sun.awt.util.PerformanceLogger; -import sun.misc.ManagedLocalsThread; import sun.security.util.SecurityConstants; /** @@ -166,7 +165,7 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { ThreadGroup appletGroup = loader.getThreadGroup(); - handler = new ManagedLocalsThread(appletGroup, this, "thread " + nm); + handler = new Thread(appletGroup, this, "thread " + nm, 0, false); // set the context class loader for this thread AccessController.doPrivileged(new PrivilegedAction() { @Override @@ -396,9 +395,8 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { // until the loader thread terminates. // (one way or another). if (loaderThread == null) { - // REMIND: do we want a name? - //System.out.println("------------------- loading applet"); - setLoaderThread(new ManagedLocalsThread(this)); + setLoaderThread(new Thread(null, this, + "AppletLoader", 0, false)); loaderThread.start(); // we get to go to sleep while this runs loaderThread.join(); diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java index b310b277f93..d613fc94341 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java @@ -38,7 +38,6 @@ import java.security.AccessController; import java.security.PrivilegedAction; import sun.awt.SunToolkit; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * A frame to show the applet tag in. @@ -854,7 +853,7 @@ public class AppletViewer extends Frame implements AppletContext, Printable { // final AppletPanel p = panel; - new ManagedLocalsThread(new Runnable() + new Thread(null, new Runnable() { @Override public void run() @@ -867,7 +866,8 @@ public class AppletViewer extends Frame implements AppletContext, Printable { appletSystemExit(); } } - }).start(); + }, + "AppletCloser", 0, false).start(); } /** @@ -890,7 +890,7 @@ public class AppletViewer extends Frame implements AppletContext, Printable { // spawn a new thread to avoid blocking the event queue // when calling appletShutdown. // - new ManagedLocalsThread(new Runnable() + new Thread(null, new Runnable() { @Override public void run() @@ -901,7 +901,8 @@ public class AppletViewer extends Frame implements AppletContext, Printable { } appletSystemExit(); } - }).start(); + }, + "AppletQuit", 0, false).start(); } /** diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java index 1ecef9162ca..8dd14c78444 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java @@ -34,7 +34,6 @@ import java.util.Map; import java.util.Set; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -337,8 +336,8 @@ public final class AWTAutoShutdown implements Runnable { private void activateBlockerThread() { AccessController.doPrivileged((PrivilegedAction) () -> { String name = "AWT-Shutdown"; - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, 0, false); thread.setContextClassLoader(null); thread.setDaemon(false); blockerThread = thread; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java index b4bc32996b2..e966905d2e0 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -46,7 +46,6 @@ import java.lang.ref.SoftReference; import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -598,8 +597,8 @@ public final class AppContext { } public Thread run() { - Thread t = new ManagedLocalsThread(appContext.getThreadGroup(), - runnable, "AppContext Disposer"); + Thread t = new Thread(appContext.getThreadGroup(), + runnable, "AppContext Disposer", 0, false); t.setContextClassLoader(appContext.getContextClassLoader()); t.setPriority(Thread.NORM_PRIORITY + 1); t.setDaemon(true); diff --git a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java index 14221d8a909..f61825d8ddf 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java @@ -55,7 +55,6 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import sun.awt.InputMethodSupport; import sun.awt.SunToolkit; -import sun.misc.ManagedLocalsThread; /** * {@code InputMethodManager} is an abstract class that manages the input @@ -166,7 +165,8 @@ public abstract class InputMethodManager { // to choose from. Otherwise, just keep the instance. if (imm.hasMultipleInputMethods()) { imm.initialize(); - Thread immThread = new ManagedLocalsThread(imm, threadName); + Thread immThread = + new Thread(null, imm, threadName, 0, false); immThread.setDaemon(true); immThread.setPriority(Thread.NORM_PRIORITY + 1); immThread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java index 699c1ea2f43..1123a9f69fd 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -74,10 +73,9 @@ public class ByteBandedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specifies the origin. */ - public ByteBandedRaster(SampleModel sampleModel, - Point origin) { + public ByteBandedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -93,12 +91,13 @@ public class ByteBandedRaster extends SunWritableRaster { * initialized and must be a DataBufferShort compatible with SampleModel. * SampleModel must be of type BandedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x , origin.y, sampleModel.getWidth(), @@ -119,39 +118,33 @@ public class ByteBandedRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, + DataBufferByte dataBuffer, Rectangle aRegion, Point origin, - ByteBandedRaster parent) { - + ByteBandedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteBandedRaster must have" + - "byte DataBuffers"); - } - DataBufferByte dbb = (DataBufferByte)dataBuffer; - if (sampleModel instanceof BandedSampleModel) { BandedSampleModel bsm = (BandedSampleModel)sampleModel; this.scanlineStride = bsm.getScanlineStride(); int bankIndices[] = bsm.getBankIndices(); int bandOffsets[] = bsm.getBandOffsets(); - int dOffsets[] = dbb.getOffsets(); + int dOffsets[] = dataBuffer.getOffsets(); dataOffsets = new int[bankIndices.length]; data = new byte[bankIndices.length][]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; for (int i = 0; i < bankIndices.length; i++) { - data[i] = stealData(dbb, bankIndices[i]); + data[i] = stealData(dataBuffer, bankIndices[i]); dataOffsets[i] = dOffsets[bankIndices[i]] + xOffset + yOffset*scanlineStride + bandOffsets[i]; } @@ -672,7 +665,7 @@ public class ByteBandedRaster extends SunWritableRaster { int deltaY = y0 - y; return new ByteBandedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java index 673e51d8518..f284e3b1fc4 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -94,7 +93,7 @@ public class ByteComponentRaster extends SunWritableRaster { */ public ByteComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -111,12 +110,13 @@ public class ByteComponentRaster extends SunWritableRaster { * SampleModel must be of type SinglePixelPackedSampleModel * or ComponentSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -141,33 +141,28 @@ public class ByteComponentRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ByteComponentRaster parent) { + DataBufferByte dataBuffer, + Rectangle aRegion, + Point origin, + ByteComponentRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteComponentRasters must have " + - "byte DataBuffers"); - } - - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); - if (dbb.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for ByteComponentRasters"+ " must only have 1 bank."); } - int dbOffset = dbb.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel ism = (ComponentSampleModel)sampleModel; @@ -823,7 +818,7 @@ public class ByteComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new ByteComponentRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java index 52f01b30b63..b406fb65211 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -87,7 +86,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { */ public ByteInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -104,12 +103,13 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * SampleModel must be of type SinglePixelPackedSampleModel * or InterleavedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public ByteInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -178,27 +178,22 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. */ public ByteInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ByteInterleavedRaster parent) { + DataBufferByte dataBuffer, + Rectangle aRegion, + Point origin, + ByteInterleavedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("ByteInterleavedRasters must have " + - "byte DataBuffers"); - } - - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); + this.data = stealData(dataBuffer, 0); int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -221,7 +216,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbb.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); dataOffsets[0] += xOffset*pixelStride+yOffset*scanlineStride; } else { throw new RasterFormatException("ByteInterleavedRasters must " + @@ -1259,7 +1254,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { int deltaY = y0 - y; return new ByteInterleavedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java index f9696c17eb8..ac00075c16a 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.MultiPixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.awt.Point; @@ -89,10 +88,9 @@ public class BytePackedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public BytePackedRaster(SampleModel sampleModel, - Point origin) { + public BytePackedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferByte) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -108,12 +106,13 @@ public class BytePackedRaster extends SunWritableRaster { * initialized and must be a DataBufferByte compatible with SampleModel. * SampleModel must be of type MultiPixelPackedSampleModel. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param origin The Point that specifies the origin. */ public BytePackedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferByte dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -137,7 +136,7 @@ public class BytePackedRaster extends SunWritableRaster { * Note that this constructor should generally be called by other * constructors or create methods, it should not be used directly. * @param sampleModel The SampleModel that specifies the layout. - * @param dataBuffer The DataBufferShort that contains the image data. + * @param dataBuffer The DataBufferByte that contains the image data. * @param aRegion The Rectangle that specifies the image area. * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. @@ -146,26 +145,22 @@ public class BytePackedRaster extends SunWritableRaster { * to requirements of this Raster type. */ public BytePackedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, + DataBufferByte dataBuffer, Rectangle aRegion, Point origin, - BytePackedRaster parent){ + BytePackedRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferByte)) { - throw new RasterFormatException("BytePackedRasters must have" + - "byte DataBuffers"); - } - DataBufferByte dbb = (DataBufferByte)dataBuffer; - this.data = stealData(dbb, 0); - if (dbb.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for BytePackedRasters"+ " must only have 1 bank."); } - int dbOffset = dbb.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof MultiPixelPackedSampleModel) { MultiPixelPackedSampleModel mppsm = @@ -1322,7 +1317,7 @@ public class BytePackedRaster extends SunWritableRaster { int deltaY = y0 - y; return new BytePackedRaster(sm, - dataBuffer, + (DataBufferByte) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java index 4ad7eea1682..2aca4285977 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java @@ -27,7 +27,6 @@ package sun.awt.image; import java.util.Vector; import sun.awt.AppContext; -import sun.misc.ManagedLocalsThread; /** * An ImageFetcher is a thread used to fetch ImageFetchable objects. @@ -42,7 +41,7 @@ import sun.misc.ManagedLocalsThread; * @author Jim Graham * @author Fred Ecks */ -class ImageFetcher extends ManagedLocalsThread { +class ImageFetcher extends Thread { static final int HIGH_PRIORITY = 8; static final int LOW_PRIORITY = 3; static final int ANIM_PRIORITY = 2; @@ -51,11 +50,18 @@ class ImageFetcher extends ManagedLocalsThread { // ImageFetchable to be added to the // queue before an ImageFetcher dies + /** + * We must only call the 5 args super() constructor passing + * in "false" to indicate to not inherit locals. + */ + private ImageFetcher() { + throw new UnsupportedOperationException("Must erase locals"); + } /** * Constructor for ImageFetcher -- only called by add() below. */ private ImageFetcher(ThreadGroup threadGroup, int index) { - super(threadGroup, "Image Fetcher " + index); + super(threadGroup, null, "Image Fetcher " + index, 0, false); setDaemon(true); } diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java index cd84986b77f..44ab7253083 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.Rectangle; import java.awt.Point; @@ -107,10 +106,9 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public IntegerComponentRaster(SampleModel sampleModel, - Point origin) { + public IntegerComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferInt) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -130,8 +128,9 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public IntegerComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferInt dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -161,24 +160,21 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public IntegerComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - IntegerComponentRaster parent){ + DataBufferInt dataBuffer, + Rectangle aRegion, + Point origin, + IntegerComponentRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin,parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferInt)) { - throw new RasterFormatException("IntegerComponentRasters must have" + - "integer DataBuffers"); - } - DataBufferInt dbi = (DataBufferInt)dataBuffer; - if (dbi.getNumBanks() != 1) { + + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for IntegerComponentRasters"+ " must only have 1 bank."); } - this.data = stealData(dbi, 0); + this.data = stealData(dataBuffer, 0); if (sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = @@ -197,7 +193,7 @@ public class IntegerComponentRaster extends SunWritableRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbi.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); this.bandOffset = this.dataOffsets[0]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -569,7 +565,7 @@ public class IntegerComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new IntegerComponentRaster(sm, - dataBuffer, + (DataBufferInt) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java index a852080a701..48ec3eed7ad 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.Rectangle; import java.awt.Point; @@ -67,10 +66,9 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public IntegerInterleavedRaster(SampleModel sampleModel, - Point origin) { + public IntegerInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferInt) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -90,8 +88,9 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param origin The Point that specifies the origin. */ public IntegerInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferInt dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -121,19 +120,16 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param parent The parent (if any) of this raster. */ public IntegerInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - IntegerInterleavedRaster parent){ + DataBufferInt dataBuffer, + Rectangle aRegion, + Point origin, + IntegerInterleavedRaster parent) + { super(sampleModel,dataBuffer,aRegion,origin,parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferInt)) { - throw new RasterFormatException("IntegerInterleavedRasters must have" + - "integer DataBuffers"); - } - DataBufferInt dbi = (DataBufferInt)dataBuffer; - this.data = stealData(dbi, 0); + + this.data = stealData(dataBuffer, 0); if (sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = @@ -141,7 +137,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbi.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); this.bandOffset = this.dataOffsets[0]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; @@ -481,7 +477,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { int deltaY = y0 - y; return new IntegerInterleavedRaster(sm, - dataBuffer, + (DataBufferInt) dataBuffer, new Rectangle(x0,y0,width,height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java index fd5c610504d..6222c61b5e9 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.awt.image.WritableRaster; import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -72,10 +71,9 @@ public class ShortBandedRaster extends SunWritableRaster { * @param sampleModel The SampleModel that specifies the layout. * @param origin The Point that specified the origin. */ - public ShortBandedRaster(SampleModel sampleModel, - Point origin) { + public ShortBandedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -95,8 +93,9 @@ public class ShortBandedRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public ShortBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -123,32 +122,27 @@ public class ShortBandedRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public ShortBandedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortBandedRaster parent) { - + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortBandedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if (!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortBandedRaster must have " + - "ushort DataBuffers"); - } - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; if (sampleModel instanceof BandedSampleModel) { BandedSampleModel bsm = (BandedSampleModel)sampleModel; this.scanlineStride = bsm.getScanlineStride(); int bankIndices[] = bsm.getBankIndices(); int bandOffsets[] = bsm.getBandOffsets(); - int dOffsets[] = dbus.getOffsets(); + int dOffsets[] = dataBuffer.getOffsets(); dataOffsets = new int[bankIndices.length]; data = new short[bankIndices.length][]; int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; for (int i = 0; i < bankIndices.length; i++) { - data[i] = stealData(dbus, bankIndices[i]); + data[i] = stealData(dataBuffer, bankIndices[i]); dataOffsets[i] = dOffsets[bankIndices[i]] + xOffset + yOffset*scanlineStride + bandOffsets[i]; } @@ -670,7 +664,7 @@ public class ShortBandedRaster extends SunWritableRaster { int deltaY = y0 - y; return new ShortBandedRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java index 76ab7d75ce4..79016e9df5a 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -94,7 +93,7 @@ public class ShortComponentRaster extends SunWritableRaster { */ public ShortComponentRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -115,8 +114,9 @@ public class ShortComponentRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. */ public ShortComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -146,28 +146,22 @@ public class ShortComponentRaster extends SunWritableRaster { * @param parent The parent (if any) of this raster. */ public ShortComponentRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortComponentRaster parent) { - + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortComponentRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if(!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortComponentRasters must have "+ - "short DataBuffers"); - } - - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; - this.data = stealData(dbus, 0); - if (dbus.getNumBanks() != 1) { + this.data = stealData(dataBuffer, 0); + if (dataBuffer.getNumBanks() != 1) { throw new RasterFormatException("DataBuffer for ShortComponentRasters"+ " must only have 1 bank."); } - int dbOffset = dbus.getOffset(); + int dbOffset = dataBuffer.getOffset(); if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel csm = (ComponentSampleModel)sampleModel; @@ -758,7 +752,7 @@ public class ShortComponentRaster extends SunWritableRaster { int deltaY = y0 - y; return new ShortComponentRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java index 05310891fe5..7a1644b6275 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.awt.image.SampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferUShort; import java.awt.Rectangle; import java.awt.Point; @@ -71,7 +70,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { */ public ShortInterleavedRaster(SampleModel sampleModel, Point origin) { this(sampleModel, - sampleModel.createDataBuffer(), + (DataBufferUShort) sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, sampleModel.getWidth(), @@ -92,8 +91,9 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param origin The Point that specifies the origin. */ public ShortInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Point origin) { + DataBufferUShort dataBuffer, + Point origin) + { this(sampleModel, dataBuffer, new Rectangle(origin.x, @@ -123,22 +123,17 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param parent The parent (if any) of this raster. */ public ShortInterleavedRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point origin, - ShortInterleavedRaster parent) { + DataBufferUShort dataBuffer, + Rectangle aRegion, + Point origin, + ShortInterleavedRaster parent) + { super(sampleModel, dataBuffer, aRegion, origin, parent); this.maxX = minX + width; this.maxY = minY + height; - if(!(dataBuffer instanceof DataBufferUShort)) { - throw new RasterFormatException("ShortInterleavedRasters must "+ - "have ushort DataBuffers"); - } - - DataBufferUShort dbus = (DataBufferUShort)dataBuffer; - this.data = stealData(dbus, 0); + this.data = stealData(dataBuffer, 0); // REMIND: need case for interleaved ComponentSampleModel if ((sampleModel instanceof PixelInterleavedSampleModel) || @@ -160,7 +155,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { this.scanlineStride = sppsm.getScanlineStride(); this.pixelStride = 1; this.dataOffsets = new int[1]; - this.dataOffsets[0] = dbus.getOffset(); + this.dataOffsets[0] = dataBuffer.getOffset(); int xOffset = aRegion.x - origin.x; int yOffset = aRegion.y - origin.y; dataOffsets[0] += xOffset+yOffset*scanlineStride; @@ -730,7 +725,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { int deltaY = y0 - y; return new ShortInterleavedRaster(sm, - dataBuffer, + (DataBufferUShort) dataBuffer, new Rectangle(x0, y0, width, height), new Point(sampleModelTranslateX+deltaX, sampleModelTranslateY+deltaY), diff --git a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java index 0ce75a7b235..2e239528c71 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java +++ b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java @@ -36,7 +36,6 @@ import java.util.concurrent.TimeUnit; import sun.awt.AppContext; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; public class CreatedFontTracker { @@ -122,8 +121,8 @@ public class CreatedFontTracker { * Make its parent the top-level thread group. */ ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - t = new ManagedLocalsThread(rootTG, - TempFileDeletionHook::runHooks); + t = new Thread(rootTG, TempFileDeletionHook::runHooks, + "TempFontFileDeleter", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java b/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java index 3aec0a72d89..bfbd4559448 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java +++ b/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java @@ -182,6 +182,25 @@ public final class FontUtilities { return FontAccess.getFontAccess().getFont2D(font); } + /** + * Return true if there any characters which would trigger layout. + * This method considers supplementary characters to be simple, + * since we do not presently invoke layout on any code points in + * outside the BMP. + */ + public static boolean isComplexScript(char [] chs, int start, int limit) { + + for (int i = start; i < limit; i++) { + if (chs[i] < MIN_LAYOUT_CHARCODE) { + continue; + } + else if (isComplexCharCode(chs[i])) { + return true; + } + } + return false; + } + /** * If there is anything in the text which triggers a case * where char->glyph does not map 1:1 in straightforward diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java index 67bb3fd383a..19200c8282b 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -55,7 +55,6 @@ import sun.awt.FontConfiguration; import sun.awt.SunToolkit; import sun.awt.util.ThreadGroupUtils; import sun.java2d.FontSupport; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -2513,8 +2512,8 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { }; AccessController.doPrivileged((PrivilegedAction) () -> { ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - fileCloser = new ManagedLocalsThread(rootTG, - fileCloserRunnable); + fileCloser = new Thread(rootTG, fileCloserRunnable, + "FileCloser", 0, false); fileCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(fileCloser); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java index 01336443bb1..e63da023936 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -26,7 +26,6 @@ package sun.java2d; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; @@ -85,7 +84,7 @@ public class Disposer implements Runnable { AccessController.doPrivileged((PrivilegedAction) () -> { String name = "Java2D Disposer"; ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - Thread t = new ManagedLocalsThread(rootTG, disposerInstance, name); + Thread t = new Thread(rootTG, disposerInstance, name, 0, false); t.setContextClassLoader(null); t.setDaemon(true); t.setPriority(Thread.MAX_PRIORITY); diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java index 38bbaeb5178..a71978a10ac 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java @@ -48,7 +48,6 @@ import java.io.FileNotFoundException; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; /** @@ -420,8 +419,9 @@ public abstract class GraphicsPrimitive { public static void setShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { TraceReporter t = new TraceReporter(); - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), t); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), t, + "TraceReporter", 0, false); thread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(thread); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java index 27abcbd86f8..5a843792f37 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java @@ -28,7 +28,6 @@ package sun.java2d.opengl; import sun.awt.util.ThreadGroupUtils; import sun.java2d.pipe.RenderBuffer; import sun.java2d.pipe.RenderQueue; -import sun.misc.ManagedLocalsThread; import static sun.java2d.pipe.BufferedOpCodes.*; import java.security.AccessController; @@ -161,7 +160,8 @@ public class OGLRenderQueue extends RenderQueue { public QueueFlusher() { String name = "Java2D Queue Flusher"; - thread = new ManagedLocalsThread(ThreadGroupUtils.getRootThreadGroup(), this, name); + thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), + this, name, 0, false); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 0d3df28921c..b62c4eb1298 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -71,7 +71,6 @@ import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; -import sun.misc.ManagedLocalsThread; import sun.print.SunPageSelection; import sun.print.SunMinMaxPage; @@ -483,8 +482,30 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { pageFormat.setOrientation(PageFormat.LANDSCAPE); } else { pageFormat.setOrientation(PageFormat.PORTRAIT); - } + } + PageRanges pageRangesAttr + = (PageRanges) attributes.get(PageRanges.class); + if (pageRangesAttr != null) { + // Get the PageRanges from print dialog. + int[][] range = pageRangesAttr.getMembers(); + + int prevFromPage = this.jobAttributes.getFromPage(); + int prevToPage = this.jobAttributes.getToPage(); + + int currFromPage = range[0][0]; + int currToPage = range[range.length - 1][1]; + + // if from < to update fromPage first followed by toPage + // else update toPage first followed by fromPage + if (currFromPage < prevToPage) { + this.jobAttributes.setFromPage(currFromPage); + this.jobAttributes.setToPage(currToPage); + } else { + this.jobAttributes.setToPage(currToPage); + this.jobAttributes.setFromPage(currFromPage); + } + } printerJob.setPrintable(this, pageFormat); } @@ -987,7 +1008,8 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { } private void startPrinterJobThread() { - printerJobThread = new ManagedLocalsThread(this, "printerJobThread"); + printerJobThread = + new Thread(null, this, "printerJobThread", 0, false); printerJobThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java index 573684a6048..8df17defd05 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java +++ b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.util.Vector; import javax.print.PrintService; @@ -42,15 +40,19 @@ import javax.print.event.PrintServiceAttributeListener; * to obtain the state of the attributes and notifies the listeners of * any changes. */ -class ServiceNotifier extends ManagedLocalsThread { +class ServiceNotifier extends Thread { private PrintService service; private Vector listeners; private boolean stop = false; private PrintServiceAttributeSet lastSet; + /* + * If adding any other constructors, always call the 5-args + * super-class constructor passing "false" for inherit-locals. + */ ServiceNotifier(PrintService service) { - super(service.getName() + " notifier"); + super(null, null, service.getName() + " notifier", 0, false); this.service = service; listeners = new Vector<>(); try { @@ -70,7 +72,7 @@ class ServiceNotifier extends ManagedLocalsThread { } } - void removeListener(PrintServiceAttributeListener listener) { + void removeListener(PrintServiceAttributeListener listener) { synchronized (this) { if (listener == null || listeners == null) { return; diff --git a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java index 8e4c2159679..587aceb454f 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java +++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -645,16 +645,7 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { // StateInfo match, otherwise a StateInfo with // SELECTED | ENABLED would match ENABLED, which we // don't want. - - // This comes from BigInteger.bitCnt - int bitCount = oState; - bitCount -= (0xaaaaaaaa & bitCount) >>> 1; - bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & - 0x33333333); - bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; - bitCount += bitCount >>> 8; - bitCount += bitCount >>> 16; - bitCount = bitCount & 0xff; + int bitCount = Integer.bitCount(oState); if (bitCount > bestCount) { bestIndex = counter; bestCount = bitCount; @@ -882,21 +873,6 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { return state; } - /** - * Returns the number of states that are similar between the - * ComponentState this StateInfo represents and val. - */ - private int getMatchCount(int val) { - // This comes from BigInteger.bitCnt - val &= state; - val -= (0xaaaaaaaa & val) >>> 1; - val = (val & 0x33333333) + ((val >>> 2) & 0x33333333); - val = val + (val >>> 4) & 0x0f0f0f0f; - val += val >>> 8; - val += val >>> 16; - return val & 0xff; - } - /** * Creates and returns a copy of this StateInfo. * diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp index df4df194fcf..7ea3032fe97 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.cpp @@ -45,9 +45,12 @@ const le_uint16 DeviceTable::fieldBits[] = { 2, 4, 8}; le_int16 DeviceTable::getAdjustment(const LEReferenceTo&base, le_uint16 ppem, LEErrorCode &success) const { + le_int16 result = 0; + if (LE_FAILURE(success)) { + return result; + } le_uint16 start = SWAPW(startSize); le_uint16 format = SWAPW(deltaFormat) - 1; - le_int16 result = 0; if (ppem >= start && ppem <= SWAPW(endSize) && format < FORMAT_COUNT) { le_uint16 sizeIndex = ppem - start; diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp index 5a94563fa5b..76131fd2193 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc.cpp @@ -71,6 +71,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp { LEErrorCode success = LE_NO_ERROR; const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + if (LE_FAILURE(success)) { + currGlyph++; + return 0; + } ByteOffset newState = SWAPW(entry->newStateOffset); le_uint16 flags = SWAPW(entry->flags); @@ -91,6 +95,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp if (actionOffset != 0) { LEReferenceTo ap(stHeader, success, actionOffset); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } LigatureActionEntry action; le_int32 offset, i = 0, j = 0; le_int32 stack[nComponents]; @@ -101,6 +109,10 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp if (j++ > 0) { ap.addObject(success); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } } action = SWAPL(*ap.getAlias()); @@ -124,9 +136,17 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp return newState; // get out! bad font } i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success)); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } if (action & (lafLast | lafStore)) { LEReferenceTo ligatureOffset(stHeader, success, i); + if (LE_FAILURE(success)) { + currGlyph++; + return newState; + } TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias()); glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp index 77e907322ed..1a4709e1d81 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LigatureSubstProc2.cpp @@ -95,6 +95,10 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp if (actionOffset != 0) { LEReferenceTo ap(stHeader, success, ligActionOffset); // byte offset + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } ap.addObject(ligActionIndex, success); LEReferenceToArrayOf ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); LigatureActionEntry action; @@ -104,8 +108,8 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp LEReferenceToArrayOf componentTable(stHeader, success, componentOffset, LE_UNBOUNDED_ARRAY); if(LE_FAILURE(success)) { - currGlyph+= dir; - return nextStateIndex; // get out! bad font + currGlyph+= dir; + return nextStateIndex; // get out! bad font } do { @@ -114,6 +118,10 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp if (j++ > 0) { ap.addObject(success); } + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } action = SWAPL(*ap.getAlias()); @@ -129,9 +137,17 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp return nextStateIndex; // get out! bad font } i += SWAPW(componentTable(LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask)),success)); + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } if (action & (lafLast | lafStore)) { TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success)); + if (LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; + } glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); if(mm==nComponents) { LE_DEBUG_BAD_FONT("exceeded nComponents"); diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp index 9aa097a6f52..ab74b239d76 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/StateTableProcessor2.cpp @@ -60,6 +60,7 @@ StateTableProcessor2::StateTableProcessor2(const LEReferenceToentryTableOffset); classTable = LEReferenceTo(stHeader, success, classTableOffset); + if (LE_FAILURE(success)) return; format = SWAPW(classTable->format); stateArray = LEReferenceToArrayOf(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java index d6ef132fede..fb7688f9b8e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java @@ -29,7 +29,6 @@ import java.awt.peer.FileDialogPeer; import java.io.File; import java.io.FilenameFilter; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; /** * FileDialogPeer for the GtkFileChooser. @@ -120,7 +119,7 @@ final class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { standaloneWindow = 0; fd.setVisible(false); }; - new ManagedLocalsThread(task).start(); + new Thread(null, task, "ShowDialog", 0, false).start(); } else { quit(); fd.setVisible(false); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java index a7870a95b6a..62658c7e92e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java @@ -29,7 +29,6 @@ import java.awt.*; import java.awt.event.*; import java.awt.peer.TrayIconPeer; import sun.awt.*; -import sun.misc.ManagedLocalsThread; import java.awt.image.*; import java.text.BreakIterator; @@ -452,7 +451,7 @@ public abstract class InfoWindow extends Window { final Thread thread; Displayer() { - this.thread = new ManagedLocalsThread(this); + this.thread = new Thread(null, this, "Displayer", 0, false); this.thread.setDaemon(true); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java index 85481f55c46..bb74478d299 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java @@ -1087,7 +1087,7 @@ public abstract class XBaseMenuWindow extends XWindow { } } else { //Invoke action event - item.action(mouseEvent.getWhen()); + item.action(mouseEvent.getWhen(), mouseEvent.getModifiers()); ungrabInput(); } } else { @@ -1200,7 +1200,7 @@ public abstract class XBaseMenuWindow extends XWindow { if (citem instanceof XMenuPeer) { cwnd.selectItem(citem, true); } else if (citem != null) { - citem.action(event.getWhen()); + citem.action(event.getWhen(), event.getModifiers()); ungrabInput(); } break; diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java index aa1c85d7908..d4e578961be 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java @@ -323,11 +323,11 @@ public class XMenuItemPeer implements MenuItemPeer { * on menu item. * @param when the timestamp of action event */ - void action(long when) { + void action(long when, int modifiers) { if (!isSeparator() && isTargetItemEnabled()) { XWindow.postEventStatic(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, getTargetActionCommand(), when, - 0)); + modifiers)); } } /************************************************ diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java index bfb964c9b7c..fa23ae0b66e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java @@ -29,7 +29,6 @@ import java.awt.PopupMenu; import java.awt.Taskbar.Feature; import java.awt.peer.TaskbarPeer; import java.awt.event.ActionEvent; -import sun.misc.ManagedLocalsThread; import java.security.AccessController; import sun.security.action.GetPropertyAction; @@ -48,10 +47,8 @@ final class XTaskbarPeer implements TaskbarPeer { new GetPropertyAction("java.desktop.appName", "")); nativeLibraryLoaded = init(dname); if (nativeLibraryLoaded) { - ManagedLocalsThread t - = new ManagedLocalsThread(() -> { - runloop(); - }); + Thread t = new Thread(null, () -> { runloop(); }, + "TaskBar", 0, false); t.setDaemon(true); t.start(); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index f1904e07626..aa460f9f636 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -284,8 +284,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } }; String name = "XToolkt-Shutdown-Thread"; - Thread shutdownThread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), r, name); + Thread shutdownThread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), r, name, 0, false); shutdownThread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdownThread); return null; @@ -332,8 +332,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable { toolkitThread = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "AWT-XAWT"; - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, + 0, false); thread.setContextClassLoader(null); thread.setPriority(Thread.NORM_PRIORITY + 1); thread.setDaemon(true); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index 9f35f172014..14ff9a5d45b 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -44,7 +44,6 @@ import sun.java2d.loops.SurfaceType; import sun.awt.util.ThreadGroupUtils; import sun.java2d.SunGraphicsEnvironment; -import sun.misc.ManagedLocalsThread; /** * This is an implementation of a GraphicsDevice object for a single @@ -442,8 +441,8 @@ public final class X11GraphicsDevice extends GraphicsDevice } }; String name = "Display-Change-Shutdown-Thread-" + screen; - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), r, name); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), r, name, 0, false); t.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(t); return null; diff --git a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java index 7cf6bf0aced..4da098d504e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; @@ -213,7 +211,8 @@ public class PrintServiceLookupProvider extends PrintServiceLookup public PrintServiceLookupProvider() { // start the printer listener thread if (pollServices) { - Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); + Thread thr = new Thread(null, new PrinterChangeListener(), + "PrinterListener", 0, false); thr.setDaemon(true); thr.start(); IPPPrintService.debug_println(debugPrefix+"polling turned on"); diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c index 7d2b8b0dbd0..8b64034a295 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1877,31 +1877,34 @@ Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode AWT_LOCK(); - config = awt_XRRGetScreenInfo(awt_display, - RootWindow(awt_display, screen)); - if (config != NULL) { - Rotation rotation; - short curRate; - SizeID curSizeIndex; - XRRScreenSize *sizes; - int nsizes; + if (screen < ScreenCount(awt_display)) { - curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation); - sizes = awt_XRRConfigSizes(config, &nsizes); - curRate = awt_XRRConfigCurrentRate(config); + config = awt_XRRGetScreenInfo(awt_display, + RootWindow(awt_display, screen)); + if (config != NULL) { + Rotation rotation; + short curRate; + SizeID curSizeIndex; + XRRScreenSize *sizes; + int nsizes; - if ((sizes != NULL) && - (curSizeIndex < nsizes)) - { - XRRScreenSize curSize = sizes[curSizeIndex]; - displayMode = X11GD_CreateDisplayMode(env, - curSize.width, - curSize.height, - BIT_DEPTH_MULTI, - curRate); + curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation); + sizes = awt_XRRConfigSizes(config, &nsizes); + curRate = awt_XRRConfigCurrentRate(config); + + if ((sizes != NULL) && + (curSizeIndex < nsizes)) + { + XRRScreenSize curSize = sizes[curSizeIndex]; + displayMode = X11GD_CreateDisplayMode(env, + curSize.width, + curSize.height, + BIT_DEPTH_MULTI, + curRate); + } + + awt_XRRFreeScreenConfigInfo(config); } - - awt_XRRFreeScreenConfigInfo(config); } AWT_FLUSH_UNLOCK(); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index b01d04443df..1e20c3582f7 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -41,7 +41,6 @@ import java.util.stream.Stream; import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; import sun.awt.util.ThreadGroupUtils; -import sun.misc.ManagedLocalsThread; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -524,8 +523,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { return null; }); AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownHook); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownHook, + "ShellFolder", 0, false); Runtime.getRuntime().addShutdownHook(t); return null; }); @@ -548,8 +548,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { * which will not get GCed before VM exit. * Make its parent the top-level thread group. */ - Thread thread = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), comRun, name); + Thread thread = new Thread( + ThreadGroupUtils.getRootThreadGroup(), comRun, name, + 0, false); thread.setDaemon(true); return thread; }); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java index e75f3b9f486..383254b815a 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java @@ -36,7 +36,6 @@ import java.util.MissingResourceException; import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @@ -98,7 +97,7 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @Override public void show() { - new ManagedLocalsThread(this::_show).start(); + new Thread(null, this::_show, "FileDialog", 0, false).start(); } @Override diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java index 10d99948b10..5e7303b1af1 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java @@ -25,8 +25,6 @@ package sun.awt.windows; -import sun.misc.ManagedLocalsThread; - final class WPageDialogPeer extends WPrintDialogPeer { WPageDialogPeer(WPageDialog target) { @@ -53,6 +51,6 @@ final class WPageDialogPeer extends WPrintDialogPeer { } ((WPrintDialog)target).setVisible(false); }; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "PageDialog", 0, false).start(); } } diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java index 99c727493d1..a80e7dd6d13 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java @@ -32,7 +32,6 @@ import java.awt.dnd.DropTarget; import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; -import sun.misc.ManagedLocalsThread; class WPrintDialogPeer extends WWindowPeer implements DialogPeer { @@ -78,7 +77,7 @@ class WPrintDialogPeer extends WWindowPeer implements DialogPeer { } ((WPrintDialog)target).setVisible(false); }; - new ManagedLocalsThread(runnable).start(); + new Thread(null, runnable, "PrintDialog", 0, false).start(); } synchronized void setHWnd(long hwnd) { diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index 8fb6f386474..097f68dac31 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -52,7 +52,6 @@ import sun.awt.datatransfer.DataTransferer; import sun.java2d.d3d.D3DRenderQueue; import sun.java2d.opengl.OGLRenderQueue; -import sun.misc.ManagedLocalsThread; import sun.print.PrintJob2D; import java.awt.dnd.DragSource; @@ -256,7 +255,7 @@ public final class WToolkit extends SunToolkit implements Runnable { (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); if (!startToolkitThread(this, rootTG)) { String name = "AWT-Windows"; - Thread toolkitThread = new ManagedLocalsThread(rootTG, this, name); + Thread toolkitThread = new Thread(rootTG, this, name, 0, false); toolkitThread.setDaemon(true); toolkitThread.start(); } @@ -283,8 +282,9 @@ public final class WToolkit extends SunToolkit implements Runnable { private void registerShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this::shutdown); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this::shutdown, + "ToolkitShutdown", 0, false); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); return null; diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java index 4b112b9fcc7..62be1e84f1b 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java @@ -49,7 +49,6 @@ import sun.java2d.SurfaceData; import sun.java2d.windows.GDIWindowSurfaceData; import sun.java2d.d3d.D3DSurfaceData.D3DWindowSurfaceData; import sun.java2d.windows.WindowsFlags; -import sun.misc.ManagedLocalsThread; /** * This class handles rendering to the screen with the D3D pipeline. @@ -99,8 +98,9 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager done = true; wakeUpUpdateThread(); }; - Thread shutdown = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + Thread shutdown = new Thread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable, + "ScreenUpdater", 0, false); shutdown.setContextClassLoader(null); try { Runtime.getRuntime().addShutdownHook(shutdown); @@ -348,8 +348,9 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager if (screenUpdater == null) { screenUpdater = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "D3D Screen Updater"; - Thread t = new ManagedLocalsThread( - ThreadGroupUtils.getRootThreadGroup(), this, name); + Thread t = new Thread( + ThreadGroupUtils.getRootThreadGroup(), this, name, + 0, false); // REMIND: should it be higher? t.setPriority(Thread.NORM_PRIORITY + 2); t.setDaemon(true); diff --git a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index e9139b46525..347336bcb7a 100644 --- a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -25,8 +25,6 @@ package sun.print; -import sun.misc.ManagedLocalsThread; - import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -99,7 +97,8 @@ public class PrintServiceLookupProvider extends PrintServiceLookup { return; } // start the printer listener thread - Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); + Thread thr = new Thread(null, new PrinterChangeListener(), + "PrinterListener", 0, false); thr.setDaemon(true); thr.start(); } /* else condition ought to never happen! */ diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp index f0550a9aa5d..e76582bf363 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp @@ -187,7 +187,7 @@ void AwtButton::NotifyListeners() { DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } MsgRouting diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index d5224df0b62..746b1114488 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -2587,6 +2588,27 @@ jint AwtComponent::GetShiftKeyLocation(UINT vkey, UINT flags) return java_awt_event_KeyEvent_KEY_LOCATION_LEFT; } +/* Returns Java ActionEvent modifieres. + * When creating ActionEvent, modifiers provided by ActionEvent + * class should be set. + */ +jint +AwtComponent::GetActionModifiers() +{ + jint modifiers = GetJavaModifiers(); + + if (modifiers & java_awt_event_InputEvent_CTRL_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_CTRL_MASK; + } + if (modifiers & java_awt_event_InputEvent_SHIFT_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_SHIFT_MASK; + } + if (modifiers & java_awt_event_InputEvent_ALT_DOWN_MASK) { + modifiers |= java_awt_event_ActionEvent_ALT_MASK; + } + return modifiers; +} + /* Returns Java extended InputEvent modifieres. * Since ::GetKeyState returns current state and Java modifiers represent * state before event, modifier on changed key are inverted. diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 83c6d8b8a4e..135ac39b874 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -438,6 +438,7 @@ public: static void InitDynamicKeyMapTable(); static void BuildDynamicKeyMapTable(); static jint GetJavaModifiers(); + static jint GetActionModifiers(); static jint GetButton(int mouseButton); static UINT GetButtonMK(int mouseButton); static UINT WindowsKeyToJavaKey(UINT windowsKey, UINT modifiers, UINT character, BOOL isDeadKey); diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp index 39016b9ab59..4c32a472996 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.cpp @@ -536,7 +536,7 @@ AwtList::WmNotify(UINT notifyCode) else if (notifyCode == LBN_DBLCLK) { DoCallback("handleAction", "(IJI)V", nCurrentSelection, ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } } } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h index 73effc3a56e..3450089b509 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_List.h @@ -56,6 +56,7 @@ public: } INLINE void Deselect(int pos) { if (isMultiSelect) { + SendListMessage(LB_SETCARETINDEX, pos, FALSE); SendListMessage(LB_SETSEL, FALSE, pos); } else { diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp index ba0488187c5..80fc977e00d 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp @@ -667,7 +667,7 @@ void AwtMenuItem::DoCommand() DoCallback("handleAction", "(Z)V", ((nState & MF_CHECKED) == 0)); } else { DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0), - (jint)AwtComponent::GetJavaModifiers()); + (jint)AwtComponent::GetActionModifiers()); } } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp index ef376f31a3b..56280a583ac 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp @@ -409,7 +409,7 @@ MsgRouting AwtTrayIcon::WmBalloonUserClick(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } return mrConsume; } @@ -425,7 +425,7 @@ MsgRouting AwtTrayIcon::WmKeySelect(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } lastKeySelectTime = now; @@ -442,7 +442,7 @@ MsgRouting AwtTrayIcon::WmSelect(UINT flags, int x, int y) MSG msg; AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0), - AwtComponent::GetJavaModifiers(), &msg); + AwtComponent::GetActionModifiers(), &msg); } return mrConsume; } diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java new file mode 100644 index 00000000000..de60d58f6ac --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BinaryRepresentationWriter.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +interface BinaryRepresentationWriter { + + boolean write(HeaderTable table, ByteBuffer destination); + + BinaryRepresentationWriter reset(); +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java new file mode 100644 index 00000000000..1c064f627f5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/BulkSizeUpdateWriter.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Iterator; + +import static java.util.Objects.requireNonNull; + +final class BulkSizeUpdateWriter implements BinaryRepresentationWriter { + + private final SizeUpdateWriter writer = new SizeUpdateWriter(); + private Iterator maxSizes; + private boolean writing; + private boolean configured; + + BulkSizeUpdateWriter maxHeaderTableSizes(Iterable sizes) { + if (configured) { + throw new IllegalStateException("Already configured"); + } + requireNonNull(sizes, "sizes"); + maxSizes = sizes.iterator(); + configured = true; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!configured) { + throw new IllegalStateException("Configure first"); + } + while (true) { + if (writing) { + if (!writer.write(table, destination)) { + return false; + } + writing = false; + } else if (maxSizes.hasNext()) { + writing = true; + writer.reset(); + writer.maxHeaderTableSize(maxSizes.next()); + } else { + configured = false; + return true; + } + } + } + + @Override + public BulkSizeUpdateWriter reset() { + maxSizes = null; + writing = false; + configured = false; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java new file mode 100644 index 00000000000..afff906424a --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Decoder.java @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.ProtocolException; +import java.nio.ByteBuffer; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * Decodes headers from their binary representation. + * + *

Typical lifecycle looks like this: + * + *

{@link #Decoder(int) new Decoder} + * ({@link #setMaxCapacity(int) setMaxCapacity}? + * {@link #decode(ByteBuffer, boolean, DecodingCallback) decode})* + * + * @apiNote + * + *

The design intentions behind Decoder were to facilitate flexible and + * incremental style of processing. + * + *

{@code Decoder} does not require a complete header block in a single + * {@code ByteBuffer}. The header block can be spread across many buffers of any + * size and decoded one-by-one the way it makes most sense for the user. This + * way also allows not to limit the size of the header block. + * + *

Headers are delivered to the {@linkplain DecodingCallback callback} as + * soon as they become decoded. Using the callback also gives the user a freedom + * to decide how headers are processed. The callback does not limit the number + * of headers decoded during single decoding operation. + * + * @since 9 + */ +public final class Decoder { + + private static final State[] states = new State[256]; + + static { + // To be able to do a quick lookup, each of 256 possibilities are mapped + // to corresponding states. + // + // We can safely do this since patterns 1, 01, 001, 0001, 0000 are + // Huffman prefixes and therefore are inherently not ambiguous. + // + // I do it mainly for better debugging (to not go each time step by step + // through if...else tree). As for performance win for the decoding, I + // believe is negligible. + for (int i = 0; i < states.length; i++) { + if ((i & 0b1000_0000) == 0b1000_0000) { + states[i] = State.INDEXED; + } else if ((i & 0b1100_0000) == 0b0100_0000) { + states[i] = State.LITERAL_WITH_INDEXING; + } else if ((i & 0b1110_0000) == 0b0010_0000) { + states[i] = State.SIZE_UPDATE; + } else if ((i & 0b1111_0000) == 0b0001_0000) { + states[i] = State.LITERAL_NEVER_INDEXED; + } else if ((i & 0b1111_0000) == 0b0000_0000) { + states[i] = State.LITERAL; + } else { + throw new InternalError(String.valueOf(i)); + } + } + } + + private final HeaderTable table; + + private State state = State.READY; + private final IntegerReader integerReader; + private final StringReader stringReader; + private final StringBuilder name; + private final StringBuilder value; + private int intValue; + private boolean firstValueRead; + private boolean firstValueIndex; + private boolean nameHuffmanEncoded; + private boolean valueHuffmanEncoded; + private int capacity; + + /** + * Constructs a {@code Decoder} with the specified initial capacity of the + * header table. + * + *

The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public Decoder(int capacity) { + setMaxCapacity(capacity); + table = new HeaderTable(capacity); + integerReader = new IntegerReader(); + stringReader = new StringReader(); + name = new StringBuilder(512); + value = new StringBuilder(1024); + } + + /** + * Sets a maximum capacity of the header table. + * + *

The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + */ + public void setMaxCapacity(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("capacity >= 0: " + capacity); + } + // FIXME: await capacity update if less than what was prior to it + this.capacity = capacity; + } + + /** + * Decodes a header block from the given buffer to the given callback. + * + *

Suppose a header block is represented by a sequence of {@code + * ByteBuffer}s in the form of {@code Iterator}. And the + * consumer of decoded headers is represented by the callback. Then to + * decode the header block, the following approach might be used: + * + *

{@code
+     * while (buffers.hasNext()) {
+     *     ByteBuffer input = buffers.next();
+     *     decoder.decode(input, callback, !buffers.hasNext());
+     * }
+     * }
+ * + *

The decoder reads as much as possible of the header block from the + * given buffer, starting at the buffer's position, and increments its + * position to reflect the bytes read. The buffer's mark and limit will not + * be modified. + * + *

Once the method is invoked with {@code endOfHeaderBlock == true}, the + * current header block is deemed ended, and inconsistencies, if any, are + * reported immediately by throwing an {@code UncheckedIOException}. + * + *

Each callback method is called only after the implementation has + * processed the corresponding bytes. If the bytes revealed a decoding + * error, the callback method is not called. + * + *

In addition to exceptions thrown directly by the method, any + * exceptions thrown from the {@code callback} will bubble up. + * + * @apiNote The method asks for {@code endOfHeaderBlock} flag instead of + * returning it for two reasons. The first one is that the user of the + * decoder always knows which chunk is the last. The second one is to throw + * the most detailed exception possible, which might be useful for + * diagnosing issues. + * + * @implNote This implementation is not atomic in respect to decoding + * errors. In other words, if the decoding operation has thrown a decoding + * error, the decoder is no longer usable. + * + * @param headerBlock + * the chunk of the header block, may be empty + * @param endOfHeaderBlock + * true if the chunk is the final (or the only one) in the sequence + * + * @param consumer + * the callback + * @throws UncheckedIOException + * in case of a decoding error + * @throws NullPointerException + * if either headerBlock or consumer are null + */ + public void decode(ByteBuffer headerBlock, boolean endOfHeaderBlock, + DecodingCallback consumer) { + requireNonNull(headerBlock, "headerBlock"); + requireNonNull(consumer, "consumer"); + while (headerBlock.hasRemaining()) { + proceed(headerBlock, consumer); + } + if (endOfHeaderBlock && state != State.READY) { + throw new UncheckedIOException( + new ProtocolException("Unexpected end of header block")); + } + } + + private void proceed(ByteBuffer input, DecodingCallback action) { + switch (state) { + case READY: + resumeReady(input); + break; + case INDEXED: + resumeIndexed(input, action); + break; + case LITERAL: + resumeLiteral(input, action); + break; + case LITERAL_WITH_INDEXING: + resumeLiteralWithIndexing(input, action); + break; + case LITERAL_NEVER_INDEXED: + resumeLiteralNeverIndexed(input, action); + break; + case SIZE_UPDATE: + resumeSizeUpdate(input, action); + break; + default: + throw new InternalError( + "Unexpected decoder state: " + String.valueOf(state)); + } + } + + private void resumeReady(ByteBuffer input) { + int b = input.get(input.position()) & 0xff; // absolute read + State s = states[b]; + switch (s) { + case INDEXED: + integerReader.configure(7); + state = State.INDEXED; + firstValueIndex = true; + break; + case LITERAL: + state = State.LITERAL; + firstValueIndex = (b & 0b0000_1111) != 0; + if (firstValueIndex) { + integerReader.configure(4); + } + break; + case LITERAL_WITH_INDEXING: + state = State.LITERAL_WITH_INDEXING; + firstValueIndex = (b & 0b0011_1111) != 0; + if (firstValueIndex) { + integerReader.configure(6); + } + break; + case LITERAL_NEVER_INDEXED: + state = State.LITERAL_NEVER_INDEXED; + firstValueIndex = (b & 0b0000_1111) != 0; + if (firstValueIndex) { + integerReader.configure(4); + } + break; + case SIZE_UPDATE: + integerReader.configure(5); + state = State.SIZE_UPDATE; + firstValueIndex = true; + break; + default: + throw new InternalError(String.valueOf(s)); + } + if (!firstValueIndex) { + input.get(); // advance, next stop: "String Literal" + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 1 | Index (7+) | + // +---+---------------------------+ + // + private void resumeIndexed(ByteBuffer input, DecodingCallback action) { + if (!integerReader.read(input)) { + return; + } + intValue = integerReader.get(); + integerReader.reset(); + try { + HeaderTable.HeaderField f = table.get(intValue); + action.onIndexed(intValue, f.name, f.value); + } finally { + state = State.READY; + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | Index (4+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteral(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + action.onLiteral(intValue, f.name, value, valueHuffmanEncoded); + } else { + action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded); + } + } finally { + cleanUpAfterReading(); + } + } + + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 1 | Index (6+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 1 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteralWithIndexing(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + // + // 1. (name, value) will be stored in the table as strings + // 2. Most likely the callback will also create strings from them + // ------------------------------------------------------------------------ + // Let's create those string beforehand (and only once!) to benefit everyone + // + String n; + String v = value.toString(); + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + n = f.name; + action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded); + } else { + n = name.toString(); + action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded); + } + table.put(n, v); + } catch (IllegalArgumentException | IllegalStateException e) { + throw new UncheckedIOException( + (IOException) new ProtocolException().initCause(e)); + } finally { + cleanUpAfterReading(); + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 1 | Index (4+) | + // +---+---+-----------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 1 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + // + private void resumeLiteralNeverIndexed(ByteBuffer input, DecodingCallback action) { + if (!completeReading(input)) { + return; + } + try { + if (firstValueIndex) { + HeaderTable.HeaderField f = table.get(intValue); + action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded); + } else { + action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded); + } + } finally { + cleanUpAfterReading(); + } + } + + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 1 | Max size (5+) | + // +---+---------------------------+ + // + private void resumeSizeUpdate(ByteBuffer input, DecodingCallback action) { + if (!integerReader.read(input)) { + return; + } + intValue = integerReader.get(); + assert intValue >= 0; + if (intValue > capacity) { + throw new UncheckedIOException(new ProtocolException( + format("Received capacity exceeds expected: " + + "capacity=%s, expected=%s", intValue, capacity))); + } + integerReader.reset(); + try { + action.onSizeUpdate(intValue); + table.setMaxSize(intValue); + } finally { + state = State.READY; + } + } + + private boolean completeReading(ByteBuffer input) { + if (!firstValueRead) { + if (firstValueIndex) { + if (!integerReader.read(input)) { + return false; + } + intValue = integerReader.get(); + integerReader.reset(); + } else { + if (!stringReader.read(input, name)) { + return false; + } + nameHuffmanEncoded = stringReader.isHuffmanEncoded(); + stringReader.reset(); + } + firstValueRead = true; + return false; + } else { + if (!stringReader.read(input, value)) { + return false; + } + } + valueHuffmanEncoded = stringReader.isHuffmanEncoded(); + stringReader.reset(); + return true; + } + + private void cleanUpAfterReading() { + name.setLength(0); + value.setLength(0); + firstValueRead = false; + state = State.READY; + } + + private enum State { + READY, + INDEXED, + LITERAL_NEVER_INDEXED, + LITERAL, + LITERAL_WITH_INDEXING, + SIZE_UPDATE + } + + HeaderTable getTable() { + return table; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java new file mode 100644 index 00000000000..d0d1ce5d5d5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/DecodingCallback.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +/** + * Delivers results of the {@link Decoder#decode(ByteBuffer, boolean, + * DecodingCallback) decoding operation}. + * + *

Methods of the callback are never called by a decoder with any of the + * arguments being {@code null}. + * + * @apiNote + * + *

The callback provides methods for all possible binary + * representations. This could be useful for implementing an intermediary, + * logging, debugging, etc. + * + *

The callback is an interface in order to interoperate with lambdas (in + * the most common use case): + *

{@code
+ *     DecodingCallback callback = (name, value) -> System.out.println(name + ", " + value);
+ * }
+ * + *

Names and values are {@link CharSequence}s rather than {@link String}s in + * order to allow users to decide whether or not they need to create objects. A + * {@code CharSequence} might be used in-place, for example, to be appended to + * an {@link Appendable} (e.g. {@link StringBuilder}) and then discarded. + * + *

That said, if a passed {@code CharSequence} needs to outlast the method + * call, it needs to be copied. + * + * @since 9 + */ +@FunctionalInterface +public interface DecodingCallback { + + /** + * A method the more specific methods of the callback forward their calls + * to. + * + * @param name + * header name + * @param value + * header value + */ + void onDecoded(CharSequence name, CharSequence value); + + /** + * A more finer-grained version of {@link #onDecoded(CharSequence, + * CharSequence)} that also reports on value sensitivity. + * + *

Value sensitivity must be considered, for example, when implementing + * an intermediary. A {@code value} is sensitive if it was represented as Literal Header + * Field Never Indexed. + * + *

It is required that intermediaries MUST use the {@linkplain + * Encoder#header(CharSequence, CharSequence, boolean) same representation} + * for encoding this header field in order to protect its value which is not + * to be put at risk by compressing it. + * + * @implSpec + * + *

The default implementation invokes {@code onDecoded(name, value)}. + * + * @param name + * header name + * @param value + * header value + * @param sensitive + * whether or not the value is sensitive + * + * @see #onLiteralNeverIndexed(int, CharSequence, CharSequence, boolean) + * @see #onLiteralNeverIndexed(CharSequence, boolean, CharSequence, boolean) + */ + default void onDecoded(CharSequence name, CharSequence value, + boolean sensitive) { + onDecoded(name, value); + } + + /** + * An Indexed + * Header Field decoded. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + */ + default void onIndexed(int index, CharSequence name, CharSequence value) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field without Indexing decoded, where a {@code name} was + * referred by an {@code index}. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteral(int index, CharSequence name, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field without Indexing decoded, where both a {@code name} and + * a {@code value} were literal. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteral(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field Never Indexed decoded, where a {@code name} + * was referred by an {@code index}. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, true)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralNeverIndexed(int index, CharSequence name, + CharSequence value, + boolean valueHuffman) { + onDecoded(name, value, true); + } + + /** + * A Literal + * Header Field Never Indexed decoded, where both a {@code + * name} and a {@code value} were literal. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, true)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralNeverIndexed(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, true); + } + + /** + * A Literal + * Header Field with Incremental Indexing decoded, where a {@code name} + * was referred by an {@code index}. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param index + * index of an entry in the table + * @param name + * header name + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralWithIndexing(int index, + CharSequence name, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Literal + * Header Field with Incremental Indexing decoded, where both a {@code + * name} and a {@code value} were literal. + * + * @implSpec + * + *

The default implementation invokes + * {@code onDecoded(name, value, false)}. + * + * @param name + * header name + * @param nameHuffman + * if the {@code name} was Huffman encoded + * @param value + * header value + * @param valueHuffman + * if the {@code value} was Huffman encoded + */ + default void onLiteralWithIndexing(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + onDecoded(name, value, false); + } + + /** + * A Dynamic Table + * Size Update decoded. + * + * @implSpec + * + *

The default implementation does nothing. + * + * @param capacity + * new capacity of the header table + */ + default void onSizeUpdate(int capacity) { } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java new file mode 100644 index 00000000000..75ab8653457 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Encoder.java @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; +import java.util.LinkedList; +import java.util.List; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * Encodes headers to their binary representation. + * + *

Typical lifecycle looks like this: + * + *

{@link #Encoder(int) new Encoder} + * ({@link #setMaxCapacity(int) setMaxCapacity}? + * {@link #encode(ByteBuffer) encode})* + * + *

Suppose headers are represented by {@code Map>}. A + * supplier and a consumer of {@link ByteBuffer}s in forms of {@code + * Supplier} and {@code Consumer} respectively. Then to + * encode headers, the following approach might be used: + * + *

{@code
+ *     for (Map.Entry> h : headers.entrySet()) {
+ *         String name = h.getKey();
+ *         for (String value : h.getValue()) {
+ *             encoder.header(name, value);        // Set up header
+ *             boolean encoded;
+ *             do {
+ *                 ByteBuffer b = buffersSupplier.get();
+ *                 encoded = encoder.encode(b);    // Encode the header
+ *                 buffersConsumer.accept(b);
+ *             } while (!encoded);
+ *         }
+ *     }
+ * }
+ * + *

Though the specification does not define how + * an encoder is to be implemented, a default implementation is provided by the + * method {@link #header(CharSequence, CharSequence, boolean)}. + * + *

To provide a custom encoding implementation, {@code Encoder} has to be + * extended. A subclass then can access methods for encoding using specific + * representations (e.g. {@link #literal(int, CharSequence, boolean) literal}, + * {@link #indexed(int) indexed}, etc.) + * + * @apiNote + * + *

An Encoder provides an incremental way of encoding headers. + * {@link #encode(ByteBuffer)} takes a buffer a returns a boolean indicating + * whether, or not, the buffer was sufficiently sized to hold the + * remaining of the encoded representation. + * + *

This way, there's no need to provide a buffer of a specific size, or to + * resize (and copy) the buffer on demand, when the remaining encoded + * representation will not fit in the buffer's remaining space. Instead, an + * array of existing buffers can be used, prepended with a frame that encloses + * the resulting header block afterwards. + * + *

Splitting the encoding operation into header set up and header encoding, + * separates long lived arguments ({@code name}, {@code value}, {@code + * sensitivity}, etc.) from the short lived ones (e.g. {@code buffer}), + * simplifying each operation itself. + * + * @implNote + * + *

The default implementation does not use dynamic table. It reports to a + * coupled Decoder a size update with the value of {@code 0}, and never changes + * it afterwards. + * + * @since 9 + */ +public class Encoder { + + // TODO: enum: no huffman/smart huffman/always huffman + private static final boolean DEFAULT_HUFFMAN = true; + + private final IndexedWriter indexedWriter = new IndexedWriter(); + private final LiteralWriter literalWriter = new LiteralWriter(); + private final LiteralNeverIndexedWriter literalNeverIndexedWriter + = new LiteralNeverIndexedWriter(); + private final LiteralWithIndexingWriter literalWithIndexingWriter + = new LiteralWithIndexingWriter(); + private final SizeUpdateWriter sizeUpdateWriter = new SizeUpdateWriter(); + private final BulkSizeUpdateWriter bulkSizeUpdateWriter + = new BulkSizeUpdateWriter(); + + private BinaryRepresentationWriter writer; + private final HeaderTable headerTable; + + private boolean encoding; + + private int maxCapacity; + private int currCapacity; + private int lastCapacity; + private long minCapacity; + private boolean capacityUpdate; + private boolean configuredCapacityUpdate; + + /** + * Constructs an {@code Encoder} with the specified maximum capacity of the + * header table. + * + *

The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + * @param maxCapacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if maxCapacity is negative + */ + public Encoder(int maxCapacity) { + if (maxCapacity < 0) { + throw new IllegalArgumentException("maxCapacity >= 0: " + maxCapacity); + } + // Initial maximum capacity update mechanics + minCapacity = Long.MAX_VALUE; + currCapacity = -1; + setMaxCapacity(maxCapacity); + headerTable = new HeaderTable(lastCapacity); + } + + /** + * Sets up the given header {@code (name, value)}. + * + *

Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, CharSequence value) + throws IllegalStateException { + header(name, value, false); + } + + /** + * Sets up the given header {@code (name, value)} with possibly sensitive + * value. + * + *

Fixates {@code name} and {@code value} for the duration of encoding. + * + * @param name + * the name + * @param value + * the value + * @param sensitive + * whether or not the value is sensitive + * + * @throws NullPointerException + * if any of the arguments are {@code null} + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + * @see #header(CharSequence, CharSequence) + * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean) + */ + public void header(CharSequence name, CharSequence value, + boolean sensitive) throws IllegalStateException { + // Arguably a good balance between complexity of implementation and + // efficiency of encoding + requireNonNull(name, "name"); + requireNonNull(value, "value"); + HeaderTable t = getHeaderTable(); + int index = t.indexOf(name, value); + if (index > 0) { + indexed(index); + } else if (index < 0) { + if (sensitive) { + literalNeverIndexed(-index, value, DEFAULT_HUFFMAN); + } else { + literal(-index, value, DEFAULT_HUFFMAN); + } + } else { + if (sensitive) { + literalNeverIndexed(name, DEFAULT_HUFFMAN, value, DEFAULT_HUFFMAN); + } else { + literal(name, DEFAULT_HUFFMAN, value, DEFAULT_HUFFMAN); + } + } + } + + /** + * Sets a maximum capacity of the header table. + * + *

The value has to be agreed between decoder and encoder out-of-band, + * e.g. by a protocol that uses HPACK (see 4.2. Maximum Table + * Size). + * + *

May be called any number of times after or before a complete header + * has been encoded. + * + *

If the encoder decides to change the actual capacity, an update will + * be encoded before a new encoding operation starts. + * + * @param capacity + * a non-negative integer + * + * @throws IllegalArgumentException + * if capacity is negative + * @throws IllegalStateException + * if the encoder hasn't fully encoded the previous header, or + * hasn't yet started to encode it + */ + public void setMaxCapacity(int capacity) { + checkEncoding(); + if (capacity < 0) { + throw new IllegalArgumentException("capacity >= 0: " + capacity); + } + int calculated = calculateCapacity(capacity); + if (calculated < 0 || calculated > capacity) { + throw new IllegalArgumentException( + format("0 <= calculated <= capacity: calculated=%s, capacity=%s", + calculated, capacity)); + } + capacityUpdate = true; + // maxCapacity needs to be updated unconditionally, so the encoder + // always has the newest one (in case it decides to update it later + // unsolicitedly) + // Suppose maxCapacity = 4096, and the encoder has decided to use only + // 2048. It later can choose anything else from the region [0, 4096]. + maxCapacity = capacity; + lastCapacity = calculated; + minCapacity = Math.min(minCapacity, lastCapacity); + } + + protected int calculateCapacity(int maxCapacity) { + // Default implementation of the Encoder won't add anything to the + // table, therefore no need for a table space + return 0; + } + + /** + * Encodes the {@linkplain #header(CharSequence, CharSequence) set up} + * header into the given buffer. + * + *

The encoder writes as much as possible of the header's binary + * representation into the given buffer, starting at the buffer's position, + * and increments its position to reflect the bytes written. The buffer's + * mark and limit will not be modified. + * + *

Once the method has returned {@code true}, the current header is + * deemed encoded. A new header may be set up. + * + * @param headerBlock + * the buffer to encode the header into, may be empty + * + * @return {@code true} if the current header has been fully encoded, + * {@code false} otherwise + * + * @throws NullPointerException + * if the buffer is {@code null} + * @throws ReadOnlyBufferException + * if this buffer is read-only + * @throws IllegalStateException + * if there is no set up header + */ + public final boolean encode(ByteBuffer headerBlock) { + if (!encoding) { + throw new IllegalStateException("A header hasn't been set up"); + } + if (!prependWithCapacityUpdate(headerBlock)) { + return false; + } + boolean done = writer.write(headerTable, headerBlock); + if (done) { + writer.reset(); // FIXME: WHY? + encoding = false; + } + return done; + } + + private boolean prependWithCapacityUpdate(ByteBuffer headerBlock) { + if (capacityUpdate) { + if (!configuredCapacityUpdate) { + List sizes = new LinkedList<>(); + if (minCapacity < currCapacity) { + sizes.add((int) minCapacity); + if (minCapacity != lastCapacity) { + sizes.add(lastCapacity); + } + } else if (lastCapacity != currCapacity) { + sizes.add(lastCapacity); + } + bulkSizeUpdateWriter.maxHeaderTableSizes(sizes); + configuredCapacityUpdate = true; + } + boolean done = bulkSizeUpdateWriter.write(headerTable, headerBlock); + if (done) { + minCapacity = lastCapacity; + currCapacity = lastCapacity; + bulkSizeUpdateWriter.reset(); + capacityUpdate = false; + configuredCapacityUpdate = false; + } + return done; + } + return true; + } + + protected final void indexed(int index) throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = indexedWriter.index(index); + } + + protected final void literal(int index, CharSequence value, + boolean useHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalWriter + .index(index).value(value, useHuffman); + } + + protected final void literal(CharSequence name, boolean nameHuffman, + CharSequence value, boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void literalNeverIndexed(int index, + CharSequence value, + boolean valueHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalNeverIndexedWriter + .index(index).value(value, valueHuffman); + } + + protected final void literalNeverIndexed(CharSequence name, + boolean nameHuffman, + CharSequence value, + boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalNeverIndexedWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void literalWithIndexing(int index, + CharSequence value, + boolean valueHuffman) + throws IndexOutOfBoundsException { + checkEncoding(); + encoding = true; + writer = literalWithIndexingWriter + .index(index).value(value, valueHuffman); + } + + protected final void literalWithIndexing(CharSequence name, + boolean nameHuffman, + CharSequence value, + boolean valueHuffman) { + checkEncoding(); + encoding = true; + writer = literalWithIndexingWriter + .name(name, nameHuffman).value(value, valueHuffman); + } + + protected final void sizeUpdate(int capacity) + throws IllegalArgumentException { + checkEncoding(); + // Ensure subclass follows the contract + if (capacity > this.maxCapacity) { + throw new IllegalArgumentException( + format("capacity <= maxCapacity: capacity=%s, maxCapacity=%s", + capacity, maxCapacity)); + } + writer = sizeUpdateWriter.maxHeaderTableSize(capacity); + } + + protected final int getMaxCapacity() { + return maxCapacity; + } + + protected final HeaderTable getHeaderTable() { + return headerTable; + } + + protected final void checkEncoding() { + if (encoding) { + throw new IllegalStateException( + "Previous encoding operation hasn't finished yet"); + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java new file mode 100644 index 00000000000..ab824a3df88 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/HeaderTable.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; + +import static java.lang.String.format; + +// +// Header Table combined from two tables: static and dynamic. +// +// There is a single address space for index values. Index-aware methods +// correspond to the table as a whole. Size-aware methods only to the dynamic +// part of it. +// +final class HeaderTable { + + private static final HeaderField[] staticTable = { + null, // To make index 1-based, instead of 0-based + new HeaderField(":authority"), + new HeaderField(":method", "GET"), + new HeaderField(":method", "POST"), + new HeaderField(":path", "/"), + new HeaderField(":path", "/index.html"), + new HeaderField(":scheme", "http"), + new HeaderField(":scheme", "https"), + new HeaderField(":status", "200"), + new HeaderField(":status", "204"), + new HeaderField(":status", "206"), + new HeaderField(":status", "304"), + new HeaderField(":status", "400"), + new HeaderField(":status", "404"), + new HeaderField(":status", "500"), + new HeaderField("accept-charset"), + new HeaderField("accept-encoding", "gzip, deflate"), + new HeaderField("accept-language"), + new HeaderField("accept-ranges"), + new HeaderField("accept"), + new HeaderField("access-control-allow-origin"), + new HeaderField("age"), + new HeaderField("allow"), + new HeaderField("authorization"), + new HeaderField("cache-control"), + new HeaderField("content-disposition"), + new HeaderField("content-encoding"), + new HeaderField("content-language"), + new HeaderField("content-length"), + new HeaderField("content-location"), + new HeaderField("content-range"), + new HeaderField("content-type"), + new HeaderField("cookie"), + new HeaderField("date"), + new HeaderField("etag"), + new HeaderField("expect"), + new HeaderField("expires"), + new HeaderField("from"), + new HeaderField("host"), + new HeaderField("if-match"), + new HeaderField("if-modified-since"), + new HeaderField("if-none-match"), + new HeaderField("if-range"), + new HeaderField("if-unmodified-since"), + new HeaderField("last-modified"), + new HeaderField("link"), + new HeaderField("location"), + new HeaderField("max-forwards"), + new HeaderField("proxy-authenticate"), + new HeaderField("proxy-authorization"), + new HeaderField("range"), + new HeaderField("referer"), + new HeaderField("refresh"), + new HeaderField("retry-after"), + new HeaderField("server"), + new HeaderField("set-cookie"), + new HeaderField("strict-transport-security"), + new HeaderField("transfer-encoding"), + new HeaderField("user-agent"), + new HeaderField("vary"), + new HeaderField("via"), + new HeaderField("www-authenticate") + }; + + private static final int STATIC_TABLE_LENGTH = staticTable.length - 1; + private static final int ENTRY_SIZE = 32; + private static final Map> staticIndexes; + + static { + staticIndexes = new HashMap<>(STATIC_TABLE_LENGTH); + for (int i = 1; i <= STATIC_TABLE_LENGTH; i++) { + HeaderField f = staticTable[i]; + Map values = staticIndexes + .computeIfAbsent(f.name, k -> new LinkedHashMap<>()); + values.put(f.value, i); + } + } + + private final Table dynamicTable = new Table(0); + private int maxSize; + private int size; + + public HeaderTable(int maxSize) { + setMaxSize(maxSize); + } + + // + // The method returns: + // + // * a positive integer i where i (i = [1..Integer.MAX_VALUE]) is an + // index of an entry with a header (n, v), where n.equals(name) && + // v.equals(value) + // + // * a negative integer j where j (j = [-Integer.MAX_VALUE..-1]) is an + // index of an entry with a header (n, v), where n.equals(name) + // + // * 0 if there's no entry e such that e.getName().equals(name) + // + // The rationale behind this design is to allow to pack more useful data + // into a single invocation, facilitating a single pass where possible + // (the idea is the same as in java.util.Arrays.binarySearch(int[], int)). + // + public int indexOf(CharSequence name, CharSequence value) { + // Invoking toString() will possibly allocate Strings for the sake of + // the search, which doesn't feel right. + String n = name.toString(); + String v = value.toString(); + + // 1. Try exact match in the static region + Map values = staticIndexes.get(n); + if (values != null) { + Integer idx = values.get(v); + if (idx != null) { + return idx; + } + } + // 2. Try exact match in the dynamic region + int didx = dynamicTable.indexOf(n, v); + if (didx > 0) { + return STATIC_TABLE_LENGTH + didx; + } else if (didx < 0) { + if (values != null) { + // 3. Return name match from the static region + return -values.values().iterator().next(); // Iterator allocation + } else { + // 4. Return name match from the dynamic region + return -STATIC_TABLE_LENGTH + didx; + } + } else { + if (values != null) { + // 3. Return name match from the static region + return -values.values().iterator().next(); // Iterator allocation + } else { + return 0; + } + } + } + + public int size() { + return size; + } + + public int maxSize() { + return maxSize; + } + + public int length() { + return STATIC_TABLE_LENGTH + dynamicTable.size(); + } + + HeaderField get(int index) { + checkIndex(index); + if (index <= STATIC_TABLE_LENGTH) { + return staticTable[index]; + } else { + return dynamicTable.get(index - STATIC_TABLE_LENGTH); + } + } + + void put(CharSequence name, CharSequence value) { + // Invoking toString() will possibly allocate Strings. But that's + // unavoidable at this stage. If a CharSequence is going to be stored in + // the table, it must not be mutable (e.g. for the sake of hashing). + put(new HeaderField(name.toString(), value.toString())); + } + + private void put(HeaderField h) { + int entrySize = sizeOf(h); + while (entrySize > maxSize - size && size != 0) { + evictEntry(); + } + if (entrySize > maxSize - size) { + return; + } + size += entrySize; + dynamicTable.add(h); + } + + void setMaxSize(int maxSize) { + if (maxSize < 0) { + throw new IllegalArgumentException + ("maxSize >= 0: maxSize=" + maxSize); + } + while (maxSize < size && size != 0) { + evictEntry(); + } + this.maxSize = maxSize; + int upperBound = (maxSize / ENTRY_SIZE) + 1; + this.dynamicTable.setCapacity(upperBound); + } + + HeaderField evictEntry() { + HeaderField f = dynamicTable.remove(); + size -= sizeOf(f); + return f; + } + + @Override + public String toString() { + double used = maxSize == 0 ? 0 : 100 * (((double) size) / maxSize); + return format("entries: %d; used %s/%s (%.1f%%)", dynamicTable.size(), + size, maxSize, used); + } + + int checkIndex(int index) { + if (index < 1 || index > STATIC_TABLE_LENGTH + dynamicTable.size()) { + throw new IllegalArgumentException( + format("1 <= index <= length(): index=%s, length()=%s", + index, length())); + } + return index; + } + + int sizeOf(HeaderField f) { + return f.name.length() + f.value.length() + ENTRY_SIZE; + } + + // + // Diagnostic information in the form used in the RFC 7541 + // + String getStateString() { + if (size == 0) { + return "empty."; + } + + StringBuilder b = new StringBuilder(); + for (int i = 1, size = dynamicTable.size(); i <= size; i++) { + HeaderField e = dynamicTable.get(i); + b.append(format("[%3d] (s = %3d) %s: %s\n", i, + sizeOf(e), e.name, e.value)); + } + b.append(format(" Table size:%4s", this.size)); + return b.toString(); + } + + // Convert to a Value Object (JDK-8046159)? + static final class HeaderField { + + final String name; + final String value; + + public HeaderField(String name) { + this(name, ""); + } + + public HeaderField(String name, String value) { + this.name = name; + this.value = value; + } + + @Override + public String toString() { + return value.isEmpty() ? name : name + ": " + value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HeaderField that = (HeaderField) o; + return name.equals(that.name) && value.equals(that.value); + } + + @Override + public int hashCode() { + return 31 * (name.hashCode()) + value.hashCode(); + } + } + + // + // In order to be able to find an index of an entry with the given contents + // in the dynamic table an effective inverse mapping is needed. Here's a + // simple idea behind such a mapping. + // + // # The problem: + // + // We have a queue with an O(1) lookup by index: + // + // get: index -> x + // + // What we also want is an O(1) reverse lookup: + // + // indexOf: x -> index + // + // # Solution: + // + // Let's store an inverse mapping as a Map. This have a problem + // that when a new element is added to the queue all indexes in the map + // becomes invalid. Namely, each i becomes shifted by 1 to the right: + // + // i -> i + 1 + // + // And the new element is assigned with an index of 1. This would seem to + // require a pass through the map incrementing all indexes (map values) by + // 1, which is O(n). + // + // The good news is we can do much better then this! + // + // Let's create a single field of type long, called 'counter'. Then each + // time a new element 'x' is added to the queue, a value of this field gets + // incremented. Then the resulting value of the 'counter_x' is then put as a + // value under key 'x' to the map: + // + // map.put(x, counter_x) + // + // It gives us a map that maps an element to a value the counter had at the + // time the element had been added. + // + // In order to retrieve an index of any element 'x' in the queue (at any + // given time) we simply need to subtract the value (the snapshot of the + // counter at the time when the 'x' was added) from the current value of the + // counter. This operation basically answers the question: + // + // How many elements ago 'x' was the tail of the queue? + // + // Which is the same as its index in the queue now. Given, of course, it's + // still in the queue. + // + // I'm pretty sure in a real life long overflow will never happen, so it's + // not too practical to add recalibrating code, but a pedantic person might + // want to do so: + // + // if (counter == Long.MAX_VALUE) { + // recalibrate(); + // } + // + // Where 'recalibrate()' goes through the table doing this: + // + // value -= counter + // + // That's given, of course, the size of the table itself is less than + // Long.MAX_VALUE :-) + // + private static final class Table { + + private final Map> map; + private final CircularBuffer buffer; + private long counter = 1; + + Table(int capacity) { + buffer = new CircularBuffer<>(capacity); + map = new HashMap<>(capacity); + } + + void add(HeaderField f) { + buffer.add(f); + Map values = map.computeIfAbsent(f.name, k -> new HashMap<>()); + values.put(f.value, counter++); + } + + HeaderField get(int index) { + return buffer.get(index - 1); + } + + int indexOf(String name, String value) { + Map values = map.get(name); + if (values == null) { + return 0; + } + Long index = values.get(value); + if (index != null) { + return (int) (counter - index); + } else { + assert !values.isEmpty(); + Long any = values.values().iterator().next(); // Iterator allocation + return -(int) (counter - any); + } + } + + HeaderField remove() { + HeaderField f = buffer.remove(); + Map values = map.get(f.name); + Long index = values.remove(f.value); + assert index != null; + if (values.isEmpty()) { + map.remove(f.name); + } + return f; + } + + int size() { + return buffer.size; + } + + public void setCapacity(int capacity) { + buffer.resize(capacity); + } + } + + // head + // v + // [ ][ ][A][B][C][D][ ][ ][ ] + // ^ + // tail + // + // |<- size ->| (4) + // |<------ capacity ------->| (9) + // + static final class CircularBuffer { + + int tail, head, size, capacity; + Object[] elements; + + CircularBuffer(int capacity) { + this.capacity = capacity; + elements = new Object[capacity]; + } + + void add(E elem) { + if (size == capacity) { + throw new IllegalStateException( + format("No room for '%s': capacity=%s", elem, capacity)); + } + elements[head] = elem; + head = (head + 1) % capacity; + size++; + } + + @SuppressWarnings("unchecked") + E remove() { + if (size == 0) { + throw new NoSuchElementException("Empty"); + } + E elem = (E) elements[tail]; + elements[tail] = null; + tail = (tail + 1) % capacity; + size--; + return elem; + } + + @SuppressWarnings("unchecked") + E get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException( + format("0 <= index <= capacity: index=%s, capacity=%s", + index, capacity)); + } + int idx = (tail + (size - index - 1)) % capacity; + return (E) elements[idx]; + } + + public void resize(int newCapacity) { + if (newCapacity < size) { + throw new IllegalStateException( + format("newCapacity >= size: newCapacity=%s, size=%s", + newCapacity, size)); + } + + Object[] newElements = new Object[newCapacity]; + + if (tail < head || size == 0) { + System.arraycopy(elements, tail, newElements, 0, size); + } else { + System.arraycopy(elements, tail, newElements, 0, elements.length - tail); + System.arraycopy(elements, 0, newElements, elements.length - tail, head); + } + + elements = newElements; + tail = 0; + head = size; + this.capacity = newCapacity; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java new file mode 100644 index 00000000000..9c58cc3acc2 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/Huffman.java @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +import static java.lang.String.format; + +/** + * Huffman coding table. + * + *

Instances of this class are safe for use by multiple threads. + * + * @since 9 + */ +public final class Huffman { + + // TODO: check if reset is done in both reader and writer + + static final class Reader { + + private Node curr; // position in the trie + private int len; // length of the path from the root to 'curr' + private int p; // byte probe + + { + reset(); + } + + public void read(ByteBuffer source, Appendable destination, + boolean isLast) { + read(source, destination, true, isLast); + } + + // Takes 'isLast' rather than returns whether the reading is done or + // not, for more informative exceptions. + void read(ByteBuffer source, Appendable destination, boolean reportEOS, + boolean isLast) { + + Node c = curr; + int l = len; + /* + Since ByteBuffer is itself stateful, its position is + remembered here NOT as a part of Reader's state, + but to set it back in the case of a failure + */ + int pos = source.position(); + + while (source.hasRemaining()) { + int d = source.get(); + for (; p != 0; p >>= 1) { + c = c.getChild(p & d); + l++; + if (c.isLeaf()) { + if (reportEOS && c.isEOSPath) { + throw new IllegalArgumentException("Encountered EOS"); + } + try { + destination.append(c.getChar()); + } catch (RuntimeException | Error e) { + source.position(pos); + throw e; + } catch (IOException e) { + source.position(pos); + throw new UncheckedIOException(e); + } + c = INSTANCE.root; + l = 0; + } + curr = c; + len = l; + } + resetProbe(); + pos++; + } + if (!isLast) { + return; // it's too early to jump to any conclusions, let's wait + } + if (c.isLeaf()) { + return; // it's perfectly ok, no extra padding bits + } + if (c.isEOSPath && len <= 7) { + return; // it's ok, some extra padding bits + } + if (c.isEOSPath) { + throw new IllegalArgumentException( + "Padding is too long (len=" + len + ") " + + "or unexpected end of data"); + } + throw new IllegalArgumentException( + "Not a EOS prefix padding or unexpected end of data"); + } + + public void reset() { + curr = INSTANCE.root; + len = 0; + resetProbe(); + } + + private void resetProbe() { + p = 0x80; + } + } + + static final class Writer { + + private int pos; // position in 'source' + private int avail = 8; // number of least significant bits available in 'curr' + private int curr; // next byte to put to the destination + private int rem; // number of least significant bits in 'code' yet to be processed + private int code; // current code being written + + private CharSequence source; + private int end; + + public Writer from(CharSequence input, int start, int end) { + if (start < 0 || end < 0 || end > input.length() || start > end) { + throw new IndexOutOfBoundsException( + String.format("input.length()=%s, start=%s, end=%s", + input.length(), start, end)); + } + pos = start; + this.end = end; + this.source = input; + return this; + } + + public boolean write(ByteBuffer destination) { + for (; pos < end; pos++) { + if (rem == 0) { + Code desc = INSTANCE.codeOf(source.charAt(pos)); + rem = desc.length; + code = desc.code; + } + while (rem > 0) { + if (rem < avail) { + curr |= (code << (avail - rem)); + avail -= rem; + rem = 0; + } else { + int c = (curr | (code >>> (rem - avail))); + if (destination.hasRemaining()) { + destination.put((byte) c); + } else { + return false; + } + curr = c; + code <<= (32 - rem + avail); // throw written bits off the cliff (is this Sparta?) + code >>>= (32 - rem + avail); // return to the position + rem -= avail; + curr = 0; + avail = 8; + } + } + } + + if (avail < 8) { // have to pad + if (destination.hasRemaining()) { + destination.put((byte) (curr | (INSTANCE.EOS.code >>> (INSTANCE.EOS.length - avail)))); + avail = 8; + } else { + return false; + } + } + + return true; + } + + public Writer reset() { + source = null; + end = -1; + pos = -1; + avail = 8; + curr = 0; + code = 0; + return this; + } + } + + /** + * Shared instance. + */ + public static final Huffman INSTANCE = new Huffman(); + + private final Code EOS = new Code(0x3fffffff, 30); + private final Code[] codes = new Code[257]; + private final Node root = new Node() { + @Override + public String toString() { return "root"; } + }; + + // TODO: consider builder and immutable trie + private Huffman() { + // @formatter:off + addChar(0, 0x1ff8, 13); + addChar(1, 0x7fffd8, 23); + addChar(2, 0xfffffe2, 28); + addChar(3, 0xfffffe3, 28); + addChar(4, 0xfffffe4, 28); + addChar(5, 0xfffffe5, 28); + addChar(6, 0xfffffe6, 28); + addChar(7, 0xfffffe7, 28); + addChar(8, 0xfffffe8, 28); + addChar(9, 0xffffea, 24); + addChar(10, 0x3ffffffc, 30); + addChar(11, 0xfffffe9, 28); + addChar(12, 0xfffffea, 28); + addChar(13, 0x3ffffffd, 30); + addChar(14, 0xfffffeb, 28); + addChar(15, 0xfffffec, 28); + addChar(16, 0xfffffed, 28); + addChar(17, 0xfffffee, 28); + addChar(18, 0xfffffef, 28); + addChar(19, 0xffffff0, 28); + addChar(20, 0xffffff1, 28); + addChar(21, 0xffffff2, 28); + addChar(22, 0x3ffffffe, 30); + addChar(23, 0xffffff3, 28); + addChar(24, 0xffffff4, 28); + addChar(25, 0xffffff5, 28); + addChar(26, 0xffffff6, 28); + addChar(27, 0xffffff7, 28); + addChar(28, 0xffffff8, 28); + addChar(29, 0xffffff9, 28); + addChar(30, 0xffffffa, 28); + addChar(31, 0xffffffb, 28); + addChar(32, 0x14, 6); + addChar(33, 0x3f8, 10); + addChar(34, 0x3f9, 10); + addChar(35, 0xffa, 12); + addChar(36, 0x1ff9, 13); + addChar(37, 0x15, 6); + addChar(38, 0xf8, 8); + addChar(39, 0x7fa, 11); + addChar(40, 0x3fa, 10); + addChar(41, 0x3fb, 10); + addChar(42, 0xf9, 8); + addChar(43, 0x7fb, 11); + addChar(44, 0xfa, 8); + addChar(45, 0x16, 6); + addChar(46, 0x17, 6); + addChar(47, 0x18, 6); + addChar(48, 0x0, 5); + addChar(49, 0x1, 5); + addChar(50, 0x2, 5); + addChar(51, 0x19, 6); + addChar(52, 0x1a, 6); + addChar(53, 0x1b, 6); + addChar(54, 0x1c, 6); + addChar(55, 0x1d, 6); + addChar(56, 0x1e, 6); + addChar(57, 0x1f, 6); + addChar(58, 0x5c, 7); + addChar(59, 0xfb, 8); + addChar(60, 0x7ffc, 15); + addChar(61, 0x20, 6); + addChar(62, 0xffb, 12); + addChar(63, 0x3fc, 10); + addChar(64, 0x1ffa, 13); + addChar(65, 0x21, 6); + addChar(66, 0x5d, 7); + addChar(67, 0x5e, 7); + addChar(68, 0x5f, 7); + addChar(69, 0x60, 7); + addChar(70, 0x61, 7); + addChar(71, 0x62, 7); + addChar(72, 0x63, 7); + addChar(73, 0x64, 7); + addChar(74, 0x65, 7); + addChar(75, 0x66, 7); + addChar(76, 0x67, 7); + addChar(77, 0x68, 7); + addChar(78, 0x69, 7); + addChar(79, 0x6a, 7); + addChar(80, 0x6b, 7); + addChar(81, 0x6c, 7); + addChar(82, 0x6d, 7); + addChar(83, 0x6e, 7); + addChar(84, 0x6f, 7); + addChar(85, 0x70, 7); + addChar(86, 0x71, 7); + addChar(87, 0x72, 7); + addChar(88, 0xfc, 8); + addChar(89, 0x73, 7); + addChar(90, 0xfd, 8); + addChar(91, 0x1ffb, 13); + addChar(92, 0x7fff0, 19); + addChar(93, 0x1ffc, 13); + addChar(94, 0x3ffc, 14); + addChar(95, 0x22, 6); + addChar(96, 0x7ffd, 15); + addChar(97, 0x3, 5); + addChar(98, 0x23, 6); + addChar(99, 0x4, 5); + addChar(100, 0x24, 6); + addChar(101, 0x5, 5); + addChar(102, 0x25, 6); + addChar(103, 0x26, 6); + addChar(104, 0x27, 6); + addChar(105, 0x6, 5); + addChar(106, 0x74, 7); + addChar(107, 0x75, 7); + addChar(108, 0x28, 6); + addChar(109, 0x29, 6); + addChar(110, 0x2a, 6); + addChar(111, 0x7, 5); + addChar(112, 0x2b, 6); + addChar(113, 0x76, 7); + addChar(114, 0x2c, 6); + addChar(115, 0x8, 5); + addChar(116, 0x9, 5); + addChar(117, 0x2d, 6); + addChar(118, 0x77, 7); + addChar(119, 0x78, 7); + addChar(120, 0x79, 7); + addChar(121, 0x7a, 7); + addChar(122, 0x7b, 7); + addChar(123, 0x7ffe, 15); + addChar(124, 0x7fc, 11); + addChar(125, 0x3ffd, 14); + addChar(126, 0x1ffd, 13); + addChar(127, 0xffffffc, 28); + addChar(128, 0xfffe6, 20); + addChar(129, 0x3fffd2, 22); + addChar(130, 0xfffe7, 20); + addChar(131, 0xfffe8, 20); + addChar(132, 0x3fffd3, 22); + addChar(133, 0x3fffd4, 22); + addChar(134, 0x3fffd5, 22); + addChar(135, 0x7fffd9, 23); + addChar(136, 0x3fffd6, 22); + addChar(137, 0x7fffda, 23); + addChar(138, 0x7fffdb, 23); + addChar(139, 0x7fffdc, 23); + addChar(140, 0x7fffdd, 23); + addChar(141, 0x7fffde, 23); + addChar(142, 0xffffeb, 24); + addChar(143, 0x7fffdf, 23); + addChar(144, 0xffffec, 24); + addChar(145, 0xffffed, 24); + addChar(146, 0x3fffd7, 22); + addChar(147, 0x7fffe0, 23); + addChar(148, 0xffffee, 24); + addChar(149, 0x7fffe1, 23); + addChar(150, 0x7fffe2, 23); + addChar(151, 0x7fffe3, 23); + addChar(152, 0x7fffe4, 23); + addChar(153, 0x1fffdc, 21); + addChar(154, 0x3fffd8, 22); + addChar(155, 0x7fffe5, 23); + addChar(156, 0x3fffd9, 22); + addChar(157, 0x7fffe6, 23); + addChar(158, 0x7fffe7, 23); + addChar(159, 0xffffef, 24); + addChar(160, 0x3fffda, 22); + addChar(161, 0x1fffdd, 21); + addChar(162, 0xfffe9, 20); + addChar(163, 0x3fffdb, 22); + addChar(164, 0x3fffdc, 22); + addChar(165, 0x7fffe8, 23); + addChar(166, 0x7fffe9, 23); + addChar(167, 0x1fffde, 21); + addChar(168, 0x7fffea, 23); + addChar(169, 0x3fffdd, 22); + addChar(170, 0x3fffde, 22); + addChar(171, 0xfffff0, 24); + addChar(172, 0x1fffdf, 21); + addChar(173, 0x3fffdf, 22); + addChar(174, 0x7fffeb, 23); + addChar(175, 0x7fffec, 23); + addChar(176, 0x1fffe0, 21); + addChar(177, 0x1fffe1, 21); + addChar(178, 0x3fffe0, 22); + addChar(179, 0x1fffe2, 21); + addChar(180, 0x7fffed, 23); + addChar(181, 0x3fffe1, 22); + addChar(182, 0x7fffee, 23); + addChar(183, 0x7fffef, 23); + addChar(184, 0xfffea, 20); + addChar(185, 0x3fffe2, 22); + addChar(186, 0x3fffe3, 22); + addChar(187, 0x3fffe4, 22); + addChar(188, 0x7ffff0, 23); + addChar(189, 0x3fffe5, 22); + addChar(190, 0x3fffe6, 22); + addChar(191, 0x7ffff1, 23); + addChar(192, 0x3ffffe0, 26); + addChar(193, 0x3ffffe1, 26); + addChar(194, 0xfffeb, 20); + addChar(195, 0x7fff1, 19); + addChar(196, 0x3fffe7, 22); + addChar(197, 0x7ffff2, 23); + addChar(198, 0x3fffe8, 22); + addChar(199, 0x1ffffec, 25); + addChar(200, 0x3ffffe2, 26); + addChar(201, 0x3ffffe3, 26); + addChar(202, 0x3ffffe4, 26); + addChar(203, 0x7ffffde, 27); + addChar(204, 0x7ffffdf, 27); + addChar(205, 0x3ffffe5, 26); + addChar(206, 0xfffff1, 24); + addChar(207, 0x1ffffed, 25); + addChar(208, 0x7fff2, 19); + addChar(209, 0x1fffe3, 21); + addChar(210, 0x3ffffe6, 26); + addChar(211, 0x7ffffe0, 27); + addChar(212, 0x7ffffe1, 27); + addChar(213, 0x3ffffe7, 26); + addChar(214, 0x7ffffe2, 27); + addChar(215, 0xfffff2, 24); + addChar(216, 0x1fffe4, 21); + addChar(217, 0x1fffe5, 21); + addChar(218, 0x3ffffe8, 26); + addChar(219, 0x3ffffe9, 26); + addChar(220, 0xffffffd, 28); + addChar(221, 0x7ffffe3, 27); + addChar(222, 0x7ffffe4, 27); + addChar(223, 0x7ffffe5, 27); + addChar(224, 0xfffec, 20); + addChar(225, 0xfffff3, 24); + addChar(226, 0xfffed, 20); + addChar(227, 0x1fffe6, 21); + addChar(228, 0x3fffe9, 22); + addChar(229, 0x1fffe7, 21); + addChar(230, 0x1fffe8, 21); + addChar(231, 0x7ffff3, 23); + addChar(232, 0x3fffea, 22); + addChar(233, 0x3fffeb, 22); + addChar(234, 0x1ffffee, 25); + addChar(235, 0x1ffffef, 25); + addChar(236, 0xfffff4, 24); + addChar(237, 0xfffff5, 24); + addChar(238, 0x3ffffea, 26); + addChar(239, 0x7ffff4, 23); + addChar(240, 0x3ffffeb, 26); + addChar(241, 0x7ffffe6, 27); + addChar(242, 0x3ffffec, 26); + addChar(243, 0x3ffffed, 26); + addChar(244, 0x7ffffe7, 27); + addChar(245, 0x7ffffe8, 27); + addChar(246, 0x7ffffe9, 27); + addChar(247, 0x7ffffea, 27); + addChar(248, 0x7ffffeb, 27); + addChar(249, 0xffffffe, 28); + addChar(250, 0x7ffffec, 27); + addChar(251, 0x7ffffed, 27); + addChar(252, 0x7ffffee, 27); + addChar(253, 0x7ffffef, 27); + addChar(254, 0x7fffff0, 27); + addChar(255, 0x3ffffee, 26); + addEOS (256, EOS.code, EOS.length); + // @formatter:on + } + + + /** + * Calculates the number of bytes required to represent the given {@code + * CharSequence} with the Huffman coding. + * + * @param value + * characters + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + */ + public int lengthOf(CharSequence value) { + return lengthOf(value, 0, value.length()); + } + + /** + * Calculates the number of bytes required to represent a subsequence of the + * given {@code CharSequence} with the Huffman coding. + * + * @param value + * characters + * @param start + * the start index, inclusive + * @param end + * the end index, exclusive + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + * @throws IndexOutOfBoundsException + * if any invocation of {@code value.charAt(i)}, where {@code start + * <= i < end} would throw an IndexOutOfBoundsException + */ + public int lengthOf(CharSequence value, int start, int end) { + int len = 0; + for (int i = start; i < end; i++) { + char c = value.charAt(i); + len += INSTANCE.codeOf(c).length; + } + // Integer division with ceiling, assumption: + assert (len / 8 + (len % 8 != 0 ? 1 : 0)) == (len + 7) / 8 : len; + return (len + 7) / 8; + } + + private void addChar(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, false); + codes[c] = new Code(code, bitLength); + } + + private void addEOS(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, true); + codes[c] = new Code(code, bitLength); + } + + private void addLeaf(int c, int code, int bitLength, boolean isEOS) { + if (bitLength < 1) { + throw new IllegalArgumentException("bitLength < 1"); + } + Node curr = root; + for (int p = 1 << bitLength - 1; p != 0 && !curr.isLeaf(); p = p >> 1) { + curr.isEOSPath |= isEOS; // If it's already true, it can't become false + curr = curr.addChildIfAbsent(p & code); + } + curr.isEOSPath |= isEOS; // The last one needs to have this property as well + if (curr.isLeaf()) { + throw new IllegalStateException("Specified code is already taken"); + } + curr.setChar((char) c); + } + + private Code codeOf(char c) { + if (c > 255) { + throw new IllegalArgumentException("char=" + ((int) c)); + } + return codes[c]; + } + + // + // For debugging/testing purposes + // + Node getRoot() { + return root; + } + + // + // Guarantees: + // + // if (isLeaf() == true) => getChar() is a legal call + // if (isLeaf() == false) => getChild(i) is a legal call (though it can + // return null) + // + static class Node { + + Node left; + Node right; + boolean isEOSPath; + + boolean charIsSet; + char c; + + Node getChild(int selector) { + if (isLeaf()) { + throw new IllegalStateException("This is a leaf node"); + } + Node result = selector == 0 ? left : right; + if (result == null) { + throw new IllegalStateException(format( + "Node doesn't have a child (selector=%s)", selector)); + } + return result; + } + + boolean isLeaf() { + return charIsSet; + } + + char getChar() { + if (!isLeaf()) { + throw new IllegalStateException("This node is not a leaf node"); + } + return c; + } + + void setChar(char c) { + if (charIsSet) { + throw new IllegalStateException( + "This node has been taken already"); + } + if (left != null || right != null) { + throw new IllegalStateException("The node cannot be made " + + "a leaf as it's already has a child"); + } + this.c = c; + charIsSet = true; + } + + Node addChildIfAbsent(int i) { + if (charIsSet) { + throw new IllegalStateException("The node cannot have a child " + + "as it's already a leaf node"); + } + Node child; + if (i == 0) { + if ((child = left) == null) { + child = left = new Node(); + } + } else { + if ((child = right) == null) { + child = right = new Node(); + } + } + return child; + } + + @Override + public String toString() { + if (isLeaf()) { + if (isEOSPath) { + return "EOS"; + } else { + return format("char: (%3s) '%s'", (int) c, c); + } + } + return "/\\"; + } + } + + // TODO: value-based class? + // FIXME: can we re-use Node instead of this class? + private static final class Code { + + final int code; + final int length; + + private Code(int code, int length) { + this.code = code; + this.length = length; + } + + public int getCode() { + return code; + } + + public int getLength() { + return length; + } + + @Override + public String toString() { + long p = 1 << length; + return Long.toBinaryString(code + p).substring(1) + + ", length=" + length; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java new file mode 100644 index 00000000000..162c9839ae9 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/ISO_8859_1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +// +// Custom implementation of ISO/IEC 8859-1:1998 +// +// The rationale behind this is not to deal with CharsetEncoder/CharsetDecoder, +// basically because it would require wrapping every single CharSequence into a +// CharBuffer and then copying it back. +// +// But why not to give a CharBuffer instead of Appendable? Because I can choose +// an Appendable (e.g. StringBuilder) that adjusts its length when needed and +// therefore not to deal with pre-sized CharBuffers or copying. +// +// The encoding is simple and well known: 1 byte <-> 1 char +// +final class ISO_8859_1 { + + private ISO_8859_1() { } + + public static final class Reader { + + public void read(ByteBuffer source, Appendable destination) { + for (int i = 0, len = source.remaining(); i < len; i++) { + char c = (char) (source.get() & 0xff); + try { + destination.append(c); + } catch (IOException e) { + throw new UncheckedIOException + ("Error appending to the destination", e); + } + } + } + + public Reader reset() { + return this; + } + } + + public static final class Writer { + + private CharSequence source; + private int pos; + private int end; + + public Writer configure(CharSequence source, int start, int end) { + this.source = source; + this.pos = start; + this.end = end; + return this; + } + + public boolean write(ByteBuffer destination) { + for (; pos < end; pos++) { + char c = source.charAt(pos); + if (c > '\u00FF') { + throw new IllegalArgumentException( + "Illegal ISO-8859-1 char: " + (int) c); + } + if (destination.hasRemaining()) { + destination.put((byte) c); + } else { + return false; + } + } + return true; + } + + public Writer reset() { + source = null; + pos = -1; + end = -1; + return this; + } + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java new file mode 100644 index 00000000000..01b4decca00 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexNameValueWriter.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +abstract class IndexNameValueWriter implements BinaryRepresentationWriter { + + private final int pattern; + private final int prefix; + private final IntegerWriter intWriter = new IntegerWriter(); + private final StringWriter nameWriter = new StringWriter(); + private final StringWriter valueWriter = new StringWriter(); + + protected boolean indexedRepresentation; + + private static final int NEW = 0; + private static final int NAME_PART_WRITTEN = 1; + private static final int VALUE_WRITTEN = 2; + + private int state = NEW; + + protected IndexNameValueWriter(int pattern, int prefix) { + this.pattern = pattern; + this.prefix = prefix; + } + + IndexNameValueWriter index(int index) { + indexedRepresentation = true; + intWriter.configure(index, prefix, pattern); + return this; + } + + IndexNameValueWriter name(CharSequence name, boolean useHuffman) { + indexedRepresentation = false; + intWriter.configure(0, prefix, pattern); + nameWriter.configure(name, useHuffman); + return this; + } + + IndexNameValueWriter value(CharSequence value, boolean useHuffman) { + valueWriter.configure(value, useHuffman); + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (state < NAME_PART_WRITTEN) { + if (indexedRepresentation) { + if (!intWriter.write(destination)) { + return false; + } + } else { + if (!intWriter.write(destination) || !nameWriter.write(destination)) { + return false; + } + } + state = NAME_PART_WRITTEN; + } + if (state < VALUE_WRITTEN) { + if (!valueWriter.write(destination)) { + return false; + } + state = VALUE_WRITTEN; + } + return state == VALUE_WRITTEN; + } + + @Override + public IndexNameValueWriter reset() { + intWriter.reset(); + if (!indexedRepresentation) { + nameWriter.reset(); + } + valueWriter.reset(); + state = NEW; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java new file mode 100644 index 00000000000..4ccd9d76112 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IndexedWriter.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class IndexedWriter implements BinaryRepresentationWriter { + + private final IntegerWriter intWriter = new IntegerWriter(); + + IndexedWriter() { } + + IndexedWriter index(int index) { + intWriter.configure(index, 7, 0b1000_0000); + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + return intWriter.write(destination); + } + + @Override + public BinaryRepresentationWriter reset() { + intWriter.reset(); + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java new file mode 100644 index 00000000000..0e7abcfd2f5 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerReader.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import static java.lang.String.format; + +final class IntegerReader { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int FIRST_BYTE_READ = 2; + private static final int DONE = 4; + + private int state = NEW; + + private int N; + private int maxValue; + private int value; + private long r; + private long b = 1; + + public IntegerReader configure(int N) { + return configure(N, Integer.MAX_VALUE); + } + + // + // Why is it important to configure 'maxValue' here. After all we can wait + // for the integer to be fully read and then check it. Can't we? + // + // Two reasons. + // + // 1. Value wraps around long won't be unnoticed. + // 2. It can spit out an exception as soon as it becomes clear there's + // an overflow. Therefore, no need to wait for the value to be fully read. + // + public IntegerReader configure(int N, int maxValue) { + if (state != NEW) { + throw new IllegalStateException("Already configured"); + } + checkPrefix(N); + if (maxValue < 0) { + throw new IllegalArgumentException( + "maxValue >= 0: maxValue=" + maxValue); + } + this.maxValue = maxValue; + this.N = N; + state = CONFIGURED; + return this; + } + + public boolean read(ByteBuffer input) { + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (state == DONE) { + return true; + } + if (!input.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + int max = (2 << (N - 1)) - 1; + int n = input.get() & max; + if (n != max) { + value = n; + state = DONE; + return true; + } else { + r = max; + } + state = FIRST_BYTE_READ; + } + if (state == FIRST_BYTE_READ) { + // variable-length quantity (VLQ) + byte i; + do { + if (!input.hasRemaining()) { + return false; + } + i = input.get(); + long increment = b * (i & 127); + if (r + increment > maxValue) { + throw new IllegalArgumentException(format( + "Integer overflow: maxValue=%,d, value=%,d", + maxValue, r + increment)); + } + r += increment; + b *= 128; + } while ((128 & i) == 128); + + value = (int) r; + state = DONE; + return true; + } + throw new InternalError(Arrays.toString( + new Object[]{state, N, maxValue, value, r, b})); + } + + public int get() throws IllegalStateException { + if (state != DONE) { + throw new IllegalStateException("Has not been fully read yet"); + } + return value; + } + + private static void checkPrefix(int N) { + if (N < 1 || N > 8) { + throw new IllegalArgumentException("1 <= N <= 8: N= " + N); + } + } + + public IntegerReader reset() { + b = 1; + state = NEW; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java new file mode 100644 index 00000000000..7fd1c108ab3 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/IntegerWriter.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +final class IntegerWriter { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int FIRST_BYTE_WRITTEN = 2; + private static final int DONE = 4; + + private int state = NEW; + + private int payload; + private int N; + private int value; + + // + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | | | | | | | | | + // +---+---+---+-------------------+ + // |<--------->|<----------------->| + // payload N=5 + // + // payload is the contents of the left-hand side part of the octet; + // it is truncated to fit into 8-N bits, where 1 <= N <= 8; + // + public IntegerWriter configure(int value, int N, int payload) { + if (state != NEW) { + throw new IllegalStateException("Already configured"); + } + if (value < 0) { + throw new IllegalArgumentException("value >= 0: value=" + value); + } + checkPrefix(N); + this.value = value; + this.N = N; + this.payload = payload & 0xFF & (0xFFFFFFFF << N); + state = CONFIGURED; + return this; + } + + public boolean write(ByteBuffer output) { + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (state == DONE) { + return true; + } + + if (!output.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + int max = (2 << (N - 1)) - 1; + if (value < max) { + output.put((byte) (payload | value)); + state = DONE; + return true; + } + output.put((byte) (payload | max)); + value -= max; + state = FIRST_BYTE_WRITTEN; + } + if (state == FIRST_BYTE_WRITTEN) { + while (value >= 128 && output.hasRemaining()) { + output.put((byte) (value % 128 + 128)); + value /= 128; + } + if (!output.hasRemaining()) { + return false; + } + output.put((byte) value); + state = DONE; + return true; + } + throw new InternalError(Arrays.toString( + new Object[]{state, payload, N, value})); + } + + private static void checkPrefix(int N) { + if (N < 1 || N > 8) { + throw new IllegalArgumentException("1 <= N <= 8: N= " + N); + } + } + + public IntegerWriter reset() { + state = NEW; + return this; + } +} diff --git a/jdk/src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java similarity index 87% rename from jdk/src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java rename to jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java index 90e9189fbf6..92547ca13a9 100644 --- a/jdk/src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralNeverIndexedWriter.java @@ -22,15 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package sun.net.httpclient.hpack; -package jdk.rmi.rmic; +final class LiteralNeverIndexedWriter extends IndexNameValueWriter { -/** - * The initial class for the rmic tool. - */ - -public class Main { - public static void main(String[] args) { - sun.rmi.rmic.Main.main(args); + LiteralNeverIndexedWriter() { + super(0b0001_0000, 4); } } diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java new file mode 100644 index 00000000000..5926bd6820e --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWithIndexingWriter.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class LiteralWithIndexingWriter extends IndexNameValueWriter { + + private boolean tableUpdated; + + private CharSequence name; + private CharSequence value; + private int index; + + LiteralWithIndexingWriter() { + super(0b0100_0000, 6); + } + + @Override + LiteralWithIndexingWriter index(int index) { + super.index(index); + this.index = index; + return this; + } + + @Override + LiteralWithIndexingWriter name(CharSequence name, boolean useHuffman) { + super.name(name, useHuffman); + this.name = name; + return this; + } + + @Override + LiteralWithIndexingWriter value(CharSequence value, boolean useHuffman) { + super.value(value, useHuffman); + this.value = value; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!tableUpdated) { + CharSequence n; + if (indexedRepresentation) { + n = table.get(index).name; + } else { + n = name; + } + table.put(n, value); + tableUpdated = true; + } + return super.write(table, destination); + } + + @Override + public IndexNameValueWriter reset() { + tableUpdated = false; + name = null; + value = null; + index = -1; + return super.reset(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java similarity index 52% rename from jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java rename to jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java index 8746ee0a161..430dac4a384 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/LiteralWriter.java @@ -22,39 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.internal.jrtfs; +package sun.net.httpclient.hpack; -/** - * Path implementation for jrt file system on JDK exploded modules build. - * - * @implNote This class needs to maintain JDK 8 source compatibility. - * - * It is used internally in the JDK to implement jimage/jrtfs access, - * but also compiled and delivered as part of the jrtfs.jar to support access - * to the jimage file provided by the shipped JDK by tools running on JDK 8. - */ -final class JrtExplodedPath extends AbstractJrtPath { +final class LiteralWriter extends IndexNameValueWriter { - JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path) { - super(jrtfs, path); - } - - JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) { - super(jrtfs, path, normalized); - } - - @Override - protected AbstractJrtPath newJrtPath(byte[] path) { - return new JrtExplodedPath(jrtfs, path); - } - - @Override - protected AbstractJrtPath newJrtPath(byte[] path, boolean normalized) { - return new JrtExplodedPath(jrtfs, path, normalized); - } - - @Override - public JrtExplodedFileSystem getFileSystem() { - return (JrtExplodedFileSystem) jrtfs; + LiteralWriter() { + super(0b0000_0000, 4); } } diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java new file mode 100644 index 00000000000..5148afeeddc --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/SizeUpdateWriter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; + +final class SizeUpdateWriter implements BinaryRepresentationWriter { + + private final IntegerWriter intWriter = new IntegerWriter(); + private int maxSize; + private boolean tableUpdated; + + SizeUpdateWriter() { } + + SizeUpdateWriter maxHeaderTableSize(int size) { + intWriter.configure(size, 5, 0b0010_0000); + this.maxSize = size; + return this; + } + + @Override + public boolean write(HeaderTable table, ByteBuffer destination) { + if (!tableUpdated) { + table.setMaxSize(maxSize); + tableUpdated = true; + } + return intWriter.write(destination); + } + + @Override + public BinaryRepresentationWriter reset() { + intWriter.reset(); + maxSize = -1; + tableUpdated = false; + return this; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java new file mode 100644 index 00000000000..e2bbefb1473 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringReader.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +// +// 0 1 2 3 4 5 6 7 +// +---+---+---+---+---+---+---+---+ +// | H | String Length (7+) | +// +---+---------------------------+ +// | String Data (Length octets) | +// +-------------------------------+ +// +final class StringReader { + + private static final int NEW = 0; + private static final int FIRST_BYTE_READ = 1; + private static final int LENGTH_READ = 2; + private static final int DONE = 4; + + private final IntegerReader intReader = new IntegerReader(); + private final Huffman.Reader huffmanReader = new Huffman.Reader(); + private final ISO_8859_1.Reader plainReader = new ISO_8859_1.Reader(); + + private int state = NEW; + + private boolean huffman; + private int remainingLength; + + boolean read(ByteBuffer input, Appendable output) { + if (state == DONE) { + return true; + } + if (!input.hasRemaining()) { + return false; + } + if (state == NEW) { + int p = input.position(); + huffman = (input.get(p) & 0b10000000) != 0; + state = FIRST_BYTE_READ; + intReader.configure(7); + } + if (state == FIRST_BYTE_READ) { + boolean lengthRead = intReader.read(input); + if (!lengthRead) { + return false; + } + remainingLength = intReader.get(); + state = LENGTH_READ; + } + if (state == LENGTH_READ) { + boolean isLast = input.remaining() >= remainingLength; + int oldLimit = input.limit(); + if (isLast) { + input.limit(input.position() + remainingLength); + } + if (huffman) { + huffmanReader.read(input, output, isLast); + } else { + plainReader.read(input, output); + } + if (isLast) { + input.limit(oldLimit); + } + return isLast; + } + throw new InternalError(Arrays.toString( + new Object[]{state, huffman, remainingLength})); + } + + boolean isHuffmanEncoded() { + if (state < FIRST_BYTE_READ) { + throw new IllegalStateException("Has not been fully read yet"); + } + return huffman; + } + + void reset() { + if (huffman) { + huffmanReader.reset(); + } else { + plainReader.reset(); + } + intReader.reset(); + state = NEW; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java new file mode 100644 index 00000000000..5c58e371082 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/StringWriter.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +// +// 0 1 2 3 4 5 6 7 +// +---+---+---+---+---+---+---+---+ +// | H | String Length (7+) | +// +---+---------------------------+ +// | String Data (Length octets) | +// +-------------------------------+ +// +// StringWriter does not require a notion of endOfInput (isLast) in 'write' +// methods due to the nature of string representation in HPACK. Namely, the +// length of the string is put before string's contents. Therefore the length is +// always known beforehand. +// +// Expected use: +// +// configure write* (reset configure write*)* +// +final class StringWriter { + + private static final int NEW = 0; + private static final int CONFIGURED = 1; + private static final int LENGTH_WRITTEN = 2; + private static final int DONE = 4; + + private final IntegerWriter intWriter = new IntegerWriter(); + private final Huffman.Writer huffmanWriter = new Huffman.Writer(); + private final ISO_8859_1.Writer plainWriter = new ISO_8859_1.Writer(); + + private int state = NEW; + private boolean huffman; + + StringWriter configure(CharSequence input, boolean huffman) { + return configure(input, 0, input.length(), huffman); + } + + StringWriter configure(CharSequence input, int start, int end, + boolean huffman) { + if (start < 0 || end < 0 || end > input.length() || start > end) { + throw new IndexOutOfBoundsException( + String.format("input.length()=%s, start=%s, end=%s", + input.length(), start, end)); + } + if (!huffman) { + plainWriter.configure(input, start, end); + intWriter.configure(end - start, 7, 0b0000_0000); + } else { + huffmanWriter.from(input, start, end); + intWriter.configure(Huffman.INSTANCE.lengthOf(input, start, end), + 7, 0b1000_0000); + } + + this.huffman = huffman; + state = CONFIGURED; + return this; + } + + boolean write(ByteBuffer output) { + if (state == DONE) { + return true; + } + if (state == NEW) { + throw new IllegalStateException("Configure first"); + } + if (!output.hasRemaining()) { + return false; + } + if (state == CONFIGURED) { + if (intWriter.write(output)) { + state = LENGTH_WRITTEN; + } else { + return false; + } + } + if (state == LENGTH_WRITTEN) { + boolean written = huffman + ? huffmanWriter.write(output) + : plainWriter.write(output); + if (written) { + state = DONE; + return true; + } else { + return false; + } + } + throw new InternalError(Arrays.toString(new Object[]{state, huffman})); + } + + void reset() { + intWriter.reset(); + if (huffman) { + huffmanWriter.reset(); + } else { + plainWriter.reset(); + } + state = NEW; + } +} diff --git a/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java new file mode 100644 index 00000000000..5c035ff4662 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/sun/net/httpclient/hpack/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * HPACK (Header Compression for HTTP/2) implementation conforming to + * RFC 7541. + * + *

Headers can be decoded and encoded by {@link sun.net.httpclient.hpack.Decoder} + * and {@link sun.net.httpclient.hpack.Encoder} respectively. + * + *

Instances of these classes are not safe for use by multiple threads. + */ +package sun.net.httpclient.hpack; diff --git a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java index 81f3387be8c..e15add5a4f8 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -42,7 +42,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; import sun.util.logging.internal.LoggingProviderImpl; /** @@ -254,9 +253,10 @@ public class LogManager { // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. - private class Cleaner extends ManagedLocalsThread { + private class Cleaner extends Thread { private Cleaner() { + super(null, null, "Logging-Cleaner", 0, false); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java index 07b06fd38c3..d8ada0c4c08 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java @@ -38,8 +38,8 @@ import java.util.Objects; import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** * A Logger object is used to log messages for a specific diff --git a/jdk/src/java.logging/share/classes/module-info.java b/jdk/src/java.logging/share/classes/module-info.java index 0deda7677b5..47456e5ef5b 100644 --- a/jdk/src/java.logging/share/classes/module-info.java +++ b/jdk/src/java.logging/share/classes/module-info.java @@ -24,8 +24,6 @@ */ module java.logging { - // 8153158 - requires jdk.unsupported; exports java.util.logging; provides jdk.internal.logger.DefaultLoggerFinder with sun.util.logging.internal.LoggingProviderImpl; diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java index 85f248311cb..5df5c243782 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java @@ -30,7 +30,6 @@ import java.io.InterruptedIOException; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; -import sun.misc.ManagedLocalsThread; public abstract class ClientCommunicatorAdmin { private static volatile long threadNo = 1; @@ -41,10 +40,11 @@ public abstract class ClientCommunicatorAdmin { if (period > 0) { checker = new Checker(); - Thread t = new ManagedLocalsThread( - checker, - "JMX client heartbeat " + (++threadNo) - ); + Thread t = new Thread(null, + checker, + "JMX client heartbeat " + (++threadNo), + 0, + false); t.setDaemon(true); t.start(); diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java index 05abd0ceeb5..e0860f8e1f0 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java @@ -52,7 +52,6 @@ import javax.management.remote.TargetedNotification; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.rmi.UnmarshalException; -import sun.misc.ManagedLocalsThread; public abstract class ClientNotifForwarder { @@ -91,7 +90,8 @@ public abstract class ClientNotifForwarder { throw new IllegalArgumentException("More than one command"); this.command = command; if (thread == null) { - thread = new ManagedLocalsThread( + thread = new Thread( + null, ()-> { while (true) { Runnable r; @@ -107,7 +107,9 @@ public abstract class ClientNotifForwarder { r.run(); } }, - "ClientNotifForwarder-" + ++threadId + "ClientNotifForwarder-" + ++threadId, + 0, + false ); thread.setDaemon(true); thread.start(); diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java index 6df86f5931b..74fbbd4c329 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java @@ -27,7 +27,6 @@ package com.sun.jmx.remote.internal; import com.sun.jmx.remote.util.ClassLogger; -import sun.misc.ManagedLocalsThread; public abstract class ServerCommunicatorAdmin { public ServerCommunicatorAdmin(long timeout) { @@ -42,7 +41,11 @@ public abstract class ServerCommunicatorAdmin { timestamp = 0; if (timeout < Long.MAX_VALUE) { Runnable timeoutTask = new Timeout(); - final Thread t = new ManagedLocalsThread(timeoutTask); + final Thread t = new Thread(null, + timeoutTask, + "JMX-Server-Admin-Timeout", + 0, + false); t.setName("JMX server connection timeout " + t.getId()); // If you change this name you will need to change a unit test // (NoServerTimeoutTest) diff --git a/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java b/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java index 6276fb33b50..eb2a59ac14a 100644 --- a/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java +++ b/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java @@ -61,7 +61,6 @@ import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; import javax.management.ReflectionException; import static javax.management.monitor.MonitorNotification.*; -import sun.misc.ManagedLocalsThread; /** * Defines the part common to all monitor MBeans. @@ -1637,10 +1636,12 @@ public abstract class Monitor } public Thread newThread(Runnable r) { - Thread t = new ManagedLocalsThread( + Thread t = new Thread( group, r, - namePrefix + threadNumber.getAndIncrement() + nameSuffix + namePrefix + threadNumber.getAndIncrement() + nameSuffix, + 0, + false ); t.setDaemon(true); diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index fe90422c193..a71bef5b403 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; +import javax.management.remote.JMXAuthenticator; import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnector; @@ -99,6 +100,21 @@ public class RMIConnectorServer extends JMXConnectorServer { public static final String RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE = "jmx.remote.rmi.server.socket.factory"; + /** + * Name of the attribute that specifies a list of class names acceptable + * as parameters to the {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()} + * remote method call. + *

+ * This list of classes should correspond to the transitive closure of the + * credentials class (or classes) used by the installed {@linkplain JMXAuthenticator} + * associated with the {@linkplain RMIServer} implementation. + *

+ * If the attribute is not set, or is null, then any class is + * deemed acceptable. + */ + public static final String CREDENTIAL_TYPES = + "jmx.remote.rmi.server.credential.types"; + /** *

Makes an RMIConnectorServer. * This is equivalent to calling {@link #RMIConnectorServer( diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java index 0e45c966c9c..838c092ca48 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,13 @@ import javax.security.auth.Subject; import com.sun.jmx.remote.internal.RMIExporter; import com.sun.jmx.remote.util.EnvHelp; +import java.io.ObjectStreamClass; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import sun.reflect.misc.ReflectUtil; +import sun.rmi.server.DeserializationChecker; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; @@ -52,6 +59,9 @@ import sun.rmi.server.UnicastServerRef2; * @since 1.5 */ public class RMIJRMPServerImpl extends RMIServerImpl { + + private final ExportedWrapper exportedWrapper; + /** *

Creates a new {@link RMIServer} object that will be exported * on the given port using the given socket factories.

@@ -89,10 +99,31 @@ public class RMIJRMPServerImpl extends RMIServerImpl { this.csf = csf; this.ssf = ssf; this.env = (env == null) ? Collections.emptyMap() : env; + + String[] credentialsTypes + = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES); + List types = null; + if (credentialsTypes != null) { + types = new ArrayList<>(); + for (String type : credentialsTypes) { + if (type == null) { + throw new IllegalArgumentException("A credential type is null."); + } + ReflectUtil.checkPackageAccess(type); + types.add(type); + } + } + exportedWrapper = types != null ? + new ExportedWrapper(this, types) : + null; } protected void export() throws IOException { - export(this); + if (exportedWrapper != null) { + export(exportedWrapper); + } else { + export(this); + } } private void export(Remote obj) throws RemoteException { @@ -142,7 +173,11 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * RMIJRMPServerImpl has not been exported yet. */ public Remote toStub() throws IOException { - return RemoteObject.toStub(this); + if (exportedWrapper != null) { + return RemoteObject.toStub(exportedWrapper); + } else { + return RemoteObject.toStub(this); + } } /** @@ -189,11 +224,56 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * server failed. */ protected void closeServer() throws IOException { - unexport(this, true); + if (exportedWrapper != null) { + unexport(exportedWrapper, true); + } else { + unexport(this, true); + } } private final int port; private final RMIClientSocketFactory csf; private final RMIServerSocketFactory ssf; private final Map env; + + private static class ExportedWrapper implements RMIServer, DeserializationChecker { + private final RMIServer impl; + private final List allowedTypes; + + private ExportedWrapper(RMIServer impl, List credentialsTypes) { + this.impl = impl; + allowedTypes = credentialsTypes; + } + + @Override + public String getVersion() throws RemoteException { + return impl.getVersion(); + } + + @Override + public RMIConnection newClient(Object credentials) throws IOException { + return impl.newClient(credentials); + } + + @Override + public void check(Method method, ObjectStreamClass descriptor, + int paramIndex, int callID) { + String type = descriptor.getName(); + if (!allowedTypes.contains(type)) { + throw new ClassCastException("Unsupported type: " + type); + } + } + + @Override + public void checkProxyClass(Method method, String[] ifaces, + int paramIndex, int callID) { + if (ifaces != null && ifaces.length > 0) { + for (String iface : ifaces) { + if (!allowedTypes.contains(iface)) { + throw new ClassCastException("Unsupported type: " + iface); + } + } + } + } + } } diff --git a/jdk/src/java.management/share/classes/module-info.java b/jdk/src/java.management/share/classes/module-info.java index 811c2de91bd..8f7bd1b909e 100644 --- a/jdk/src/java.management/share/classes/module-info.java +++ b/jdk/src/java.management/share/classes/module-info.java @@ -27,8 +27,6 @@ module java.management { requires public java.rmi; requires java.logging; requires java.naming; - // 8147553 - requires jdk.unsupported; exports java.lang.management; exports javax.management; diff --git a/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java b/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java index 344d2db2b9e..f96227ce471 100644 --- a/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java +++ b/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java @@ -34,7 +34,6 @@ import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.Method; import sun.management.VMManagement; -import sun.misc.ManagedLocalsThread; /** * JdpController is responsible to create and manage a broadcast loop. @@ -219,7 +218,7 @@ public final class JdpController { controller = new JDPControllerRunner(bcast, packet, pause); - Thread t = new ManagedLocalsThread(controller, "JDP broadcaster"); + Thread t = new Thread(null, controller, "JDP broadcaster", 0, false); t.setDaemon(true); t.start(); } diff --git a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java index 5ef0f7f1708..477b7786421 100644 --- a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java +++ b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java @@ -510,6 +510,9 @@ public final class ConnectorBootstrap { // This RMI server should not keep the VM alive Map env = new HashMap<>(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter()); + env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); // The local connector server need only be available via the // loopback connection. @@ -740,6 +743,9 @@ public final class ConnectorBootstrap { PermanentExporter exporter = new PermanentExporter(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter); + env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); boolean useSocketFactory = bindAddress != null && !useSsl; diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java index b810187c649..6f642607500 100644 --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,7 +92,12 @@ final class LdapReferralContext implements DirContext, LdapContext { try { referral = refEx.getNextReferral(); if (referral == null) { - throw (NamingException)(previousEx.fillInStackTrace()); + if (previousEx != null) { + throw (NamingException)(previousEx.fillInStackTrace()); + } else { + throw new NamingException( + "Illegal encoding: referral is empty"); + } } } catch (LdapReferralException e) { diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java new file mode 100644 index 00000000000..8182b10bfbe --- /dev/null +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.rmi.server; + +import java.io.ObjectStreamClass; +import java.lang.reflect.Method; + +/** + * Implementing this interface to have a deserialization control when RMI + * dispatches a remote request. If an exported object implements this interface, + * RMI dispatching mechanism will call the method {@code check} every time + * deserialising a remote object for invoking a method of the exported object. + * + * @author sjiang + */ +public interface DeserializationChecker { + /** + * Will be called to check a descriptor. + * This method may be called 2 times, the first time is when a descriptor is read + * from the stream, the second is just before creating an object described + * by this descriptor. + * + * @param method the method invoked from a remote request. + * @param descriptor The descriptor of the class of any object deserialised + * while deserialising the parameter. The first descriptor will be that of + * the top level object (the concrete class of the parameter itself); + * Subsequent calls with the same {@code method}, {@code paramIndex} and + * {@code callID} will correspond to objects contained in the parameter. + * @param paramIndex an index indicates the position of a parameter in the + * method. This index will be reused for deserialising all + * objects contained in the parameter object. For example, the parameter + * being deserialised is a {@code List}, all deserialisation calls for its + * elements will have same index. + * @param callID a unique ID identifying one + * time method invocation, the same ID is used for deserialization call of + * all parameters within the method. + */ + public void check(Method method, + ObjectStreamClass descriptor, + int paramIndex, + int callID); + + /** + * Will be called to validate a Proxy interfaces from a remote user before loading it. + * @param method the method invoked from a remote request. + * @param ifaces a string table of all interfaces implemented by the proxy to be checked. + * @param paramIndex an index indicates the position of a parameter in the + * method. This index will be reused for deserialising all + * objects contained in the parameter object. For example, the parameter + * being deserialised is a {@code List}, all deserialisation calls for its + * elements will have same index. + * @param callID a unique ID identifying one + * time method invocation, the same ID is used for deserialization call of + * all parameters within the method. + */ + public void checkProxyClass(Method method, + String[] ifaces, + int paramIndex, + int callID); + + /** + * Inform of the completion of parameter deserialisation for a method invocation. + * This is useful if the last parameter is a complex object, like a {@code List} + * which elements are complex object too. + * + * The default implementation does nothing. + * @param callID the ID identifying a method invocation. + */ + public default void end(int callID) {} +} diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java index 3453e61f517..59c0be3360e 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,13 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.io.StreamCorruptedException; -import java.net.URL; import java.util.*; import java.security.AccessControlException; import java.security.Permission; - import java.rmi.server.RMIClassLoader; import java.security.PrivilegedAction; +import jdk.internal.misc.ObjectStreamClassValidator; +import jdk.internal.misc.SharedSecrets; /** * MarshalInputStream is an extension of ObjectInputStream. When resolving @@ -54,6 +54,11 @@ import java.security.PrivilegedAction; * @author Peter Jones */ public class MarshalInputStream extends ObjectInputStream { + interface StreamChecker extends ObjectStreamClassValidator { + void checkProxyInterfaceNames(String[] ifaces); + } + + private volatile StreamChecker streamChecker = null; /** * Value of "java.rmi.server.useCodebaseOnly" property, @@ -123,7 +128,7 @@ public class MarshalInputStream extends ObjectInputStream { throws IOException, StreamCorruptedException { super(in); - } + } /** * Returns a callback previously registered via the setDoneCallback @@ -240,6 +245,11 @@ public class MarshalInputStream extends ObjectInputStream { protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { + StreamChecker checker = streamChecker; + if (checker != null) { + checker.checkProxyInterfaceNames(interfaces); + } + /* * Always read annotation written by MarshalOutputStream. */ @@ -319,4 +329,28 @@ public class MarshalInputStream extends ObjectInputStream { void useCodebaseOnly() { useCodebaseOnly = true; } + + synchronized void setStreamChecker(StreamChecker checker) { + streamChecker = checker; + SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker); + } + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, + ClassNotFoundException { + ObjectStreamClass descriptor = super.readClassDescriptor(); + + validateDesc(descriptor); + + return descriptor; + } + + private void validateDesc(ObjectStreamClass descriptor) { + StreamChecker checker; + synchronized (this) { + checker = streamChecker; + } + if (checker != null) { + checker.validateDescriptor(descriptor); + } + } } diff --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java index b608f237cf5..3c57aa4b2d2 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ package sun.rmi.server; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.PrintStream; +import java.io.ObjectStreamClass; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.MarshalException; @@ -52,6 +52,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; import sun.rmi.runtime.Log; import sun.rmi.transport.LiveRef; import sun.rmi.transport.Target; @@ -116,6 +117,8 @@ public class UnicastServerRef extends UnicastRef private static final Map,?> withoutSkeletons = Collections.synchronizedMap(new WeakHashMap,Void>()); + private final AtomicInteger methodCallIDCount = new AtomicInteger(0); + /** * Create a new (empty) Unicast server remote reference. */ @@ -297,14 +300,11 @@ public class UnicastServerRef extends UnicastRef logCall(obj, method); // unmarshal parameters - Class[] types = method.getParameterTypes(); - Object[] params = new Object[types.length]; + Object[] params = null; try { unmarshalCustomCallData(in); - for (int i = 0; i < types.length; i++) { - params[i] = unmarshalValue(types[i], in); - } + params = unmarshalParameters(obj, method, marshalStream); } catch (java.io.IOException e) { throw new UnmarshalException( "error unmarshalling arguments", e); @@ -565,4 +565,85 @@ public class UnicastServerRef extends UnicastRef return map; } } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Perform any necessary checks. + */ + private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + return (obj instanceof DeserializationChecker) ? + unmarshalParametersChecked((DeserializationChecker)obj, method, in) : + unmarshalParametersUnchecked(method, in); + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do not perform any additional checks. + */ + private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in) + throws IOException, ClassNotFoundException { + Class[] types = method.getParameterTypes(); + Object[] params = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + params[i] = unmarshalValue(types[i], in); + } + return params; + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do perform all additional checks. + */ + private Object[] unmarshalParametersChecked( + DeserializationChecker checker, + Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + int callID = methodCallIDCount.getAndIncrement(); + MyChecker myChecker = new MyChecker(checker, method, callID); + in.setStreamChecker(myChecker); + try { + Class[] types = method.getParameterTypes(); + Object[] values = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + myChecker.setIndex(i); + values[i] = unmarshalValue(types[i], in); + } + myChecker.end(callID); + return values; + } finally { + in.setStreamChecker(null); + } + } + + private static class MyChecker implements MarshalInputStream.StreamChecker { + private final DeserializationChecker descriptorCheck; + private final Method method; + private final int callID; + private int parameterIndex; + + MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) { + this.descriptorCheck = descriptorCheck; + this.method = method; + this.callID = callID; + } + + @Override + public void validateDescriptor(ObjectStreamClass descriptor) { + descriptorCheck.check(method, descriptor, parameterIndex, callID); + } + + @Override + public void checkProxyInterfaceNames(String[] ifaces) { + descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID); + } + + void setIndex(int parameterIndex) { + this.parameterIndex = parameterIndex; + } + + void end(int callId) { + descriptorCheck.end(callId); + } + } } diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java index ece97a92afd..3e664d7cccc 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/SunProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,8 +97,6 @@ public final class SunProvider extends Provider { } } - public static final SunProvider INSTANCE = new SunProvider(); - public SunProvider() { /* We are the Sun JGSS provider */ super("SunJGSS", 9.0d, INFO); diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java index d09ca8d6a16..3463fd69dfa 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java @@ -159,7 +159,9 @@ public class GSSNameElement implements GSSNameSpi { int atPos = krbName.lastIndexOf('@'); if (atPos != -1) { String atRealm = krbName.substring(atPos); - if (nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL) + // getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null + if ((nameType == null + || nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL)) && new String(nameBytes).endsWith(atRealm)) { // Created from Kerberos name with realm, no need to check } else { diff --git a/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java b/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java index c32e9d0eea4..a1abeac9763 100644 --- a/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/jdk/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -134,7 +134,7 @@ public class Klist { Character arg; for (int i = 0; i < args.length; i++) { if ((args[i].length() >= 2) && (args[i].startsWith("-"))) { - arg = new Character(args[i].charAt(1)); + arg = Character.valueOf(args[i].charAt(1)); switch (arg.charValue()) { case 'c': action = 'c'; diff --git a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java index b17cd507e9e..55179670edb 100644 --- a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java +++ b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java @@ -1963,7 +1963,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return (float)0; } try { - return ((new Float(value.toString())).floatValue()); + return Float.parseFloat(value.toString()); } catch (NumberFormatException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.floatfail").toString(), new Object[] {value.toString().trim(), columnIndex})); @@ -2007,7 +2007,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return (double)0; } try { - return ((new Double(value.toString().trim())).doubleValue()); + return Double.parseDouble(value.toString().trim()); } catch (NumberFormatException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.doublefail").toString(), new Object[] {value.toString().trim(), columnIndex})); @@ -4017,9 +4017,9 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern return new BigDecimal(srcObj.toString().trim()); case java.sql.Types.REAL: case java.sql.Types.FLOAT: - return new Float(srcObj.toString().trim()); + return Float.valueOf(srcObj.toString().trim()); case java.sql.Types.DOUBLE: - return new Double(srcObj.toString().trim()); + return Double.valueOf(srcObj.toString().trim()); case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: diff --git a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java index 7578c41d963..931f351a196 100644 --- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java +++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java @@ -30,8 +30,8 @@ import java.lang.reflect.*; import java.util.Arrays; import java.util.Vector; import javax.sql.rowset.RowSetWarning; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; /** @@ -141,7 +141,7 @@ public class SerialJavaObject implements Serializable, Cloneable { * Check if the caller is allowed to access the specified class's package. * If access is denied, throw a SecurityException. */ - Class caller = sun.reflect.Reflection.getCallerClass(); + Class caller = Reflection.getCallerClass(); if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), c.getClassLoader())) { ReflectUtil.checkPackageAccess(c); diff --git a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java index 331239e3733..5530fda159d 100644 --- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java +++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java @@ -36,8 +36,8 @@ import java.security.PrivilegedAction; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java index 224b5375283..bb762ad0b42 100644 --- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,11 @@ package com.sun.java.accessibility.util; -import java.lang.*; +import com.sun.java.accessibility.util.internal.*; import java.beans.*; import java.util.*; import java.awt.*; import java.awt.event.*; -import java.awt.image.*; -import java.security.AccessControlException; // Do not import Swing classes. This module is intended to work // with both Swing and AWT. // import javax.swing.*; @@ -77,12 +75,26 @@ public class Translator extends AccessibleContext if (c == null) { return null; } - try { - t = Class.forName("com.sun.java.accessibility.util.internal." - + c.getSimpleName() - + "Translator"); + switch (c.getSimpleName()) { + case "Button": + t = ButtonTranslator.class; + break; + case "Checkbox": + t = CheckboxTranslator.class; + break; + case "Label": + t = LabelTranslator.class; + break; + case "List": + t = ListTranslator.class; + break; + case "TextComponent": + t = TextComponentTranslator.class; + break; + } + if (t != null) { return t; - } catch (Exception e) { + } else { return getTranslatorClass(c.getSuperclass()); } } @@ -106,10 +118,6 @@ public class Translator extends AccessibleContext if (o instanceof Accessible) { a = (Accessible)o; } else { - // About to "newInstance" an object of a class of a restricted package - // so ensure the caller is allowed access to that package. - String pkg = "com.sun.java.accessibility.util.internal"; - System.getSecurityManager().checkPackageAccess(pkg); Class translatorClass = getTranslatorClass(o.getClass()); if (translatorClass != null) { try { diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp index b8602f52f0d..7943374892c 100644 --- a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -543,7 +543,7 @@ void Jaccesswalker::addComponentNodes(long vmID, AccessibleContext context, } else { char s[LINE_BUFSIZE]; sprintf( s, - "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %X", + "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %p", vmID, context ); TVITEM tvi; diff --git a/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp index 45b47071fcd..3fa8fc6f67c 100644 --- a/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1125,7 +1125,7 @@ WinAccessBridge::getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT6 PrintDebugString("WinAccessBridge::getAccessibleContextWithFocus(%p, %X, )", window, vmID); // find vmID, etc. from HWND; ask that VM for the AC w/Focus - HWND pkgVMID = (HWND)ABLongToHandle( pkg->rVMID ) ; + HWND pkgVMID; if (getAccessibleContextFromHWND(window, (long *)&(pkgVMID), &(pkg->rAccessibleContext)) == TRUE) { HWND destABWindow = javaVMs->findAccessBridgeWindow((long)pkgVMID); // ineffecient [[[FIXME]]] if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java b/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java index 065b8d2f000..07f4c1bf3e1 100644 --- a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,6 @@ module jdk.crypto.pkcs11 { // Depends on SunEC provider for EC related functionality requires jdk.crypto.ec; - // 8153371 - requires jdk.unsupported; provides java.security.Provider with sun.security.pkcs11.SunPKCS11; } diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java index bccddb41bd1..3aa2e69103f 100644 --- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java @@ -141,6 +141,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { } // see JCA spec + @Override public void initialize(int keySize, SecureRandom random) { token.ensureValid(); try { @@ -162,6 +163,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { } // see JCA spec + @Override public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { token.ensureValid(); @@ -173,7 +175,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { } DHParameterSpec dhParams = (DHParameterSpec) params; tmpKeySize = dhParams.getP().bitLength(); - checkKeySize(tmpKeySize, null); + checkKeySize(tmpKeySize, dhParams); // XXX sanity check params } else if (algorithm.equals("RSA")) { if (params instanceof RSAKeyGenParameterSpec == false) { @@ -195,7 +197,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { } DSAParameterSpec dsaParams = (DSAParameterSpec) params; tmpKeySize = dsaParams.getP().bitLength(); - checkKeySize(tmpKeySize, null); + checkKeySize(tmpKeySize, dsaParams); // XXX sanity check params } else if (algorithm.equals("EC")) { ECParameterSpec ecParams; @@ -220,7 +222,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ("ECParameterSpec or ECGenParameterSpec required for EC"); } tmpKeySize = ecParams.getCurve().getField().getFieldSize(); - checkKeySize(tmpKeySize, null); + checkKeySize(tmpKeySize, ecParams); } else { throw new ProviderException("Unknown algorithm: " + algorithm); } @@ -229,40 +231,45 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { this.random = random; } - // NOTE: 'params' is only used for checking RSA keys currently. - private void checkKeySize(int keySize, RSAKeyGenParameterSpec params) + private void checkKeySize(int keySize, AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { // check native range first if ((minKeySize != -1) && (keySize < minKeySize)) { throw new InvalidAlgorithmParameterException(algorithm + - " key must be at least " + minKeySize + " bits"); + " key must be at least " + minKeySize + " bits. " + + "The specific key size " + keySize + " is not supported"); } if ((maxKeySize != -1) && (keySize > maxKeySize)) { throw new InvalidAlgorithmParameterException(algorithm + - " key must be at most " + maxKeySize + " bits"); + " key must be at most " + maxKeySize + " bits. " + + "The specific key size " + keySize + " is not supported"); } // check our own algorithm-specific limits also if (algorithm.equals("EC")) { if (keySize < 112) { - throw new InvalidAlgorithmParameterException - ("Key size must be at least 112 bit"); + throw new InvalidAlgorithmParameterException( + "EC key size must be at least 112 bit. " + + "The specific key size " + keySize + " is not supported"); } if (keySize > 2048) { // sanity check, nobody really wants keys this large - throw new InvalidAlgorithmParameterException - ("Key size must be at most 2048 bit"); + throw new InvalidAlgorithmParameterException( + "EC key size must be at most 2048 bit. " + + "The specific key size " + keySize + " is not supported"); } } else { // RSA, DH, DSA if (keySize < 512) { - throw new InvalidAlgorithmParameterException - ("Key size must be at least 512 bit"); + throw new InvalidAlgorithmParameterException(algorithm + + " key size must be at least 512 bit. " + + "The specific key size " + keySize + " is not supported"); } if (algorithm.equals("RSA")) { BigInteger tmpExponent = rsaPublicExponent; if (params != null) { - tmpExponent = params.getPublicExponent(); + tmpExponent = + ((RSAKeyGenParameterSpec)params).getPublicExponent(); } try { // Reuse the checking in SunRsaSign provider. @@ -272,31 +279,55 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { minKeySize, (maxKeySize==-1? Integer.MAX_VALUE:maxKeySize)); } catch (InvalidKeyException e) { - throw new InvalidAlgorithmParameterException(e.getMessage()); + throw new InvalidAlgorithmParameterException(e); } - } else { - if (algorithm.equals("DH") && (params != null)) { + } else if (algorithm.equals("DH")) { + if (params != null) { // initialized with specified parameters // sanity check, nobody really wants keys this large if (keySize > 64 * 1024) { - throw new InvalidAlgorithmParameterException - ("Key size must be at most 65536 bit"); + throw new InvalidAlgorithmParameterException( + "DH key size must be at most 65536 bit. " + + "The specific key size " + + keySize + " is not supported"); } - } else { - // this restriction is in the spec for DSA - // since we currently use DSA parameters for DH as well, - // it also applies to DH if no parameters are specified - if ((keySize != 2048) && + } else { // default parameters will be used. + // Range is based on the values in + // sun.security.provider.ParameterCache class. + if ((keySize > 8192) || (keySize < 512) || + ((keySize & 0x3f) != 0)) { + throw new InvalidAlgorithmParameterException( + "DH key size must be multiple of 64, and can " + + "only range from 512 to 8192 (inclusive). " + + "The specific key size " + + keySize + " is not supported"); + } + + DHParameterSpec cache = + ParameterCache.getCachedDHParameterSpec(keySize); + // Except 2048 and 3072, not yet support generation of + // parameters bigger than 1024 bits. + if ((cache == null) && (keySize > 1024)) { + throw new InvalidAlgorithmParameterException( + "Unsupported " + keySize + + "-bit DH parameter generation"); + } + } + } else { + // this restriction is in the spec for DSA + if ((keySize != 3072) && (keySize != 2048) && ((keySize > 1024) || ((keySize & 0x3f) != 0))) { - throw new InvalidAlgorithmParameterException(algorithm + - " key must be multiples of 64 if less than 1024 bits" + - ", or 2048 bits"); - } + throw new InvalidAlgorithmParameterException( + "DSA key must be multiples of 64 if less than " + + "1024 bits, or 2048, 3072 bits. " + + "The specific key size " + + keySize + " is not supported"); } } } } // see JCA spec + @Override public KeyPair generateKeyPair() { token.ensureValid(); CK_ATTRIBUTE[] publicKeyTemplate; diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java index de0bef55897..890587ad790 100644 --- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ import javax.security.auth.callback.ConfirmationCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.TextOutputCallback; -import sun.misc.ManagedLocalsThread; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; @@ -816,7 +815,7 @@ public final class SunPKCS11 extends AuthProvider { return; } final TokenPoller poller = new TokenPoller(this); - Thread t = new ManagedLocalsThread(poller, "Poller " + getName()); + Thread t = new Thread(null, poller, "Poller " + getName(), 0, false); t.setDaemon(true); t.setPriority(Thread.MIN_PRIORITY); t.start(); diff --git a/jdk/src/jdk.httpserver/share/classes/module-info.java b/jdk/src/jdk.httpserver/share/classes/module-info.java index e71e6a3f3c8..e26758b66e9 100644 --- a/jdk/src/jdk.httpserver/share/classes/module-info.java +++ b/jdk/src/jdk.httpserver/share/classes/module-info.java @@ -25,8 +25,7 @@ module jdk.httpserver { requires java.logging; - // 8153372 - requires jdk.unsupported; + exports com.sun.net.httpserver; exports com.sun.net.httpserver.spi; uses com.sun.net.httpserver.spi.HttpServerProvider; diff --git a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java index 1c3ac29f936..a8566e8f7b6 100644 --- a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java +++ b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java @@ -36,7 +36,6 @@ import javax.net.ssl.*; import com.sun.net.httpserver.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.ManagedLocalsThread; import sun.net.httpserver.HttpConnection.State; /** @@ -143,7 +142,7 @@ class ServerImpl implements TimeSource { if (executor == null) { executor = new DefaultExecutor(); } - dispatcherThread = new ManagedLocalsThread(dispatcher); + dispatcherThread = new Thread(null, dispatcher, "HTTP-Dispatcher", 0, false); started = true; dispatcherThread.start(); } diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java index a9aece44e30..c49cdf55502 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionExecuter.java @@ -83,14 +83,14 @@ public class ExpressionExecuter implements ExpressionEvaluator { if (op == null) { return evaluate(l); } else { - Double lval = new Double(((Number)evaluate(l)).doubleValue()); - Double rval = new Double(((Number)evaluate(r)).doubleValue()); - double result = op.eval(lval.doubleValue(), rval.doubleValue()); + double lval = ((Number)evaluate(l)).doubleValue(); + double rval = ((Number)evaluate(r)).doubleValue(); + double result = op.eval(lval, rval); if (debug) { System.out.println("Performed Operation: " + lval + op + rval + " = " + result); } - return new Double(result); + return Double.valueOf(result); } } } diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java index c0e198438c6..63505988b8e 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java @@ -71,7 +71,7 @@ public class ExpressionResolver implements ExpressionEvaluator { if (m == null) { System.err.println("Warning: Unresolved Symbol: " + id.getName() + " substituted NaN"); - return new Literal(new Double(Double.NaN)); + return new Literal(Double.valueOf(Double.NaN)); } if (m.getVariability() == Variability.CONSTANT) { if (debug) { @@ -105,7 +105,7 @@ public class ExpressionResolver implements ExpressionEvaluator { Literal rl = (Literal)r; boolean warn = false; - Double nan = new Double(Double.NaN); + Double nan = Double.valueOf(Double.NaN); if (ll.getValue() instanceof String) { warn = true; ll.setValue(nan); } @@ -129,7 +129,7 @@ public class ExpressionResolver implements ExpressionEvaluator { + " (right = " + rn.doubleValue() + ")" + " to literal value " + result); } - return new Literal(new Double(result)); + return new Literal(Double.valueOf(result)); } } diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java index 33b17b95323..a9f9b203e20 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java @@ -324,7 +324,7 @@ public class Parser { case StreamTokenizer.TT_NUMBER: double literal = lookahead.nval; matchNumber(); - e = new Literal(new Double(literal)); + e = new Literal(Double.valueOf(literal)); log(pdebug, "Parsed: number -> " + literal); break; default: @@ -360,7 +360,7 @@ public class Parser { e1.setOperator(op); e1.setRight(e); log(pdebug, "Parsed: unary -> " + e1); - e1.setLeft(new Literal(new Double(0))); + e1.setLeft(new Literal(Double.valueOf(0))); e = e1; } } diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java index 11a376e0f22..5e6438d887a 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java @@ -478,7 +478,7 @@ class Commands { ThreadGroupReference tg = it.nextThreadGroup(); ++cnt; MessageOutput.println("thread group number description name", - new Object [] { new Integer (cnt), + new Object [] { Integer.valueOf(cnt), Env.description(tg), tg.name()}); } @@ -1014,7 +1014,7 @@ class Commands { return MessageOutput.format("locationString", new Object [] {loc.declaringType().name(), loc.method().name(), - new Integer (loc.lineNumber()), + Integer.valueOf(loc.lineNumber()), Long.valueOf(loc.codeIndex())}); } @@ -1467,7 +1467,7 @@ class Commands { MessageOutput.println("Line number information not available for"); } else if (Env.sourceLine(loc, lineno) == null) { MessageOutput.println("is an invalid line number for", - new Object [] {new Integer (lineno), + new Object [] {Integer.valueOf(lineno), refType.name()}); } else { for (int i = startLine; i <= endLine; i++) { @@ -1477,11 +1477,11 @@ class Commands { } if (i == lineno) { MessageOutput.println("source line number current line and line", - new Object [] {new Integer (i), + new Object [] {Integer.valueOf(i), sourceLine}); } else { MessageOutput.println("source line number and line", - new Object [] {new Integer (i), + new Object [] {Integer.valueOf(i), sourceLine}); } } @@ -1724,7 +1724,7 @@ class Commands { } else { MessageOutput.println("Owned by:", new Object [] {owner.name(), - new Integer (object.entryCount())}); + Integer.valueOf(object.entryCount())}); } List waiters = object.waitingThreads(); if (waiters.size() == 0) { diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java index 8de0675183c..ac3decf432a 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/MessageOutput.java @@ -198,7 +198,7 @@ public class MessageOutput { (MessageOutput.format("jdb prompt thread name and current stack frame", new Object [] { threadInfo.getThread().name(), - new Integer (threadInfo.getCurrentFrameIndex() + 1)})); + Integer.valueOf(threadInfo.getCurrentFrameIndex() + 1)})); } System.out.flush(); } diff --git a/jdk/src/jdk.rmic/share/classes/module-info.java b/jdk/src/jdk.rmic/share/classes/module-info.java index 43578b83fb0..de865a2bd29 100644 --- a/jdk/src/jdk.rmic/share/classes/module-info.java +++ b/jdk/src/jdk.rmic/share/classes/module-info.java @@ -27,6 +27,5 @@ module jdk.rmic { requires java.corba; requires jdk.compiler; requires jdk.javadoc; - exports jdk.rmi.rmic; } diff --git a/jdk/src/jdk.unsupported/share/classes/module-info.java b/jdk/src/jdk.unsupported/share/classes/module-info.java index e83c5012b69..a13d3428022 100644 --- a/jdk/src/jdk.unsupported/share/classes/module-info.java +++ b/jdk/src/jdk.unsupported/share/classes/module-info.java @@ -25,6 +25,6 @@ module jdk.unsupported { exports sun.misc; - //exports sun.reflect; + exports sun.reflect; } diff --git a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java index c69b66020ab..a2ff7add481 100644 --- a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java +++ b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java @@ -27,8 +27,8 @@ package sun.misc; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.misc.VM; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; import java.lang.reflect.Field; import java.security.ProtectionDomain; @@ -55,7 +55,7 @@ import java.security.ProtectionDomain; public final class Unsafe { static { - sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); + Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); } private Unsafe() {} diff --git a/jdk/src/jdk.unsupported/share/classes/sun/reflect/Reflection.java b/jdk/src/jdk.unsupported/share/classes/sun/reflect/Reflection.java new file mode 100644 index 00000000000..29d864557ac --- /dev/null +++ b/jdk/src/jdk.unsupported/share/classes/sun/reflect/Reflection.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.reflect; + +public class Reflection { + + private Reflection() { } + + /** + * @deprecated This method is an internal API and will be removed. + * Use {@link StackWalker} to walk the stack and obtain the caller class + * with {@link StackWalker.StackFrame#getDeclaringClass} instead. + */ + @Deprecated(forRemoval=true) + public static Class getCallerClass(int depth) { + if (depth < 0) + throw new InternalError("depth must be positive"); + + // increase depth to account for delegation to the internal impl + return jdk.internal.reflect.Reflection.getCallerClass(depth + 1); + } +} diff --git a/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java new file mode 100644 index 00000000000..85f4e4cb299 --- /dev/null +++ b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.reflect; + +import java.lang.reflect.Constructor; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; + +public class ReflectionFactory { + + private static final ReflectionFactory soleInstance = new ReflectionFactory(); + private final jdk.internal.reflect.ReflectionFactory delegate; + + private ReflectionFactory() { + delegate = AccessController.doPrivileged( + new PrivilegedAction() { + public jdk.internal.reflect.ReflectionFactory run() { + return jdk.internal.reflect.ReflectionFactory.getReflectionFactory(); + } + }); + } + + private static final Permission REFLECTION_FACTORY_ACCESS_PERM + = new RuntimePermission("reflectionFactoryAccess"); + + /** + * Provides the caller with the capability to instantiate reflective + * objects. + * + *

First, if there is a security manager, its {@code checkPermission} + * method is called with a {@link java.lang.RuntimePermission} with target + * {@code "reflectionFactoryAccess"}. This may result in a securit + * exception. + * + *

The returned {@code ReflectionFactory} object should be carefully + * guarded by the caller, since it can be used to read and write private + * data and invoke private methods, as well as to load unverified bytecodes. + * It must never be passed to untrusted code. + * + * @throws SecurityException if a security manager exists and its + * {@code checkPermission} method doesn't allow access to + * the RuntimePermission "reflectionFactoryAccess". + */ + public static ReflectionFactory getReflectionFactory() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(REFLECTION_FACTORY_ACCESS_PERM); + } + return soleInstance; + } + + public Constructor newConstructorForSerialization(Class classToInstantiate, + Constructor constructorToCall) + { + return delegate.newConstructorForSerialization(classToInstantiate, + constructorToCall); + } +} + diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 53deee5c732..673b0862d5c 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -32,7 +32,6 @@ tier1 = \ -java/util/WeakHashMap/GCDuringIteration.java \ -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ - -java/util/TimeZone/Bug6772689.java \ sun/nio/cs/ISO8859x.java \ java/nio/Buffer \ com/sun/crypto/provider/Cipher \ @@ -43,7 +42,6 @@ tier2 = \ java/util/WeakHashMap/GCDuringIteration.java \ java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ - java/util/TimeZone/Bug6772689.java \ :jdk_io \ :jdk_nio \ -sun/nio/cs/ISO8859x.java \ @@ -76,6 +74,7 @@ jdk_lang = \ sun/invoke \ sun/misc \ sun/reflect \ + jdk/internal/reflect \ jdk/lambda \ jdk/internal/misc \ jdk/internal/ref \ @@ -495,8 +494,8 @@ needs_jdk = \ sun/management/jmxremote/bootstrap/CustomLauncherTest.java \ sun/misc/JarIndex/metaInfFilenames/Basic.java \ sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java \ - sun/reflect/CallerSensitive/CallerSensitiveFinder.java \ - sun/reflect/CallerSensitive/MissingCallerSensitive.java \ + jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java \ + jdk/internal/reflect/CallerSensitive/MissingCallerSensitive.java \ sun/security/util/Resources/NewNamesFormat.java \ vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java \ javax/xml/ws/clientjar/TestWsImport.java \ diff --git a/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java b/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java new file mode 100644 index 00000000000..1faaa6783b4 --- /dev/null +++ b/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHKeys.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + */ + +import java.math.BigInteger; + +import java.security.*; +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +public class SupportedDHKeys { + + /* + * Sizes and values for various lengths. + */ + private enum SupportedKeySize { + dhp512(512), dhp768(768), dhp832(832), + dhp1024(1024), dhp1536(1536), dhp2048(2048), + dhp3072(3072), dhp4096(4096), dhp6144(6144), + dhp8192(8192); + + final int primeSize; + + SupportedKeySize(int primeSize) { + this.primeSize = primeSize; + } + } + + public static void main(String[] args) throws Exception { + for (SupportedKeySize keySize : SupportedKeySize.values()) { + System.out.println("Checking " + keySize.primeSize + " ..."); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); + kpg.initialize(keySize.primeSize); + KeyPair kp = kpg.generateKeyPair(); + checkKeyPair(kp, keySize.primeSize); + + DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); + BigInteger p = publicKey.getParams().getP(); + BigInteger g = publicKey.getParams().getG(); + kpg.initialize(new DHParameterSpec(p, g)); + kp = kpg.generateKeyPair(); + checkKeyPair(kp, keySize.primeSize); + } + } + + private static void checkKeyPair(KeyPair kp, int pSize) throws Exception { + + DHPrivateKey privateKey = (DHPrivateKey)kp.getPrivate(); + BigInteger p = privateKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + // System.out.println("P(" + pSize + "): " + p.toString()); + if (!p.isProbablePrime(128)) { + throw new Exception("Good luck, the modulus is composite!"); + } + + DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); + p = publicKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + BigInteger leftOpen = BigInteger.ONE; + BigInteger rightOpen = p.subtract(BigInteger.ONE); + + BigInteger x = privateKey.getX(); + if ((x.compareTo(leftOpen) <= 0) || + (x.compareTo(rightOpen) >= 0)) { + throw new Exception( + "X outside range [2, p - 2]: x: " + x + " p: " + p); + } + + BigInteger y = publicKey.getY(); + if ((y.compareTo(leftOpen) <= 0) || + (y.compareTo(rightOpen) >= 0)) { + throw new Exception( + "Y outside range [2, p - 2]: x: " + x + " p: " + p); + } + } +} diff --git a/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java b/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java new file mode 100644 index 00000000000..863563263ad --- /dev/null +++ b/jdk/test/com/sun/crypto/provider/KeyAgreement/SupportedDHParamGens.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + * @run main/timeout=300 SupportedDHParamGens 512 + * @run main/timeout=300 SupportedDHParamGens 768 + * @run main/timeout=300 SupportedDHParamGens 832 + * @run main/timeout=300 SupportedDHParamGens 1024 + * @run main/timeout=300 SupportedDHParamGens 2048 + * @run main/timeout=450 SupportedDHParamGens 3072 + */ + +import java.math.BigInteger; + +import java.security.*; +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +public class SupportedDHParamGens { + + public static void main(String[] args) throws Exception { + int primeSize = Integer.valueOf(args[0]).intValue(); + + System.out.println("Checking " + primeSize + " ..."); + AlgorithmParameterGenerator apg = + AlgorithmParameterGenerator.getInstance("DH", "SunJCE"); + apg.init(primeSize); + AlgorithmParameters ap = apg.generateParameters(); + DHParameterSpec spec = ap.getParameterSpec(DHParameterSpec.class); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); + kpg.initialize(spec); + KeyPair kp = kpg.generateKeyPair(); + checkKeyPair(kp, primeSize); + } + + private static void checkKeyPair(KeyPair kp, int pSize) throws Exception { + + DHPrivateKey privateKey = (DHPrivateKey)kp.getPrivate(); + BigInteger p = privateKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + if (!p.isProbablePrime(128)) { + throw new Exception("Good luck, the modulus is composite!"); + } + + DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); + p = publicKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + BigInteger leftOpen = BigInteger.ONE; + BigInteger rightOpen = p.subtract(BigInteger.ONE); + + BigInteger x = privateKey.getX(); + if ((x.compareTo(leftOpen) <= 0) || + (x.compareTo(rightOpen) >= 0)) { + throw new Exception( + "X outside range [2, p - 2]: x: " + x + " p: " + p); + } + + BigInteger y = publicKey.getY(); + if ((y.compareTo(leftOpen) <= 0) || + (y.compareTo(rightOpen) >= 0)) { + throw new Exception( + "Y outside range [2, p - 2]: x: " + x + " p: " + p); + } + } +} diff --git a/jdk/test/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java b/jdk/test/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java new file mode 100644 index 00000000000..d2ef5fab807 --- /dev/null +++ b/jdk/test/com/sun/crypto/provider/KeyAgreement/UnsupportedDHKeys.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + */ + +import java.math.BigInteger; + +import java.security.*; +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +public class UnsupportedDHKeys { + + /* + * Sizes and values for various lengths. + */ + private enum UnsupportedKeySize { + // not multiple of 64 + dhp513(513), dhp769(769), dhp895(895), + dhp1023(1023), dhp1535(1535), dhp2047(2047), + + // unsupported + dhp2176(2176), dhp3008(3008), dhp4032(4032), + dhp5120(5120), dhp6400(6400), dhp7680(7680), + dhp8191(8191), dhp8128(8128), dhp8260(8260); + + final int primeSize; + + UnsupportedKeySize(int primeSize) { + this.primeSize = primeSize; + } + } + + public static void main(String[] args) throws Exception { + for (UnsupportedKeySize keySize : UnsupportedKeySize.values()) { + try { + System.out.println("Checking " + keySize.primeSize + " ..."); + KeyPairGenerator kpg = + KeyPairGenerator.getInstance("DH", "SunJCE"); + kpg.initialize(keySize.primeSize); + + throw new Exception("Should not support " + keySize.primeSize); + } catch (InvalidParameterException ipe) { + System.out.println("\tOk, unsupported"); + } + } + } +} diff --git a/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..9c6317d9a7d --- /dev/null +++ b/jdk/test/java/awt/Button/ActionEventTest/ActionEventTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main/manual ActionEventTest + */ + +import java.awt.AWTException; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Button; +import java.awt.TextArea; +import java.awt.Robot; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +public class ActionEventTest extends Frame { + Button button; + Robot robot; + TextArea instructions; + public static boolean isProgInterruption = false; + static Thread mainThread = null; + static int sleepTime = 300000; + + public ActionEventTest() { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + + button = new Button("ClickMe"); + button.setEnabled(true); + + instructions = new TextArea(10, 50); + instructions.setText( + " This is a manual test\n" + + " Keep the Alt, Shift & Ctrl Keys pressed &\n" + + " Click 'ClickMe' button with left mouse button\n" + + " Test exits automatically after mouse click."); + + add(button); + add(instructions); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + isProgInterruption = true; + mainThread.interrupt(); + if ((md & expectedMask) != expectedMask) { + throw new RuntimeException("Action Event modifiers" + + " are not set correctly."); + } + } + }); + } + + public static void main(String args[]) throws Exception { + mainThread = Thread.currentThread(); + ActionEventTest test = new ActionEventTest(); + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException e) { + if (!isProgInterruption) { + throw e; + } + } + test.dispose(); + if (!isProgInterruption) { + throw new RuntimeException("Timed out after " + sleepTime / 1000 + + " seconds"); + } + } +} diff --git a/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java b/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java index 43a6d326702..cd74e128b7c 100644 --- a/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java +++ b/jdk/test/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java @@ -25,7 +25,7 @@ /* @test - @bug 6383903 + @bug 6383903 8144166 @summary REGRESSION: componentMoved is now getting called for some hidden components @author andrei.dmitriev: area=awt.component @run main CompEventOnHiddenComponent diff --git a/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java b/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java index d68b2e4409f..4dbff501d39 100644 --- a/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java +++ b/jdk/test/java/awt/FontClass/CreateFont/CreateFontArrayTest.java @@ -23,9 +23,9 @@ /* * @test - * @bug 8055463 + * @bug 8055463 8153272 * @summary Test createFont APIs - * @run CreateFontArrayTest + * @run main CreateFontArrayTest */ import java.awt.Font; diff --git a/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java b/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java new file mode 100644 index 00000000000..99b2595c41b --- /dev/null +++ b/jdk/test/java/awt/FontClass/TextRequiresLayoutTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146324 + * @summary Test Font.textRequiresLayout + */ + +import java.awt.Font; + +public class TextRequiresLayoutTest { + + public static void main(String args[]) { + + String simpleStr = "Hello World"; + String complexStr = "\u0641\u0642\u0643"; + char[] simpleChars = simpleStr.toCharArray(); + char[] complexChars = complexStr.toCharArray(); + + if (Font.textRequiresLayout(simpleChars, 0, simpleChars.length)) { + throw new RuntimeException("Simple text should not need layout"); + } + + if (!Font.textRequiresLayout(complexChars, 0, complexChars.length)) { + throw new RuntimeException("Complex text should need layout"); + } + + if (Font.textRequiresLayout(complexChars, 0, 0)) { + throw new RuntimeException("Empty text should not need layout"); + } + + boolean except = false; + try { + Font.textRequiresLayout(null, 0, 0); + } catch (NullPointerException npe) { + except = true; + } + if (!except) { + throw new RuntimeException("No expected IllegalArgumentException"); + } + + except = false; + try { + Font.textRequiresLayout(complexChars, -1, 0); + } catch (ArrayIndexOutOfBoundsException aioobe) { + except = true; + } + if (!except) { + throw new + RuntimeException("No expected ArrayIndexOutOfBoundsException"); + } + + except = false; + try { + Font.textRequiresLayout(complexChars, 0, complexChars.length+1); + } catch (ArrayIndexOutOfBoundsException aioobe) { + except = true; + } + if (!except) { + throw new + RuntimeException("No expected ArrayIndexOutOfBoundsException"); + } + } +} diff --git a/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..f1cd8e32a46 --- /dev/null +++ b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main ActionEventTest + */ + +import java.awt.AWTException; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +public class ActionEventTest extends Frame { + List list; + Robot robot; + + public ActionEventTest() { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + + list = new List(1, false); + list.add("0"); + add(list); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + } + + void performTest() { + list.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + if ((md & expectedMask) != expectedMask) { + + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + dispose(); + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + + list.select(0); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + // Press Enter on list item, to generate action event. + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + } + + public static void main(String args[]) { + ActionEventTest test = new ActionEventTest(); + test.performTest(); + test.dispose(); + } +} diff --git a/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java b/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java new file mode 100644 index 00000000000..c239b01360c --- /dev/null +++ b/jdk/test/java/awt/List/ItemEventTest/ItemEventTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8033936 + * @summary Verify that correct ItemEvent is received while selection & + * deselection of multi select List items. + */ + +import java.awt.AWTException; +import java.awt.Event; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +public class ItemEventTest extends Frame +{ + List list; + final String expectedSelectionOrder; + StringBuilder actualSelectionOrder; + Robot robot; + + public ItemEventTest() + { + try { + robot = new Robot(); + } catch(AWTException e) { + throw new RuntimeException(e.getMessage()); + } + expectedSelectionOrder = "01230123"; + + list = new List(4, true); + list.add("0"); + list.add("1"); + list.add("2"); + list.add("3"); + + add(list); + setSize(400,400); + setLayout(new FlowLayout()); + pack(); + setVisible(true); + robot.waitForIdle(); + } + + @Override + public boolean handleEvent(Event e) { + if (e.target instanceof List) { + if (e.id == Event.LIST_DESELECT || e.id == Event.LIST_SELECT) { + actualSelectionOrder.append(e.arg); + } + } + return true; + } + + void testHandleEvent() { + // When no ItemListener is added to List, parent's handleEvent is + // called with ItemEvent. + performTest(); + } + + void testItemListener() { + list.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent ie) { + actualSelectionOrder.append(ie.getItem()); + } + }); + performTest(); + } + + void performTest() { + actualSelectionOrder = new StringBuilder(); + Point loc = list.getLocationOnScreen(); + Rectangle rect = list.getBounds(); + int dY = rect.height / list.getItemCount(); + loc = new Point(loc.x + 10, loc.y + 5); + + String osName = System.getProperty("os.name"); + boolean isMac = osName.contains("Mac") || osName.contains("mac"); + if(isMac) { + robot.keyPress(KeyEvent.VK_META); + } + + // First loop to select & Second loop to deselect the list items. + for (int j = 0; j < 2; ++j) { + for (int i = 0; i < list.getItemCount(); ++i) { + robot.mouseMove(loc.x, loc.y + i * dY); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(100); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + } + } + + if(isMac) { + robot.keyRelease(KeyEvent.VK_META); + } + + if (!expectedSelectionOrder.equals(actualSelectionOrder.toString())) { + dispose(); + throw new RuntimeException("ItemEvent for selection & deselection" + + " of multi select List's item is not correct" + + " Expected : " + expectedSelectionOrder + + " Actual : " + actualSelectionOrder); + } + } + + public static void main(String args[]) { + ItemEventTest test = new ItemEventTest(); + test.testHandleEvent(); + test.testItemListener(); + test.dispose(); + } +} diff --git a/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..6af94798e31 --- /dev/null +++ b/jdk/test/java/awt/MenuBar/ActionEventTest/ActionEventTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @run main/manual ActionEventTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public final class ActionEventTest extends Frame { + + MenuBar menuBar; + TextArea instructions; + public static boolean isProgInterruption = false; + static Thread mainThread = null; + static int sleepTime = 300000; + + public ActionEventTest() { + menuBar = new MenuBar(); + Menu menu = new Menu("Menu1"); + MenuItem menuItem = new MenuItem("MenuItem"); + + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + System.out.println("actionPerformed"); + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + isProgInterruption = true; + mainThread.interrupt(); + if ((md & expectedMask) != expectedMask) { + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + menu.add(menuItem); + menuBar.add(menu); + setMenuBar(menuBar); + + instructions = new TextArea(10, 50); + instructions.setText( + " This is a manual test\n" + + " Keep the Alt, Shift & Ctrl Keys pressed while doing next steps\n" + + " Click 'Menu1' Menu from the Menu Bar\n" + + " It will show 'MenuItem'\n" + + " Left mouse Click the 'MenuItem'\n" + + " Test exits automatically after mouse click."); + add(instructions); + + setSize(400, 400); + setVisible(true); + validate(); + } + + + public static void main(final String[] args) throws Exception { + mainThread = Thread.currentThread(); + ActionEventTest test = new ActionEventTest(); + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException e) { + if (!isProgInterruption) { + throw e; + } + } + test.dispose(); + if (!isProgInterruption) { + throw new RuntimeException("Timed out after " + sleepTime / 1000 + + " seconds"); + } + } +} diff --git a/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java b/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java new file mode 100644 index 00000000000..186b9a6d8ba --- /dev/null +++ b/jdk/test/java/awt/PrintJob/JobAttrUpdateTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + /* + * @test + * @bug 6357905 + * @summary JobAttributes.getFromPage() and getToPage() always returns 1 + * @run main/manual JobAttrUpdateTest + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.JobAttributes; +import java.awt.PrintJob; +import java.awt.Toolkit; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class JobAttrUpdateTest { + + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + doTest(JobAttrUpdateTest::printTest); + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("" + + "JobAttributes.getFromPage(),getToPage() not updated correctly"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + private static void printTest() { + JobAttributes ja = new JobAttributes(); + + Toolkit tk = Toolkit.getDefaultToolkit(); + // ja.setToPage(4); + // ja.setFromPage(3); + // show dialog + PrintJob pjob = tk.getPrintJob(new JFrame(), "test", ja, null); + if (pjob == null) { + return; + } + + + if (ja.getDefaultSelection() == JobAttributes.DefaultSelectionType.RANGE) { + int fromPage = ja.getFromPage(); + int toPage = ja.getToPage(); + if (fromPage != 2 || toPage != 3) { + fail(); + } else { + pass(); + } + } + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " A print dialog will be shown.\n " + + " Please select Pages within Page-range.\n" + + " and enter From 2 and To 3. Then Select OK."; + + final JDialog dialog = new JDialog(); + dialog.setTitle("JobAttribute Updation Test"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + } +} diff --git a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java new file mode 100644 index 00000000000..7a5f87a38f3 --- /dev/null +++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6191390 + * @summary Verify that ActionEvent is received with correct modifiers set. + * @library ../../../../lib/testlibrary ../ + * @build ExtendedRobot SystemTrayIconHelper + */ + +import java.awt.Image; +import java.awt.TrayIcon; +import java.awt.SystemTray; +import java.awt.Robot; +import java.awt.EventQueue; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; + +public class ActionEventTest { + + Image image; + TrayIcon icon; + Robot robot; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + System.out.println("SystemTray not supported on the platform." + + " Marking the test passed."); + } else { + if (System.getProperty("os.name").toLowerCase().startsWith("win")) { + System.err.println( + "Test can fail on Windows platform\n"+ + "On Windows 7, by default icon hides behind icon pool\n" + + "Due to which test might fail\n" + + "Set \"Right mouse click\" -> " + + "\"Customize notification icons\" -> \"Always show " + + "all icons and notifications on the taskbar\" true " + + "to avoid this problem.\nOR change behavior only for " + + "Java SE tray icon and rerun test."); + } + + ActionEventTest test = new ActionEventTest(); + test.doTest(); + test.clear(); + } + } + + public ActionEventTest() throws Exception { + robot = new Robot(); + EventQueue.invokeAndWait(this::initializeGUI); + } + + private void initializeGUI() { + + icon = new TrayIcon( + new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "ti"); + icon.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + if ((md & expectedMask) != expectedMask) { + clear(); + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } + } + }); + + try { + SystemTray.getSystemTray().add(icon); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void clear() { + SystemTray.getSystemTray().remove(icon); + } + + void doTest() throws Exception { + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + + Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); + if (iconPosition == null) { + throw new RuntimeException("Unable to find the icon location!"); + } + + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(100); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(100); + robot.waitForIdle(); + robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + } +} diff --git a/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java b/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java new file mode 100644 index 00000000000..82dd8ab57f1 --- /dev/null +++ b/jdk/test/java/awt/font/MonospacedGlyphWidth/MonospacedGlyphWidthTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8073400 + * @summary Some Monospaced logical fonts have a different width + * @author Dmitry Markov + * @run main MonospacedGlyphWidthTest + */ +import java.awt.*; +import java.awt.font.FontRenderContext; + +public class MonospacedGlyphWidthTest { + private static final int START_INDEX = 0x2018; + private static final int END_INDEX = 0x201F; + + public static void main(String[] args) { + Font font = new Font(Font.MONOSPACED, Font.PLAIN, 12); + double width = getCharWidth(font, 'a'); + + for (int i = START_INDEX; i <= END_INDEX; i++) { + if (width != getCharWidth(font, (char)i)) { + throw new RuntimeException("Test Failed: characters have different width!"); + } + } + System.out.println("Test Passed!"); + } + + private static double getCharWidth(Font font, char c) { + FontRenderContext fontRenderContext = new FontRenderContext(null, false, false); + return font.getStringBounds(new char[] {c}, 0, 1, fontRenderContext).getWidth(); + } +} + diff --git a/jdk/test/java/awt/image/RasterCreationTest.java b/jdk/test/java/awt/image/RasterCreationTest.java new file mode 100644 index 00000000000..885fb8da76d --- /dev/null +++ b/jdk/test/java/awt/image/RasterCreationTest.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Point; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; + +/* + * @test + * @bug 6353518 + * @summary Test possible combinations of Raster creation + * Test fails if any of Raster.createXXX() method throws exception. + */ +public class RasterCreationTest { + + public static void main(String[] args) { + + final int width = 10; + final int height = 5; + final int imageSize = width * height; + Point location = new Point(0, 0); + int[] bandOffsets = {0}; + int[] bitMask = {0x00ff0000, 0x0000ff00, 0xff, 0x0}; + + SampleModel[] inputSampleModels = { + new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, + 1, 1, 1, 1, bandOffsets), + new PixelInterleavedSampleModel(DataBuffer.TYPE_USHORT, + 1, 1, 1, 1, bandOffsets), + new PixelInterleavedSampleModel(DataBuffer.TYPE_INT, + 1, 1, 1, 1, bandOffsets), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, bitMask), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT, + width, height, bitMask), + new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, + width, height, bitMask), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 4), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_USHORT, + width, height, 2), + new MultiPixelPackedSampleModel(DataBuffer.TYPE_INT, + width, height, 2) + }; + + // --------------------------------------------------------------------- + // Test ability to create Raster & WritableRaster with DataBuffer + // classes + // --------------------------------------------------------------------- + DataBuffer[] inputDataBuffer = { + new DataBufferByte(imageSize), + new DataBufferUShort(imageSize), + new DataBufferInt(imageSize, 1), + new DataBufferShort(imageSize), + new DataBufferFloat(imageSize), + new DataBufferDouble(imageSize) + }; + + for (SampleModel sm : inputSampleModels) { + for (DataBuffer db : inputDataBuffer) { + // Test Raster creation + Raster.createRaster(sm, db, location); + + // Test writableRaster creation + Raster.createWritableRaster(sm, db, location); + Raster.createWritableRaster(sm, location); + } + } + + // --------------------------------------------------------------------- + // Test ability to create Raster & WritableRaster with custom DataBuffer + // classes + // --------------------------------------------------------------------- + DataBuffer[] myDataBuffer = { + new MyDataBufferByte(imageSize), + new MyDataBufferUShort(imageSize), + new MyDataBufferInt(imageSize), + new MyDataBufferShort(imageSize), + new MyDataBufferDouble(imageSize), + new MyDataBufferFloat(imageSize) + }; + + for (SampleModel sm : inputSampleModels) { + for (DataBuffer db : myDataBuffer) { + // Test Raster creation + Raster.createRaster(sm, db, location); + + // Test writableRaster creation + Raster.createWritableRaster(sm, db, location); + Raster.createWritableRaster(sm, location); + } + } + + // --------------------------------------------------------------------- + // Test ability to create InterleavedRaster + // --------------------------------------------------------------------- + int[] interleavedInputDataTypes = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT + }; + + int numBands = 1; + + for (int i : interleavedInputDataTypes) { + Raster.createInterleavedRaster(i, width, height, 1, location); + Raster.createInterleavedRaster(i, width, height, width * numBands, + numBands, bandOffsets, location); + } + + for (int i = 0; i < interleavedInputDataTypes.length ; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + Raster.createInterleavedRaster(d1, width, height, width * numBands, + numBands, bandOffsets, location); + Raster.createInterleavedRaster(d2, width, height, width * numBands, + numBands, bandOffsets, location); + } + + // --------------------------------------------------------------------- + // Test ability to create BandedRaster + // --------------------------------------------------------------------- + int[] bankIndices = new int[numBands]; + bankIndices[0] = 0; + + int[] bandedInputDataTypes = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT, + DataBuffer.TYPE_INT + }; + + for (int i : bandedInputDataTypes) { + Raster.createBandedRaster(i, width, height, 1, location); + Raster.createBandedRaster(i, width, height, width, + bankIndices, bandOffsets, location); + } + + for (int i = 0; i < bandedInputDataTypes.length; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + Raster.createBandedRaster(d1, width, height, width, + bankIndices, bandOffsets, location); + Raster.createBandedRaster(d2, width, height, width, + bankIndices, bandOffsets, location); + } + + // --------------------------------------------------------------------- + // Test ability to create PackedRaster + // --------------------------------------------------------------------- + int[] bandMasks = new int[numBands]; + bandMasks[0] = 0; + + int packedInputDataTypes[] = { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT, + DataBuffer.TYPE_INT + }; + + for (int i : packedInputDataTypes) { + Raster.createPackedRaster(i, width, height, bandMasks, location); + + for (int bits = 1; bits < 5; bits *= 2) { + Raster.createPackedRaster(i, width, height, 1, bits, location); + } + } + + for (int i = 0; i < packedInputDataTypes.length; i++) { + DataBuffer d1 = inputDataBuffer[i]; + DataBuffer d2 = myDataBuffer[i]; + + for (int bits = 1; bits < 5; bits *= 2) { + Raster.createPackedRaster(d1, width, height, bits, location); + Raster.createPackedRaster(d2, width, height, bits, location); + } + + Raster.createPackedRaster(d1, width, height, 1,bandMasks, location); + Raster.createPackedRaster(d2, width, height, 1,bandMasks, location); + } + } +} + +// --------------------------------------------------------------------- +// Custom DataBuffer classes for testing purpose +// --------------------------------------------------------------------- +final class MyDataBufferByte extends DataBuffer { + + byte[] data; + byte[][] bankdata; + + public MyDataBufferByte(int size) { + super(TYPE_BYTE, size); + data = new byte[size]; + bankdata = new byte[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (byte) val; + } +} + +final class MyDataBufferDouble extends DataBuffer { + + double[] data; + double[][] bankdata; + + public MyDataBufferDouble(int size) { + super(TYPE_DOUBLE, size); + data = new double[size]; + bankdata = new double[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return (int) bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (double) val; + } +} + +final class MyDataBufferFloat extends DataBuffer { + + float[] data; + float[][] bankdata; + + public MyDataBufferFloat(int size) { + super(TYPE_FLOAT, size); + data = new float[size]; + bankdata = new float[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return (int) bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (float) val; + } +} + +final class MyDataBufferShort extends DataBuffer { + + short[] data; + short[][] bankdata; + + public MyDataBufferShort(int size) { + super(TYPE_SHORT, size); + data = new short[size]; + bankdata = new short[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (short) val; + } +} + +final class MyDataBufferUShort extends DataBuffer { + + short[] data; + short[][] bankdata; + + public MyDataBufferUShort(int size) { + super(TYPE_USHORT, size); + data = new short[size]; + bankdata = new short[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (short) val; + } +} + +final class MyDataBufferInt extends DataBuffer { + + int[] data; + int[][] bankdata; + + public MyDataBufferInt(int size) { + super(TYPE_INT, size); + data = new int[size]; + bankdata = new int[1][]; + bankdata[0] = data; + } + + @Override + public int getElem(int bank, int i) { + return bankdata[bank][i + offsets[bank]]; + } + + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank][i + offsets[bank]] = (int) val; + } +} diff --git a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java index 87a6de00917..bb0a7525ec7 100644 --- a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java +++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java @@ -24,8 +24,7 @@ /* @test - @bug 8150176 - @ignore 8150176 + @bug 8150176 8151773 @summary Check if correct resolution variant is used for tray icon. @author a.stepanov @run applet/manual=yesno MultiResolutionTrayIconTest.html diff --git a/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java b/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java new file mode 100644 index 00000000000..dc31ffda1fd --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/DlgAttrsBug.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8061258 + * @summary PrinterJob's native Print Dialog does not reflect + * specified Copies or Page Ranges + * @run main/manual DlgAttrsBug + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + + +public class DlgAttrsBug implements Printable { + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + doTest(DlgAttrsBug::printTest); + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("Print Dialog does not " + + "reflect Copies or Page Ranges"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + private static void printTest() { + PrinterJob job = PrinterJob.getPrinterJob(); + if (job.getPrintService() == null) { + System.out.println("No printers. Test cannot continue"); + return; + } + job.setPrintable(new DlgAttrsBug()); + PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); + aset.add(new Copies(5)); + aset.add(new PageRanges(3,4)); + aset.add(DialogTypeSelection.NATIVE); + job.printDialog(aset); + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " Visual inspection of print dialog is required.\n" + + " A print dialog will be shown.\n " + + " Please verify Copies 5 is selected.\n" + + " Also verify, Page Range is selected with " + + " from page 3 and to Page 4.\n" + + " If ok, press PASS else press FAIL"; + + final JDialog dialog = new JDialog(); + dialog.setTitle("printSelectionTest"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + dialog.dispose(); + pass(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + dialog.dispose(); + fail(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + } + + public int print(Graphics g, PageFormat pf, int pi) + throws PrinterException { + System.out.println("pi = " + pi); + if (pi >= 5) { + return NO_SUCH_PAGE; + } + g.drawString("Page : " + (pi+1), 200, 200); + return PAGE_EXISTS; + } + +} diff --git a/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java b/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java new file mode 100644 index 00000000000..f068964c4e1 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + @test + @bug 8042713 + @summary Print Dialog does not update attribute set with page range + @run main/manual PrintAttributeUpdateTest + */ +import java.awt.Component; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Printable; +import java.awt.print.PrinterJob; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.print.attribute.standard.PageRanges; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +public class PrintAttributeUpdateTest implements Pageable, Printable { + + public static void main(String args[]) throws Exception { + String[] instructions + = { + "Select Pages Range From instead of All in print dialog. ", + "Then select Print" + }; + SwingUtilities.invokeAndWait(() -> { + JOptionPane.showMessageDialog((Component) null, + instructions, "Instructions", + JOptionPane.INFORMATION_MESSAGE); + }); + HashPrintRequestAttributeSet as = new HashPrintRequestAttributeSet(); + PrinterJob j = PrinterJob.getPrinterJob(); + j.setPageable(new PrintAttributeUpdateTest()); + as.add(DialogTypeSelection.NATIVE); + j.printDialog(as); + if (as.containsKey(PageRanges.class) == false) { + throw new RuntimeException("Print Dialog did not update " + + " attribute set with page range"); + } + Attribute attrs[] = as.toArray(); + for (int i = 0; i < attrs.length; i++) { + System.out.println("attr " + attrs[i]); + } + j.print(as); + } + + public int getNumberOfPages() { + return UNKNOWN_NUMBER_OF_PAGES; + } + + public PageFormat getPageFormat(int pageIndex) { + PageFormat pf = new PageFormat(); + return pf; + } + + public Printable getPrintable(int pageIndex) { + return this; + } + + public int print(Graphics g, PageFormat pgFmt, int pi) { + g.drawString("Page : " + (pi + 1), 200, 200); + + return PAGE_EXISTS; + } + +} diff --git a/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java b/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java index 75898f4cbfe..8e0c3d6774e 100644 --- a/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java +++ b/jdk/test/java/awt/xembed/server/TestXEmbedServerJava.java @@ -76,7 +76,23 @@ public class TestXEmbedServerJava extends TestXEmbedServer { public Process startClient(Rectangle[] bounds, long window) { try { String java_home = System.getProperty("java.home"); - return Runtime.getRuntime().exec(java_home + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED JavaClient " + window); + boolean hasModules = true; + try { + Class.class.getMethod("getModule"); + }catch(Exception hasModulesEx) { + hasModules = false; + } + if (hasModules) { + System.out.println(java_home + + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED "+ + "-XaddExports:java.desktop/sun.awt=ALL-UNNAMED JavaClient " + window); + return Runtime.getRuntime().exec(java_home + + "/bin/java -XaddExports:java.desktop/sun.awt.X11=ALL-UNNAMED "+ + "-XaddExports:java.desktop/sun.awt=ALL-UNNAMED JavaClient " + window); + }else{ + System.out.println(java_home + "/bin/java JavaClient " + window); + return Runtime.getRuntime().exec(java_home + "/bin/java JavaClient " + window); + } } catch (IOException ex1) { ex1.printStackTrace(); } diff --git a/jdk/test/java/lang/Class/GetPackageTest.java b/jdk/test/java/lang/Class/GetPackageTest.java index d1ffea75ecb..f9cb5fb31ff 100644 --- a/jdk/test/java/lang/Class/GetPackageTest.java +++ b/jdk/test/java/lang/Class/GetPackageTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public class GetPackageTest { assertEquals(fooClass.getClassLoader(), loader); } - @DataProvider(name = "testclasses") + @DataProvider(name = "testClasses") public Object[][] testClasses() { return new Object[][] { // primitive type, void, array types diff --git a/jdk/test/java/lang/Math/FusedMultiplyAddTests.java b/jdk/test/java/lang/Math/FusedMultiplyAddTests.java new file mode 100644 index 00000000000..b8ed3ab69f3 --- /dev/null +++ b/jdk/test/java/lang/Math/FusedMultiplyAddTests.java @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4851642 + * @summary Tests for Math.fusedMac and StrictMath.fusedMac. + * @build Tests + * @build FusedMultiplyAddTests + * @run main FusedMultiplyAddTests + */ + +/** + * The specifications for both Math.fusedMac and StrictMath.fusedMac + * are the same and both are exactly specified. Therefore, both + * methods are tested in this file. + */ + +public class FusedMultiplyAddTests { + private FusedMultiplyAddTests(){} + + private static final double Infinity = Double.POSITIVE_INFINITY; + private static final float InfinityF = Float.POSITIVE_INFINITY; + private static final double NaN = Double.NaN; + private static final float NaNf = Float.NaN; + + public static void main(String... args) { + int failures = 0; + + failures += testNonFiniteD(); + failures += testZeroesD(); + failures += testSimpleD(); + + failures += testNonFiniteF(); + failures += testZeroesF(); + failures += testSimpleF(); + + if (failures > 0) { + System.err.println("Testing fma incurred " + + failures + " failures."); + throw new RuntimeException(); + } + } + + private static int testNonFiniteD() { + int failures = 0; + + double [][] testCases = { + {Infinity, Infinity, Infinity, + Infinity, + }, + + {-Infinity, Infinity, -Infinity, + -Infinity, + }, + + {-Infinity, Infinity, Infinity, + NaN, + }, + + {Infinity, Infinity, -Infinity, + NaN, + }, + + {1.0, Infinity, 2.0, + Infinity, + }, + + {1.0, 2.0, Infinity, + Infinity, + }, + + {Infinity, 1.0, Infinity, + Infinity, + }, + + {Double.MAX_VALUE, 2.0, -Infinity, + -Infinity}, + + {Infinity, 1.0, -Infinity, + NaN, + }, + + {-Infinity, 1.0, Infinity, + NaN, + }, + + {1.0, NaN, 2.0, + NaN, + }, + + {1.0, 2.0, NaN, + NaN, + }, + + {Infinity, 2.0, NaN, + NaN, + }, + + {NaN, 2.0, Infinity, + NaN, + }, + }; + + for (double[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + private static int testZeroesD() { + int failures = 0; + + double [][] testCases = { + {+0.0, +0.0, +0.0, + +0.0, + }, + + {-0.0, +0.0, +0.0, + +0.0, + }, + + {+0.0, +0.0, -0.0, + +0.0, + }, + + {+0.0, +0.0, -0.0, + +0.0, + }, + + {-0.0, +0.0, -0.0, + -0.0, + }, + + {-0.0, -0.0, -0.0, + +0.0, + }, + + {-1.0, +0.0, -0.0, + -0.0, + }, + + {-1.0, +0.0, +0.0, + +0.0, + }, + + {-2.0, +0.0, -0.0, + -0.0, + }, + + {-2.0, +0.0, +0.0, + +0.0, + }, + }; + + for (double[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + private static int testSimpleD() { + int failures = 0; + + double [][] testCases = { + {1.0, 2.0, 3.0, + 5.0,}, + + {1.0, 2.0, -2.0, + 0.0,}, + + {5.0, 5.0, -25.0, + 0.0,}, + + {Double.MAX_VALUE, 2.0, -Double.MAX_VALUE, + Double.MAX_VALUE}, + + {Double.MAX_VALUE, 2.0, 1.0, + Infinity}, + + {Double.MIN_VALUE, -Double.MIN_VALUE, +0.0, + -0.0}, + + {Double.MIN_VALUE, -Double.MIN_VALUE, -0.0, + -0.0}, + + {Double.MIN_VALUE, Double.MIN_VALUE, +0.0, + +0.0}, + + {Double.MIN_VALUE, Double.MIN_VALUE, -0.0, + +0.0}, + + {Double.MIN_VALUE, +0.0, -0.0, + +0.0}, + + {Double.MIN_VALUE, -0.0, -0.0, + -0.0}, + + {Double.MIN_VALUE, +0.0, +0.0, + +0.0}, + + {Double.MIN_VALUE, -0.0, +0.0, + +0.0}, + }; + + for (double[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + private static int testNonFiniteF() { + int failures = 0; + + float [][] testCases = { + {1.0f, InfinityF, 2.0f, + InfinityF, + }, + + {1.0f, 2.0f, InfinityF, + InfinityF, + }, + + {InfinityF, 1.0f, InfinityF, + InfinityF, + }, + + {Float.MAX_VALUE, 2.0f, -InfinityF, + -InfinityF}, + + {InfinityF, 1.0f, -InfinityF, + NaNf, + }, + + {-InfinityF, 1.0f, InfinityF, + NaNf, + }, + + {1.0f, NaNf, 2.0f, + NaNf, + }, + + {1.0f, 2.0f, NaNf, + NaNf, + }, + + {InfinityF, 2.0f, NaNf, + NaNf, + }, + + {NaNf, 2.0f, InfinityF, + NaNf, + }, + }; + + for (float[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + private static int testZeroesF() { + int failures = 0; + + float [][] testCases = { + {+0.0f, +0.0f, +0.0f, + +0.0f, + }, + + {-0.0f, +0.0f, +0.0f, + +0.0f, + }, + + {+0.0f, +0.0f, -0.0f, + +0.0f, + }, + + {+0.0f, +0.0f, -0.0f, + +0.0f, + }, + + {-0.0f, +0.0f, -0.0f, + -0.0f, + }, + + {-0.0f, -0.0f, -0.0f, + +0.0f, + }, + + {-1.0f, +0.0f, -0.0f, + -0.0f, + }, + + {-1.0f, +0.0f, +0.0f, + +0.0f, + }, + + {-2.0f, +0.0f, -0.0f, + -0.0f, + }, + }; + + for (float[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + private static int testSimpleF() { + int failures = 0; + + float [][] testCases = { + {1.0f, 2.0f, 3.0f, + 5.0f,}, + + {1.0f, 2.0f, -2.0f, + 0.0f,}, + + {5.0f, 5.0f, -25.0f, + 0.0f,}, + + {Float.MAX_VALUE, 2.0f, -Float.MAX_VALUE, + Float.MAX_VALUE}, + + {Float.MAX_VALUE, 2.0f, 1.0f, + InfinityF}, + }; + + for (float[] testCase: testCases) + failures += testFusedMacCase(testCase[0], testCase[1], testCase[2], testCase[3]); + + return failures; + } + + + private static int testFusedMacCase(double input1, double input2, double input3, double expected) { + int failures = 0; + failures += Tests.test("Math.fma(double)", input1, input2, input3, + Math.fma(input1, input2, input3), expected); + failures += Tests.test("StrictMath.fma(double)", input1, input2, input3, + StrictMath.fma(input1, input2, input3), expected); + + // Permute first two inputs + failures += Tests.test("Math.fma(double)", input2, input1, input3, + Math.fma(input2, input1, input3), expected); + failures += Tests.test("StrictMath.fma(double)", input2, input1, input3, + StrictMath.fma(input2, input1, input3), expected); + return failures; + } + + private static int testFusedMacCase(float input1, float input2, float input3, float expected) { + int failures = 0; + failures += Tests.test("Math.fma(float)", input1, input2, input3, + Math.fma(input1, input2, input3), expected); + failures += Tests.test("StrictMath.fma(float)", input1, input2, input3, + StrictMath.fma(input1, input2, input3), expected); + + // Permute first two inputs + failures += Tests.test("Math.fma(float)", input2, input1, input3, + Math.fma(input2, input1, input3), expected); + failures += Tests.test("StrictMath.fma(float)", input2, input1, input3, + StrictMath.fma(input2, input1, input3), expected); + return failures; + } +} diff --git a/jdk/test/java/lang/Math/Tests.java b/jdk/test/java/lang/Math/Tests.java index b74086b9f5b..98821142fc9 100644 --- a/jdk/test/java/lang/Math/Tests.java +++ b/jdk/test/java/lang/Math/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,6 +391,38 @@ public class Tests { return 0; } + public static int test(String testName, + float input1, float input2, float input3, + float result, float expected) { + if (Float.compare(expected, result ) != 0) { + System.err.println("Failure for " + testName + ":\n" + + "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " + + input2 + "\t(" + toHexString(input2) + ") and" + + input3 + "\t(" + toHexString(input3) + ")\n" + + "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + + "\tgot " + result + "\t(" + toHexString(result) + ")."); + return 1; + } + else + return 0; + } + + public static int test(String testName, + double input1, double input2, double input3, + double result, double expected) { + if (Double.compare(expected, result ) != 0) { + System.err.println("Failure for " + testName + ":\n" + + "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " + + input2 + "\t(" + toHexString(input2) + ") and" + + input3 + "\t(" + toHexString(input3) + ")\n" + + "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + + "\tgot " + result + "\t(" + toHexString(result) + ")."); + return 1; + } + else + return 0; + } + static int testUlpCore(double result, double expected, double ulps) { // We assume we won't be unlucky and have an inexact expected // be nextDown(2^i) when 2^i would be the correctly rounded diff --git a/jdk/test/java/lang/SecurityManager/RestrictedPackages.java b/jdk/test/java/lang/SecurityManager/RestrictedPackages.java index 56d0ed5ea13..546df6b1661 100644 --- a/jdk/test/java/lang/SecurityManager/RestrictedPackages.java +++ b/jdk/test/java/lang/SecurityManager/RestrictedPackages.java @@ -77,7 +77,6 @@ final class RestrictedPackages { "jdk.internal.", "jdk.nashorn.internal.", "jdk.nashorn.tools.", - "jdk.rmi.rmic.", "jdk.tools.jimage.", "com.sun.activation.registries.", "com.sun.java.accessibility.util.internal." diff --git a/jdk/test/java/lang/StackWalker/DumpStackTest.java b/jdk/test/java/lang/StackWalker/DumpStackTest.java index 2aa97d7c93e..c0ff99f9f68 100644 --- a/jdk/test/java/lang/StackWalker/DumpStackTest.java +++ b/jdk/test/java/lang/StackWalker/DumpStackTest.java @@ -82,9 +82,9 @@ public class DumpStackTest { new CallFrame(DumpStackTest.class, "test"), new CallFrame(DumpStackTest.class, "main"), // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), new CallFrame(Method.class, "invoke"), new CallFrame(Thread.class, "run"), }; @@ -138,9 +138,9 @@ public class DumpStackTest { new CallFrame(DumpStackTest.class, "testLambda"), new CallFrame(DumpStackTest.class, "main"), // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), new CallFrame(Method.class, "invoke"), new CallFrame(Thread.class, "run") }; @@ -161,16 +161,16 @@ public class DumpStackTest { CallFrame[] callStack = new CallFrame[] { new CallFrame(Thread.class, "getStackTrace"), new CallFrame(DumpStackTest.class, "methodInvoke"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), new CallFrame(Method.class, "invoke"), new CallFrame(DumpStackTest.class, "testMethodInvoke"), new CallFrame(DumpStackTest.class, "main"), // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), new CallFrame(Method.class, "invoke"), new CallFrame(Thread.class, "run") }; @@ -196,9 +196,9 @@ public class DumpStackTest { new CallFrame(DumpStackTest.class, "testMethodHandle"), new CallFrame(DumpStackTest.class, "main"), // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), + new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), + new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), new CallFrame(Method.class, "invoke"), new CallFrame(Thread.class, "run") }; diff --git a/jdk/test/java/lang/StackWalker/EmbeddedStackWalkTest.java b/jdk/test/java/lang/StackWalker/EmbeddedStackWalkTest.java index f01e64eeb14..00bcb213596 100644 --- a/jdk/test/java/lang/StackWalker/EmbeddedStackWalkTest.java +++ b/jdk/test/java/lang/StackWalker/EmbeddedStackWalkTest.java @@ -75,7 +75,7 @@ public class EmbeddedStackWalkTest { if (loops == 0) { String caller = walker.walk(s -> s.map(StackFrame::getClassName) - .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) + .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) .skip(2).findFirst() ).get(); assertEquals(caller, C1.class.getName()); @@ -122,7 +122,7 @@ public class EmbeddedStackWalkTest { static void call(StackWalker walker) { String caller = walker.walk(s -> s.map(StackFrame::getClassName) - .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) + .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) .skip(2).findFirst() ).get(); assertEquals(caller, C2.class.getName()); diff --git a/jdk/test/java/lang/StackWalker/HiddenFrames.java b/jdk/test/java/lang/StackWalker/HiddenFrames.java index d9f6dac28d7..d030c52b46f 100644 --- a/jdk/test/java/lang/StackWalker/HiddenFrames.java +++ b/jdk/test/java/lang/StackWalker/HiddenFrames.java @@ -98,7 +98,7 @@ public class HiddenFrames { void checkFrame(StackFrame frame) { String cn = frame.getClassName(); - if (cn.startsWith("java.lang.reflect.") || cn.startsWith("sun.reflect.")) { + if (cn.startsWith("java.lang.reflect.") || cn.startsWith("jdk.internal.reflect.")) { reflects.add(frame); } if (cn.contains("$$Lambda$")) { diff --git a/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java b/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java index 18ec9454ee0..fa520719fe4 100644 --- a/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java +++ b/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java @@ -46,8 +46,8 @@ import static java.lang.StackWalker.Option.*; public class MultiThreadStackWalk { static Set infrastructureClasses = new TreeSet<>(Arrays.asList( - "sun.reflect.NativeMethodAccessorImpl", - "sun.reflect.DelegatingMethodAccessorImpl", + "jdk.internal.reflect.NativeMethodAccessorImpl", + "jdk.internal.reflect.DelegatingMethodAccessorImpl", "java.lang.reflect.Method", "com.sun.javatest.regtest.MainWrapper$MainThread", "java.lang.Thread" diff --git a/jdk/test/java/lang/StackWalker/StackWalkTest.java b/jdk/test/java/lang/StackWalker/StackWalkTest.java index 5c4782fb46a..711bd4bd584 100644 --- a/jdk/test/java/lang/StackWalker/StackWalkTest.java +++ b/jdk/test/java/lang/StackWalker/StackWalkTest.java @@ -55,8 +55,8 @@ public class StackWalkTest { private static final int MAX_RANDOM_DEPTH = 1000; static final Set infrastructureClasses = new TreeSet<>(Arrays.asList( - "sun.reflect.NativeMethodAccessorImpl", - "sun.reflect.DelegatingMethodAccessorImpl", + "jdk.internal.reflect.NativeMethodAccessorImpl", + "jdk.internal.reflect.DelegatingMethodAccessorImpl", "java.lang.reflect.Method", "com.sun.javatest.regtest.MainWrapper$MainThread", "com.sun.javatest.regtest.agent.MainWrapper$MainThread", diff --git a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java index d9cfcf6aba5..7d5c978b59f 100644 --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java @@ -100,9 +100,9 @@ public class VerifyStackTrace { "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + - "5: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "6: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + + "5: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + + "6: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + + "7: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + "8: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + "10: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + @@ -137,9 +137,9 @@ public class VerifyStackTrace { "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(java.base/LambdaForm$MH)\n" + "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + - "8: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "9: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + + "8: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + + "9: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + + "10: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + "11: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + "13: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 71e4b0e89d8..1df672fb997 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -26,6 +26,7 @@ /* @test * @bug 8139885 * @bug 8150635 + * @bug 8150956 * @bug 8150957 * @bug 8153637 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest @@ -265,6 +266,28 @@ public class LoopCombinatorTest { assertEquals(v, w.i); } + @Test + public static void testWhileVoidInit() throws Throwable { + While w = new While(); + int v = 5; + MethodHandle loop = MethodHandles.whileLoop(While.MH_voidInit.bindTo(w), While.MH_voidPred.bindTo(w), + While.MH_voidBody.bindTo(w)); + assertEquals(While.MT_void, loop.type()); + loop.invoke(v); + assertEquals(v, w.i); + } + + @Test + public static void testDoWhileVoidInit() throws Throwable { + While w = new While(); + int v = 5; + MethodHandle loop = MethodHandles.doWhileLoop(While.MH_voidInit.bindTo(w), While.MH_voidBody.bindTo(w), + While.MH_voidPred.bindTo(w)); + assertEquals(While.MT_void, loop.type()); + loop.invoke(v); + assertEquals(v, w.i); + } + @Test public static void testCountedLoop() throws Throwable { // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; => a variation on a well known theme @@ -274,6 +297,14 @@ public class LoopCombinatorTest { assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!")); } + @Test + public static void testCountedLoopVoidInit() throws Throwable { + MethodHandle fit5 = MethodHandles.constant(int.class, 5); + MethodHandle loop = MethodHandles.countedLoop(fit5, MethodHandles.zero(void.class), Counted.MH_printHello); + assertEquals(Counted.MT_countedPrinting, loop.type()); + loop.invoke(); + } + @Test public static void testCountedArrayLoop() throws Throwable { // int[] a = new int[]{0}; for (int i = 0; i < 13; ++i) { ++a[0]; } => a[0] == 13 @@ -360,7 +391,8 @@ public class LoopCombinatorTest { public static void testIterateNullBody() { boolean caught = false; try { - MethodHandles.iteratedLoop(MethodHandles.identity(int.class), MethodHandles.identity(int.class), null); + MethodHandles.iteratedLoop(MethodHandles.empty(methodType(Iterator.class, int.class)), + MethodHandles.identity(int.class), null); } catch (IllegalArgumentException iae) { assertEquals("iterated loop body must not be null", iae.getMessage()); caught = true; @@ -368,6 +400,26 @@ public class LoopCombinatorTest { assertTrue(caught); } + @Test + public static void testIterateVoidIterator() { + boolean caught = false; + MethodType v = methodType(void.class); + try { + MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v)); + } catch(IllegalArgumentException iae) { + assertEquals("iteratedLoop first argument must have Iterator return type", iae.getMessage()); + caught = true; + } + assertTrue(caught); + } + + @Test + public static void testIterateVoidInit() throws Throwable { + MethodHandle loop = MethodHandles.iteratedLoop(null, Iterate.MH_voidInit, Iterate.MH_printStep); + assertEquals(Iterate.MT_print, loop.type()); + loop.invoke(Arrays.asList("hello", "world")); + } + static class Empty { static void f() { } @@ -604,6 +656,10 @@ public class LoopCombinatorTest { private int i = 0; + void voidInit(int k) { + // empty + } + void voidBody(int k) { ++i; } @@ -623,6 +679,7 @@ public class LoopCombinatorTest { static final MethodType MT_zipInitZip = methodType(List.class, Iterator.class, Iterator.class); static final MethodType MT_zipPred = methodType(boolean.class, List.class, Iterator.class, Iterator.class); static final MethodType MT_zipStep = methodType(List.class, List.class, Iterator.class, Iterator.class); + static final MethodType MT_voidInit = methodType(void.class, int.class); static final MethodType MT_voidBody = methodType(void.class, int.class); static final MethodType MT_voidPred = methodType(boolean.class, int.class); @@ -635,6 +692,7 @@ public class LoopCombinatorTest { static final MethodHandle MH_zipInitZip; static final MethodHandle MH_zipPred; static final MethodHandle MH_zipStep; + static final MethodHandle MH_voidInit; static final MethodHandle MH_voidBody; static final MethodHandle MH_voidPred; @@ -654,6 +712,7 @@ public class LoopCombinatorTest { MH_zipInitZip = LOOKUP.findStatic(WHILE, "zipInitZip", MT_zipInitZip); MH_zipPred = LOOKUP.findStatic(WHILE, "zipPred", MT_zipPred); MH_zipStep = LOOKUP.findStatic(WHILE, "zipStep", MT_zipStep); + MH_voidInit = LOOKUP.findVirtual(WHILE, "voidInit", MT_voidInit); MH_voidBody = LOOKUP.findVirtual(WHILE, "voidBody", MT_voidBody); MH_voidPred = LOOKUP.findVirtual(WHILE, "voidPred", MT_voidPred); } catch (Exception e) { @@ -768,6 +827,10 @@ public class LoopCombinatorTest { System.out.print(s); } + static void voidInit() { + // empty + } + static final Class ITERATE = Iterate.class; static final MethodType MT_sumIterator = methodType(Iterator.class, Integer[].class); @@ -783,6 +846,8 @@ public class LoopCombinatorTest { static final MethodType MT_mapStep = methodType(List.class, String.class, List.class, List.class); static final MethodType MT_printStep = methodType(void.class, String.class, List.class); + static final MethodType MT_voidInit = methodType(void.class); + static final MethodHandle MH_sumIterator; static final MethodHandle MH_sumInit; static final MethodHandle MH_sumStep; @@ -797,6 +862,8 @@ public class LoopCombinatorTest { static final MethodHandle MH_mapInit; static final MethodHandle MH_mapStep; + static final MethodHandle MH_voidInit; + static final MethodType MT_sum = methodType(int.class, Integer[].class); static final MethodType MT_reverse = methodType(List.class, List.class); static final MethodType MT_length = methodType(int.class, List.class); @@ -815,6 +882,7 @@ public class LoopCombinatorTest { MH_mapInit = LOOKUP.findStatic(ITERATE, "mapInit", MT_mapInit); MH_mapStep = LOOKUP.findStatic(ITERATE, "mapStep", MT_mapStep); MH_printStep = LOOKUP.findStatic(ITERATE, "printStep", MT_printStep); + MH_voidInit = LOOKUP.findStatic(ITERATE, "voidInit", MT_voidInit); } catch (Exception e) { throw new ExceptionInInitializerError(e); } diff --git a/jdk/test/java/lang/invoke/RevealDirectTest.java b/jdk/test/java/lang/invoke/RevealDirectTest.java index 55cd0b62aa7..d2f9f7d5e01 100644 --- a/jdk/test/java/lang/invoke/RevealDirectTest.java +++ b/jdk/test/java/lang/invoke/RevealDirectTest.java @@ -24,7 +24,7 @@ /* * @test * @summary verify Lookup.revealDirect on a variety of input handles - * @modules java.base/sun.reflect + * @modules java.base/jdk.internal.reflect * @compile -XDignore.symbol.file RevealDirectTest.java * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest * @@ -311,7 +311,7 @@ public class RevealDirectTest { if (!(mem instanceof AnnotatedElement)) return false; AnnotatedElement ae = (AnnotatedElement) mem; if (CS_CLASS != null) - return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class); + return ae.isAnnotationPresent(jdk.internal.reflect.CallerSensitive.class); for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) { if (a.toString().contains(".CallerSensitive")) return true; @@ -322,7 +322,7 @@ public class RevealDirectTest { static { Class c = null; try { - c = sun.reflect.CallerSensitive.class; + c = jdk.internal.reflect.CallerSensitive.class; } catch (SecurityException | LinkageError ex) { } CS_CLASS = c; diff --git a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java index 7d8646d5361..1fa3a557941 100644 --- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java +++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java @@ -28,7 +28,6 @@ * @build java.base/java.util.stream.OpTestCase * @run testng/othervm NetworkInterfaceStreamTest * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest - * @key intermittent */ import org.testng.annotations.Test; @@ -52,21 +51,27 @@ public class NetworkInterfaceStreamTest extends OpTestCase { public void testNetworkInterfaces() throws SocketException { Supplier> ss = () -> { try { - return NetworkInterface.networkInterfaces(); + return NetworkInterface.networkInterfaces() + .filter(ni -> isIncluded(ni)); } catch (SocketException e) { throw new RuntimeException(e); } }; - Collection expected = Collections.list(NetworkInterface.getNetworkInterfaces()); + Collection enums = Collections.list(NetworkInterface.getNetworkInterfaces()); + Collection expected = new ArrayList<>(); + enums.forEach(ni -> { + if (isIncluded(ni)) { + expected.add(ni); + } + }); withData(TestData.Factory.ofSupplier("Top-level network interfaces", ss)) .stream(s -> s) .expectedResult(expected) .exercise(); } - private Collection getAllNetworkInterfaces() throws SocketException { Collection anis = new ArrayList<>(); for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) { diff --git a/jdk/test/java/net/httpclient/http2/HpackDriver.java b/jdk/test/java/net/httpclient/http2/HpackDriver.java new file mode 100644 index 00000000000..3bf1bc39a4b --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/HpackDriver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8153353 + * @modules java.httpclient/sun.net.httpclient.hpack + * @key randomness + * @compile/module=java.httpclient sun/net/httpclient/hpack/SpecHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/TestHelper.java + * @compile/module=java.httpclient sun/net/httpclient/hpack/BuffersTestingKit.java + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.BinaryPrimitivesTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.CircularBufferTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.DecoderTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.EncoderTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.HeaderTableTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.HuffmanTest + * @run testng/othervm -XaddReads:java.httpclient=ALL-UNNAMED java.httpclient/sun.net.httpclient.hpack.TestHelper + */ +public class HpackDriver { } diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java new file mode 100644 index 00000000000..dedd53329a8 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BinaryPrimitivesTest.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import static sun.net.httpclient.hpack.BuffersTestingKit.*; +import static sun.net.httpclient.hpack.TestHelper.newRandom; + +// +// Some of the tests below overlap in what they test. This allows to diagnose +// bugs quicker and with less pain by simply ruling out common working bits. +// +public final class BinaryPrimitivesTest { + + private final Random rnd = newRandom(); + + @Test + public void integerRead1() { + verifyRead(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); + } + + @Test + public void integerRead2() { + verifyRead(bytes(0b00001010), 10, 5); + } + + @Test + public void integerRead3() { + verifyRead(bytes(0b00101010), 42, 8); + } + + @Test + public void integerWrite1() { + verifyWrite(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); + } + + @Test + public void integerWrite2() { + verifyWrite(bytes(0b00001010), 10, 5); + } + + @Test + public void integerWrite3() { + verifyWrite(bytes(0b00101010), 42, 8); + } + + // + // Since readInteger(x) is the inverse of writeInteger(x), thus: + // + // for all x: readInteger(writeInteger(x)) == x + // + @Test + public void integerIdentity() { + final int MAX_VALUE = 1 << 22; + int totalCases = 0; + int maxFilling = 0; + IntegerReader r = new IntegerReader(); + IntegerWriter w = new IntegerWriter(); + ByteBuffer buf = ByteBuffer.allocate(8); + for (int N = 1; N < 9; N++) { + for (int expected = 0; expected <= MAX_VALUE; expected++) { + w.reset().configure(expected, N, 1).write(buf); + buf.flip(); + totalCases++; + maxFilling = Math.max(maxFilling, buf.remaining()); + r.reset().configure(N).read(buf); + assertEquals(r.get(), expected); + buf.clear(); + } + } + System.out.printf("totalCases: %,d, maxFilling: %,d, maxValue: %,d%n", + totalCases, maxFilling, MAX_VALUE); + } + + @Test + public void integerReadChunked() { + final int NUM_TESTS = 1024; + IntegerReader r = new IntegerReader(); + ByteBuffer bb = ByteBuffer.allocate(8); + IntegerWriter w = new IntegerWriter(); + for (int i = 0; i < NUM_TESTS; i++) { + final int N = 1 + rnd.nextInt(8); + final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; + w.reset().configure(expected, N, rnd.nextInt()).write(bb); + bb.flip(); + + forEachSplit(bb, + (buffers) -> { + Iterable buf = relocateBuffers(injectEmptyBuffers(buffers)); + r.configure(N); + for (ByteBuffer b : buf) { + r.read(b); + } + assertEquals(r.get(), expected); + r.reset(); + }); + bb.clear(); + } + } + + // FIXME: use maxValue in the test + + @Test + // FIXME: tune values for better coverage + public void integerWriteChunked() { + ByteBuffer bb = ByteBuffer.allocate(6); + IntegerWriter w = new IntegerWriter(); + IntegerReader r = new IntegerReader(); + for (int i = 0; i < 1024; i++) { // number of tests + final int N = 1 + rnd.nextInt(8); + final int payload = rnd.nextInt(255); + final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; + + forEachSplit(bb, + (buffers) -> { + List buf = new ArrayList<>(); + relocateBuffers(injectEmptyBuffers(buffers)).forEach(buf::add); + boolean written = false; + w.configure(expected, N, payload); // TODO: test for payload it can be read after written + for (ByteBuffer b : buf) { + int pos = b.position(); + written = w.write(b); + b.position(pos); + } + if (!written) { + fail("please increase bb size"); + } + r.configure(N).read(concat(buf)); + // TODO: check payload here + assertEquals(r.get(), expected); + w.reset(); + r.reset(); + bb.clear(); + }); + } + } + + + // + // Since readString(x) is the inverse of writeString(x), thus: + // + // for all x: readString(writeString(x)) == x + // + @Test + public void stringIdentity() { + final int MAX_STRING_LENGTH = 4096; + ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); // it takes 6 bytes to encode string length of Integer.MAX_VALUE + CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + StringReader reader = new StringReader(); + StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + for (int i = 0; i < 64; i++) { + // not so much "test in isolation", I know... we're testing .reset() as well + bytes.clear(); + chars.clear(); + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + boolean written = writer + .configure(CharBuffer.wrap(expected), 0, expected.length(), false) + .write(bytes); + + if (!written) { + fail("please increase 'bytes' size"); + } + bytes.flip(); + reader.read(bytes, chars); + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + writer.reset(); + } + } + } + +// @Test +// public void huffmanStringWriteChunked() { +// fail(); +// } +// +// @Test +// public void huffmanStringReadChunked() { +// fail(); +// } + + @Test + public void stringWriteChunked() { + final int MAX_STRING_LENGTH = 8; + final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); + final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + final StringReader reader = new StringReader(); + final StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + forEachSplit(bytes, (buffers) -> { + writer.configure(expected, 0, expected.length(), false); + boolean written = false; + for (ByteBuffer buf : buffers) { + int p0 = buf.position(); + written = writer.write(buf); + buf.position(p0); + } + if (!written) { + fail("please increase 'bytes' size"); + } + reader.read(concat(buffers), chars); + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + writer.reset(); + chars.clear(); + bytes.clear(); + }); + } + } + + @Test + public void stringReadChunked() { + final int MAX_STRING_LENGTH = 16; + final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); + final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); + final StringReader reader = new StringReader(); + final StringWriter writer = new StringWriter(); + for (int len = 0; len <= MAX_STRING_LENGTH; len++) { + + byte[] b = new byte[len]; + rnd.nextBytes(b); + + String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string + + boolean written = writer + .configure(CharBuffer.wrap(expected), 0, expected.length(), false) + .write(bytes); + writer.reset(); + + if (!written) { + fail("please increase 'bytes' size"); + } + bytes.flip(); + + forEachSplit(bytes, (buffers) -> { + for (ByteBuffer buf : buffers) { + int p0 = buf.position(); + reader.read(buf, chars); + buf.position(p0); + } + chars.flip(); + assertEquals(chars.toString(), expected); + reader.reset(); + chars.clear(); + }); + + bytes.clear(); + } + } + +// @Test +// public void test_Huffman_String_Identity() { +// StringWriter writer = new StringWriter(); +// StringReader reader = new StringReader(); +// // 256 * 8 gives 2048 bits in case of plain 8 bit coding +// // 256 * 30 gives you 7680 bits or 960 bytes in case of almost +// // improbable event of 256 30 bits symbols in a row +// ByteBuffer binary = ByteBuffer.allocate(960); +// CharBuffer text = CharBuffer.allocate(960 / 5); // 5 = minimum code length +// for (int len = 0; len < 128; len++) { +// for (int i = 0; i < 256; i++) { +// // not so much "test in isolation", I know... +// binary.clear(); +// +// byte[] bytes = new byte[len]; +// rnd.nextBytes(bytes); +// +// String s = new String(bytes, StandardCharsets.ISO_8859_1); +// +// writer.write(CharBuffer.wrap(s), binary, true); +// binary.flip(); +// reader.read(binary, text); +// text.flip(); +// assertEquals(text.toString(), s); +// } +// } +// } + + // TODO: atomic failures: e.g. readonly/overflow + + private static byte[] bytes(int... data) { + byte[] bytes = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + bytes[i] = (byte) data[i]; + } + return bytes; + } + + private static void verifyRead(byte[] data, int expected, int N) { + ByteBuffer buf = ByteBuffer.wrap(data, 0, data.length); + IntegerReader reader = new IntegerReader(); + reader.configure(N).read(buf); + assertEquals(expected, reader.get()); + } + + private void verifyWrite(byte[] expected, int data, int N) { + IntegerWriter w = new IntegerWriter(); + ByteBuffer buf = ByteBuffer.allocate(2 * expected.length); + w.configure(data, N, 1).write(buf); + buf.flip(); + assertEquals(ByteBuffer.wrap(expected), buf); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java new file mode 100644 index 00000000000..4f9631647c7 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/BuffersTestingKit.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.nio.ByteBuffer.allocate; + +public final class BuffersTestingKit { + + /** + * Relocates a {@code [position, limit)} region of the given buffer to + * corresponding region in a new buffer starting with provided {@code + * newPosition}. + * + *

Might be useful to make sure ByteBuffer's users do not rely on any + * absolute positions, but solely on what's reported by position(), limit(). + * + *

The contents between the given buffer and the returned one are not + * shared. + */ + public static ByteBuffer relocate(ByteBuffer buffer, int newPosition, + int newCapacity) { + int oldPosition = buffer.position(); + int oldLimit = buffer.limit(); + + if (newPosition + oldLimit - oldPosition > newCapacity) { + throw new IllegalArgumentException(); + } + + ByteBuffer result; + if (buffer.isDirect()) { + result = ByteBuffer.allocateDirect(newCapacity); + } else { + result = allocate(newCapacity); + } + + result.position(newPosition); + result.put(buffer).limit(result.position()).position(newPosition); + buffer.position(oldPosition); + + if (buffer.isReadOnly()) { + return result.asReadOnlyBuffer(); + } + return result; + } + + public static Iterable relocateBuffers( + Iterable source) { + return () -> + new Iterator() { + + private final Iterator it = source.iterator(); + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public ByteBuffer next() { + ByteBuffer buf = it.next(); + int remaining = buf.remaining(); + int newCapacity = remaining + random.nextInt(17); + int newPosition = random.nextInt(newCapacity - remaining + 1); + return relocate(buf, newPosition, newCapacity); + } + }; + } + + // TODO: not always of size 0 (it's fine for buffer to report !b.hasRemaining()) + public static Iterable injectEmptyBuffers( + Iterable source) { + return injectEmptyBuffers(source, () -> allocate(0)); + } + + public static Iterable injectEmptyBuffers( + Iterable source, + Supplier emptyBufferFactory) { + + return () -> + new Iterator() { + + private final Iterator it = source.iterator(); + private ByteBuffer next = calculateNext(); + + private ByteBuffer calculateNext() { + if (random.nextBoolean()) { + return emptyBufferFactory.get(); + } else if (it.hasNext()) { + return it.next(); + } else { + return null; + } + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public ByteBuffer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + ByteBuffer next = this.next; + this.next = calculateNext(); + return next; + } + }; + } + + public static ByteBuffer concat(Iterable split) { + return concat(split, ByteBuffer::allocate); + } + + public static ByteBuffer concat(Iterable split, + Function concatBufferFactory) { + int size = 0; + for (ByteBuffer bb : split) { + size += bb.remaining(); + } + + ByteBuffer result = concatBufferFactory.apply(size); + for (ByteBuffer bb : split) { + result.put(bb); + } + + result.flip(); + return result; + } + + public static void forEachSplit(ByteBuffer bb, + Consumer> action) { + forEachSplit(bb.remaining(), + (lengths) -> { + int end = bb.position(); + List buffers = new LinkedList<>(); + for (int len : lengths) { + ByteBuffer d = bb.duplicate(); + d.position(end); + d.limit(end + len); + end += len; + buffers.add(d); + } + action.accept(buffers); + }); + } + + private static void forEachSplit(int n, Consumer> action) { + forEachSplit(n, new Stack<>(), action); + } + + private static void forEachSplit(int n, Stack path, + Consumer> action) { + if (n == 0) { + action.accept(path); + } else { + for (int i = 1; i <= n; i++) { + path.push(i); + forEachSplit(n - i, path, action); + path.pop(); + } + } + } + + private static final Random random = new Random(); + + private BuffersTestingKit() { + throw new InternalError(); + } + +// public static void main(String[] args) { +// +// List buffers = Arrays.asList( +// (ByteBuffer) allocate(3).position(1).limit(2), +// allocate(0), +// allocate(7)); +// +// Iterable buf = relocateBuffers(injectEmptyBuffers(buffers)); +// List result = new ArrayList<>(); +// buf.forEach(result::add); +// System.out.println(result); +// } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java new file mode 100644 index 00000000000..ebf1cb1d1ee --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/CircularBufferTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import sun.net.httpclient.hpack.HeaderTable.CircularBuffer; + +import java.util.Queue; +import java.util.Random; +import java.util.concurrent.ArrayBlockingQueue; + +import static org.testng.Assert.assertEquals; +import static sun.net.httpclient.hpack.TestHelper.newRandom; + +public final class CircularBufferTest { + + private final Random r = newRandom(); + + @BeforeClass + public void setUp() { + r.setSeed(System.currentTimeMillis()); + } + + @Test + public void queue() { + for (int capacity = 1; capacity <= 2048; capacity++) { + queueOnce(capacity, 32); + } + } + + @Test + public void resize() { + for (int capacity = 1; capacity <= 4096; capacity++) { + resizeOnce(capacity); + } + } + + @Test + public void downSizeEmptyBuffer() { + CircularBuffer buffer = new CircularBuffer<>(16); + buffer.resize(15); + } + + private void resizeOnce(int capacity) { + + int nextNumberToPut = 0; + + Queue referenceQueue = new ArrayBlockingQueue<>(capacity); + CircularBuffer buffer = new CircularBuffer<>(capacity); + + // Fill full, so the next add will wrap + for (int i = 0; i < capacity; i++, nextNumberToPut++) { + buffer.add(nextNumberToPut); + referenceQueue.add(nextNumberToPut); + } + int gets = r.nextInt(capacity); // [0, capacity) + for (int i = 0; i < gets; i++) { + referenceQueue.poll(); + buffer.remove(); + } + int puts = r.nextInt(gets + 1); // [0, gets] + for (int i = 0; i < puts; i++, nextNumberToPut++) { + buffer.add(nextNumberToPut); + referenceQueue.add(nextNumberToPut); + } + + Integer[] expected = referenceQueue.toArray(new Integer[0]); + buffer.resize(expected.length); + + assertEquals(buffer.elements, expected); + } + + private void queueOnce(int capacity, int numWraps) { + + Queue referenceQueue = new ArrayBlockingQueue<>(capacity); + CircularBuffer buffer = new CircularBuffer<>(capacity); + + int nextNumberToPut = 0; + int totalPuts = 0; + int putsLimit = capacity * numWraps; + int remainingCapacity = capacity; + int size = 0; + + while (totalPuts < putsLimit) { + assert remainingCapacity + size == capacity; + int puts = r.nextInt(remainingCapacity + 1); // [0, remainingCapacity] + remainingCapacity -= puts; + size += puts; + for (int i = 0; i < puts; i++, nextNumberToPut++) { + referenceQueue.add(nextNumberToPut); + buffer.add(nextNumberToPut); + } + totalPuts += puts; + int gets = r.nextInt(size + 1); // [0, size] + size -= gets; + remainingCapacity += gets; + for (int i = 0; i < gets; i++) { + Integer expected = referenceQueue.poll(); + Integer actual = buffer.remove(); + assertEquals(actual, expected); + } + } + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java new file mode 100644 index 00000000000..29a651fb0f7 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/DecoderTest.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.io.UncheckedIOException; +import java.net.ProtocolException; +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static sun.net.httpclient.hpack.TestHelper.*; + +public final class DecoderTest { + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 + // + @Test + public void example1() { + // @formatter:off + test("400a 6375 7374 6f6d 2d6b 6579 0d63 7573\n" + + "746f 6d2d 6865 6164 6572", + + "[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55", + + "custom-key: custom-header"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.2 + // + @Test + public void example2() { + // @formatter:off + test("040c 2f73 616d 706c 652f 7061 7468", + "empty.", + ":path: /sample/path"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.3 + // + @Test + public void example3() { + // @formatter:off + test("1008 7061 7373 776f 7264 0673 6563 7265\n" + + "74", + "empty.", + "password: secret"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.4 + // + @Test + public void example4() { + // @formatter:off + test("82", + "empty.", + ":method: GET"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.3 + // + @Test + public void example5() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + + "2e63 6f6d", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com"); + + test(d, "8286 84be 5808 6e6f 2d63 6163 6865", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com\n" + + "cache-control: no-cache"); + + test(d, "8287 85bf 400a 6375 7374 6f6d 2d6b 6579\n" + + "0c63 7573 746f 6d2d 7661 6c75 65", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164", + + ":method: GET\n" + + ":scheme: https\n" + + ":path: /index.html\n" + + ":authority: www.example.com\n" + + "custom-key: custom-value"); + + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.4 + // + @Test + public void example6() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4\n" + + "ff", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com"); + + test(d, "8286 84be 5886 a8eb 1064 9cbf", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110", + + ":method: GET\n" + + ":scheme: http\n" + + ":path: /\n" + + ":authority: www.example.com\n" + + "cache-control: no-cache"); + + test(d, "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925\n" + + "a849 e95b b8e8 b4bf", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164", + + ":method: GET\n" + + ":scheme: https\n" + + ":path: /index.html\n" + + ":authority: www.example.com\n" + + "custom-key: custom-value"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.5 + // + @Test + public void example7() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "4803 3330 3258 0770 7269 7661 7465 611d\n" + + "4d6f 6e2c 2032 3120 4f63 7420 3230 3133\n" + + "2032 303a 3133 3a32 3120 474d 546e 1768\n" + + "7474 7073 3a2f 2f77 7777 2e65 7861 6d70\n" + + "6c65 2e63 6f6d", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222", + + ":status: 302\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "4803 3330 37c1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222", + + ":status: 307\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420\n" + + "3230 3133 2032 303a 3133 3a32 3220 474d\n" + + "54c0 5a04 677a 6970 7738 666f 6f3d 4153\n" + + "444a 4b48 514b 425a 584f 5157 454f 5049\n" + + "5541 5851 5745 4f49 553b 206d 6178 2d61\n" + + "6765 3d33 3630 303b 2076 6572 7369 6f6e\n" + + "3d31", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215", + + ":status: 200\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + "location: https://www.example.com\n" + + "content-encoding: gzip\n" + + "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.6 + // + @Test + public void example8() { + // @formatter:off + Decoder d = new Decoder(256); + + test(d, "4882 6402 5885 aec3 771a 4b61 96d0 7abe\n" + + "9410 54d4 44a8 2005 9504 0b81 66e0 82a6\n" + + "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8\n" + + "e9ae 82ae 43d3", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222", + + ":status: 302\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "4883 640e ffc1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222", + + ":status: 307\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "location: https://www.example.com"); + + test(d, "88c1 6196 d07a be94 1054 d444 a820 0595\n" + + "040b 8166 e084 a62d 1bff c05a 839b d9ab\n" + + "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b\n" + + "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f\n" + + "9587 3160 65c0 03ed 4ee5 b106 3d50 07", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215", + + ":status: 200\n" + + "cache-control: private\n" + + "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + "location: https://www.example.com\n" + + "content-encoding: gzip\n" + + "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + // @formatter:on + } + + @Test + // One of responses from Apache Server that helped to catch a bug + public void testX() { + Decoder d = new Decoder(4096); + // @formatter:off + test(d, "3fe1 1f88 6196 d07a be94 03ea 693f 7504\n" + + "00b6 a05c b827 2e32 fa98 b46f 769e 86b1\n" + + "9272 b025 da5c 2ea9 fd70 a8de 7fb5 3556\n" + + "5ab7 6ece c057 02e2 2ad2 17bf 6c96 d07a\n" + + "be94 0854 cb6d 4a08 0075 40bd 71b6 6e05\n" + + "a531 68df 0f13 8efe 4522 cd32 21b6 5686\n" + + "eb23 781f cf52 848f d24a 8f0f 0d02 3435\n" + + "5f87 497c a589 d34d 1f", + + "[ 1] (s = 53) content-type: text/html\n" + + "[ 2] (s = 50) accept-ranges: bytes\n" + + "[ 3] (s = 74) last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + + "[ 4] (s = 77) server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + + "[ 5] (s = 65) date: Mon, 09 Nov 2015 16:26:39 GMT\n" + + " Table size: 319", + + ":status: 200\n" + + "date: Mon, 09 Nov 2015 16:26:39 GMT\n" + + "server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + + "last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + + "etag: \"2d-432a5e4a73a80\"\n" + + "accept-ranges: bytes\n" + + "content-length: 45\n" + + "content-type: text/html"); + // @formatter:on + } + + // + // This test is missing in the spec + // + @Test + public void sizeUpdate() { + Decoder d = new Decoder(4096); + assertEquals(d.getTable().maxSize(), 4096); + d.decode(ByteBuffer.wrap(new byte[]{0b00111110}), true, nopCallback()); // newSize = 30 + assertEquals(d.getTable().maxSize(), 30); + } + + @Test + public void incorrectSizeUpdate() { + ByteBuffer b = ByteBuffer.allocate(8); + Encoder e = new Encoder(8192) { + @Override + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + }; + e.header("a", "b"); + e.encode(b); + b.flip(); + { + Decoder d = new Decoder(4096); + UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(b, true, (name, value) -> { })); + + assertNotNull(ex.getCause()); + assertEquals(ex.getCause().getClass(), ProtocolException.class); + } + b.flip(); + { + Decoder d = new Decoder(4096); + UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(b, false, (name, value) -> { })); + + assertNotNull(ex.getCause()); + assertEquals(ex.getCause().getClass(), ProtocolException.class); + } + } + + @Test + public void corruptedHeaderBlockInteger() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + (byte) 0b10011010 // 25 + ... + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + // 5.1. Integer Representation + // ... + // Integer encodings that exceed implementation limits -- in value or octet + // length -- MUST be treated as decoding errors. Different limits can + // be set for each of the different uses of integers, based on + // implementation constraints. + @Test + public void headerBlockIntegerNoOverflow() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + 127 + // Integer.MAX_VALUE - 127 (base 128, little-endian): + (byte) 0b10000000, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b00000111 + }); + + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "index=2147483647"); + } + + @Test + public void headerBlockIntegerOverflow() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + (byte) 0b11111111, // indexed + 127 + // Integer.MAX_VALUE - 127 + 1 (base 128, little endian): + (byte) 0b10000001, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b11111111, + (byte) 0b00000111 + }); + + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Integer overflow"); + } + + @Test + public void corruptedHeaderBlockString1() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + 0b00001000, // huffman=false, length=8 + 0b00000000, // \ + 0b00000000, // but only 3 octets available... + 0b00000000 // / + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + @Test + public void corruptedHeaderBlockString2() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10001000, // huffman=true, length=8 + 0b00000000, // \ + 0b00000000, // \ + 0b00000000, // but only 5 octets available... + 0b00000000, // / + 0b00000000 // / + }); + UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, + () -> d.decode(data, true, nopCallback())); + assertNotNull(e.getCause()); + assertEquals(e.getCause().getClass(), ProtocolException.class); + assertExceptionMessageContains(e, "Unexpected end of header block"); + } + + // 5.2. String Literal Representation + // ...A Huffman-encoded string literal containing the EOS symbol MUST be + // treated as a decoding error... + @Test + public void corruptedHeaderBlockHuffmanStringEOS() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000110, // huffman=true, length=6 + 0b00011001, 0b01001101, (byte) 0b11111111, + (byte) 0b11111111, (byte) 0b11111111, (byte) 0b11111100 + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Encountered EOS"); + } + + // 5.2. String Literal Representation + // ...A padding strictly longer than 7 bits MUST be treated as a decoding + // error... + @Test + public void corruptedHeaderBlockHuffmanStringLongPadding1() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01001101, (byte) 0b11111111 + // len("aei") + len(padding) = (5 + 5 + 5) + (9) + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Padding is too long", "len=9"); + } + + @Test + public void corruptedHeaderBlockHuffmanStringLongPadding2() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01111010, (byte) 0b11111111 + // len("aek") + len(padding) = (5 + 5 + 7) + (7) + }); + assertVoidDoesNotThrow(() -> d.decode(data, true, nopCallback())); + } + + // 5.2. String Literal Representation + // ...A padding not corresponding to the most significant bits of the code + // for the EOS symbol MUST be treated as a decoding error... + @Test + public void corruptedHeaderBlockHuffmanStringNotEOSPadding() { + Decoder d = new Decoder(4096); + ByteBuffer data = ByteBuffer.wrap(new byte[]{ + 0b00001111, // literal, index=15 + 0b00000000, + (byte) 0b10000011, // huffman=true, length=3 + 0b00011001, 0b01111010, (byte) 0b11111110 + }); + IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, + () -> d.decode(data, true, nopCallback())); + + assertExceptionMessageContains(e, "Not a EOS prefix"); + } + + @Test + public void argsTestBiConsumerIsNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(ByteBuffer.allocate(16), true, null)); + } + + @Test + public void argsTestByteBufferIsNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(null, true, nopCallback())); + } + + @Test + public void argsTestBothAreNull() { + Decoder decoder = new Decoder(4096); + assertVoidThrows(NullPointerException.class, + () -> decoder.decode(null, true, null)); + } + + private static void test(String hexdump, + String headerTable, String headerList) { + test(new Decoder(4096), hexdump, headerTable, headerList); + } + + // + // Sometimes we need to keep the same decoder along several runs, + // as it models the same connection + // + private static void test(Decoder d, String hexdump, + String expectedHeaderTable, String expectedHeaderList) { + + ByteBuffer source = SpecHelper.toBytes(hexdump); + + List actual = new LinkedList<>(); + d.decode(source, true, (name, value) -> { + if (value == null) { + actual.add(name.toString()); + } else { + actual.add(name + ": " + value); + } + }); + + assertEquals(d.getTable().getStateString(), expectedHeaderTable); + assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); + } + + private static DecodingCallback nopCallback() { + return (t, u) -> { }; + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java new file mode 100644 index 00000000000..c7b375b1238 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/EncoderTest.java @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import static java.util.Arrays.asList; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static sun.net.httpclient.hpack.SpecHelper.toHexdump; +import static sun.net.httpclient.hpack.TestHelper.assertVoidThrows; + +// TODO: map textual representation of commands from the spec to actual +// calls to encoder (actually, this is a good idea for decoder as well) +public final class EncoderTest { + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 + // + @Test + public void example1() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literalWithIndexing("custom-key", false, "custom-header", false); + // @formatter:off + test(e, + + "400a 6375 7374 6f6d 2d6b 6579 0d63 7573\n" + + "746f 6d2d 6865 6164 6572", + + "[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.2 + // + @Test + public void example2() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literal(4, "/sample/path", false); + // @formatter:off + test(e, + + "040c 2f73 616d 706c 652f 7061 7468", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.3 + // + @Test + public void example3() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.literalNeverIndexed("password", false, "secret", false); + // @formatter:off + test(e, + + "1008 7061 7373 776f 7264 0673 6563 7265\n" + + "74", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.2.4 + // + @Test + public void example4() { + + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + e.indexed(2); + // @formatter:off + test(e, + + "82", + + "empty."); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.3 + // + @Test + public void example5() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(64); + e.indexed(2); + e.encode(output); + e.indexed(6); + e.encode(output); + e.indexed(4); + e.encode(output); + e.literalWithIndexing(1, "www.example.com", false); + e.encode(output); + + output.flip(); + + // @formatter:off + test(e, output, + + "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + + "2e63 6f6d", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 6); + e.encode(output); + e.indexed( 4); + e.encode(output); + e.indexed(62); + e.encode(output); + e.literalWithIndexing(24, "no-cache", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "8286 84be 5808 6e6f 2d63 6163 6865", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 7); + e.encode(output); + e.indexed( 5); + e.encode(output); + e.indexed(63); + e.encode(output); + e.literalWithIndexing("custom-key", false, "custom-value", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "8287 85bf 400a 6375 7374 6f6d 2d6b 6579\n" + + "0c63 7573 746f 6d2d 7661 6c75 65", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.4 + // + @Test + public void example6() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(64); + e.indexed(2); + e.encode(output); + e.indexed(6); + e.encode(output); + e.indexed(4); + e.encode(output); + e.literalWithIndexing(1, "www.example.com", true); + e.encode(output); + + output.flip(); + + // @formatter:off + test(e, output, + + "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4\n" + + "ff", + + "[ 1] (s = 57) :authority: www.example.com\n" + + " Table size: 57"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 6); + e.encode(output); + e.indexed( 4); + e.encode(output); + e.indexed(62); + e.encode(output); + e.literalWithIndexing(24, "no-cache", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "8286 84be 5886 a8eb 1064 9cbf", + + "[ 1] (s = 53) cache-control: no-cache\n" + + "[ 2] (s = 57) :authority: www.example.com\n" + + " Table size: 110"); + + output.clear(); + + e.indexed( 2); + e.encode(output); + e.indexed( 7); + e.encode(output); + e.indexed( 5); + e.encode(output); + e.indexed(63); + e.encode(output); + e.literalWithIndexing("custom-key", true, "custom-value", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925\n" + + "a849 e95b b8e8 b4bf", + + "[ 1] (s = 54) custom-key: custom-value\n" + + "[ 2] (s = 53) cache-control: no-cache\n" + + "[ 3] (s = 57) :authority: www.example.com\n" + + " Table size: 164"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.5 + // + @Test + public void example7() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(128); + // @formatter:off + e.literalWithIndexing( 8, "302", false); + e.encode(output); + e.literalWithIndexing(24, "private", false); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:21 GMT", false); + e.encode(output); + e.literalWithIndexing(46, "https://www.example.com", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "4803 3330 3258 0770 7269 7661 7465 611d\n" + + "4d6f 6e2c 2032 3120 4f63 7420 3230 3133\n" + + "2032 303a 3133 3a32 3120 474d 546e 1768\n" + + "7474 7073 3a2f 2f77 7777 2e65 7861 6d70\n" + + "6c65 2e63 6f6d", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222"); + + output.clear(); + + e.literalWithIndexing( 8, "307", false); + e.encode(output); + e.indexed(65); + e.encode(output); + e.indexed(64); + e.encode(output); + e.indexed(63); + e.encode(output); + + output.flip(); + + test(e, output, + + "4803 3330 37c1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222"); + + output.clear(); + + e.indexed( 8); + e.encode(output); + e.indexed(65); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:22 GMT", false); + e.encode(output); + e.indexed(64); + e.encode(output); + e.literalWithIndexing(26, "gzip", false); + e.encode(output); + e.literalWithIndexing(55, "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", false); + e.encode(output); + + output.flip(); + + test(e, output, + + "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420\n" + + "3230 3133 2032 303a 3133 3a32 3220 474d\n" + + "54c0 5a04 677a 6970 7738 666f 6f3d 4153\n" + + "444a 4b48 514b 425a 584f 5157 454f 5049\n" + + "5541 5851 5745 4f49 553b 206d 6178 2d61\n" + + "6765 3d33 3630 303b 2076 6572 7369 6f6e\n" + + "3d31", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215"); + // @formatter:on + } + + // + // http://tools.ietf.org/html/rfc7541#appendix-C.6 + // + @Test + public void example8() { + Encoder e = newCustomEncoder(256); + drainInitialUpdate(e); + + ByteBuffer output = ByteBuffer.allocate(128); + // @formatter:off + e.literalWithIndexing( 8, "302", true); + e.encode(output); + e.literalWithIndexing(24, "private", true); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:21 GMT", true); + e.encode(output); + e.literalWithIndexing(46, "https://www.example.com", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "4882 6402 5885 aec3 771a 4b61 96d0 7abe\n" + + "9410 54d4 44a8 2005 9504 0b81 66e0 82a6\n" + + "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8\n" + + "e9ae 82ae 43d3", + + "[ 1] (s = 63) location: https://www.example.com\n" + + "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 3] (s = 52) cache-control: private\n" + + "[ 4] (s = 42) :status: 302\n" + + " Table size: 222"); + + output.clear(); + + e.literalWithIndexing( 8, "307", true); + e.encode(output); + e.indexed(65); + e.encode(output); + e.indexed(64); + e.encode(output); + e.indexed(63); + e.encode(output); + + output.flip(); + + test(e, output, + + "4883 640e ffc1 c0bf", + + "[ 1] (s = 42) :status: 307\n" + + "[ 2] (s = 63) location: https://www.example.com\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + + "[ 4] (s = 52) cache-control: private\n" + + " Table size: 222"); + + output.clear(); + + e.indexed( 8); + e.encode(output); + e.indexed(65); + e.encode(output); + e.literalWithIndexing(33, "Mon, 21 Oct 2013 20:13:22 GMT", true); + e.encode(output); + e.indexed(64); + e.encode(output); + e.literalWithIndexing(26, "gzip", true); + e.encode(output); + e.literalWithIndexing(55, "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", true); + e.encode(output); + + output.flip(); + + test(e, output, + + "88c1 6196 d07a be94 1054 d444 a820 0595\n" + + "040b 8166 e084 a62d 1bff c05a 839b d9ab\n" + + "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b\n" + + "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f\n" + + "9587 3160 65c0 03ed 4ee5 b106 3d50 07", + + "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + + "[ 2] (s = 52) content-encoding: gzip\n" + + "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + + " Table size: 215"); + // @formatter:on + } + + @Test + public void initialSizeUpdateDefaultEncoder() { + Function e = Encoder::new; + testSizeUpdate(e, 1024, asList(), asList(0)); + testSizeUpdate(e, 1024, asList(1024), asList(0)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList(0)); + testSizeUpdate(e, 1024, asList(1024, 512), asList(0)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(0)); + testSizeUpdate(e, 1024, asList(512, 2048), asList(0)); + } + + @Test + public void initialSizeUpdateCustomEncoder() { + Function e = EncoderTest::newCustomEncoder; + testSizeUpdate(e, 1024, asList(), asList(1024)); + testSizeUpdate(e, 1024, asList(1024), asList(1024)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList(1024)); + testSizeUpdate(e, 1024, asList(1024, 512), asList(512)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(1024)); + testSizeUpdate(e, 1024, asList(512, 2048), asList(2048)); + } + + @Test + public void seriesOfSizeUpdatesDefaultEncoder() { + Function e = c -> { + Encoder encoder = new Encoder(c); + drainInitialUpdate(encoder); + return encoder; + }; + testSizeUpdate(e, 0, asList(0), asList()); + testSizeUpdate(e, 1024, asList(1024), asList()); + testSizeUpdate(e, 1024, asList(2048), asList()); + testSizeUpdate(e, 1024, asList(512), asList()); + testSizeUpdate(e, 1024, asList(1024, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 2048), asList()); + testSizeUpdate(e, 1024, asList(2048, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 512), asList()); + testSizeUpdate(e, 1024, asList(512, 1024), asList()); + } + + // + // https://tools.ietf.org/html/rfc7541#section-4.2 + // + @Test + public void seriesOfSizeUpdatesCustomEncoder() { + Function e = c -> { + Encoder encoder = newCustomEncoder(c); + drainInitialUpdate(encoder); + return encoder; + }; + testSizeUpdate(e, 0, asList(0), asList()); + testSizeUpdate(e, 1024, asList(1024), asList()); + testSizeUpdate(e, 1024, asList(2048), asList(2048)); + testSizeUpdate(e, 1024, asList(512), asList(512)); + testSizeUpdate(e, 1024, asList(1024, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 2048), asList(2048)); + testSizeUpdate(e, 1024, asList(2048, 1024), asList()); + testSizeUpdate(e, 1024, asList(1024, 512), asList(512)); + testSizeUpdate(e, 1024, asList(512, 1024), asList(512, 1024)); + } + + @Test + public void callSequenceViolations() { + { // Hasn't set up a header + Encoder e = new Encoder(0); + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + { // Can't set up header while there's an unfinished encoding + Encoder e = new Encoder(0); + e.indexed(32); + assertVoidThrows(IllegalStateException.class, () -> e.indexed(32)); + } + { // Can't setMaxCapacity while there's an unfinished encoding + Encoder e = new Encoder(0); + e.indexed(32); + assertVoidThrows(IllegalStateException.class, () -> e.setMaxCapacity(512)); + } + { // Hasn't set up a header + Encoder e = new Encoder(0); + e.setMaxCapacity(256); + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + { // Hasn't set up a header after the previous encoding + Encoder e = new Encoder(0); + e.indexed(0); + boolean encoded = e.encode(ByteBuffer.allocate(16)); + assertTrue(encoded); // assumption + assertVoidThrows(IllegalStateException.class, () -> e.encode(ByteBuffer.allocate(16))); + } + } + + private static void test(Encoder encoder, + String expectedTableState, + String expectedHexdump) { + + ByteBuffer b = ByteBuffer.allocate(128); + encoder.encode(b); + b.flip(); + test(encoder, b, expectedTableState, expectedHexdump); + } + + private static void test(Encoder encoder, + ByteBuffer output, + String expectedHexdump, + String expectedTableState) { + + String actualTableState = encoder.getHeaderTable().getStateString(); + assertEquals(actualTableState, expectedTableState); + + String actualHexdump = toHexdump(output); + assertEquals(actualHexdump, expectedHexdump.replaceAll("\\n", " ")); + } + + // initial size - the size encoder is constructed with + // updates - a sequence of values for consecutive calls to encoder.setMaxCapacity + // expected - a sequence of values expected to be decoded by a decoder + private void testSizeUpdate(Function encoder, + int initialSize, + List updates, + List expected) { + Encoder e = encoder.apply(initialSize); + updates.forEach(e::setMaxCapacity); + ByteBuffer b = ByteBuffer.allocate(64); + e.header("a", "b"); + e.encode(b); + b.flip(); + Decoder d = new Decoder(updates.isEmpty() ? initialSize : Collections.max(updates)); + List actual = new ArrayList<>(); + d.decode(b, true, new DecodingCallback() { + @Override + public void onDecoded(CharSequence name, CharSequence value) { } + + @Override + public void onSizeUpdate(int capacity) { + actual.add(capacity); + } + }); + assertEquals(actual, expected); + } + + // + // Default encoder does not need any table, therefore a subclass that + // behaves differently is needed + // + private static Encoder newCustomEncoder(int maxCapacity) { + return new Encoder(maxCapacity) { + @Override + protected int calculateCapacity(int maxCapacity) { + return maxCapacity; + } + }; + } + + private static void drainInitialUpdate(Encoder e) { + ByteBuffer b = ByteBuffer.allocate(4); + e.header("a", "b"); + boolean done; + do { + done = e.encode(b); + b.flip(); + } while (!done); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java new file mode 100644 index 00000000000..1bc12029ca6 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HeaderTableTest.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; +import sun.net.httpclient.hpack.HeaderTable.HeaderField; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.String.format; +import static org.testng.Assert.assertEquals; +import static sun.net.httpclient.hpack.TestHelper.*; + +public class HeaderTableTest { + + // + // https://tools.ietf.org/html/rfc7541#appendix-A + // + // @formatter:off + private static final String SPEC = + " | 1 | :authority | |\n" + + " | 2 | :method | GET |\n" + + " | 3 | :method | POST |\n" + + " | 4 | :path | / |\n" + + " | 5 | :path | /index.html |\n" + + " | 6 | :scheme | http |\n" + + " | 7 | :scheme | https |\n" + + " | 8 | :status | 200 |\n" + + " | 9 | :status | 204 |\n" + + " | 10 | :status | 206 |\n" + + " | 11 | :status | 304 |\n" + + " | 12 | :status | 400 |\n" + + " | 13 | :status | 404 |\n" + + " | 14 | :status | 500 |\n" + + " | 15 | accept-charset | |\n" + + " | 16 | accept-encoding | gzip, deflate |\n" + + " | 17 | accept-language | |\n" + + " | 18 | accept-ranges | |\n" + + " | 19 | accept | |\n" + + " | 20 | access-control-allow-origin | |\n" + + " | 21 | age | |\n" + + " | 22 | allow | |\n" + + " | 23 | authorization | |\n" + + " | 24 | cache-control | |\n" + + " | 25 | content-disposition | |\n" + + " | 26 | content-encoding | |\n" + + " | 27 | content-language | |\n" + + " | 28 | content-length | |\n" + + " | 29 | content-location | |\n" + + " | 30 | content-range | |\n" + + " | 31 | content-type | |\n" + + " | 32 | cookie | |\n" + + " | 33 | date | |\n" + + " | 34 | etag | |\n" + + " | 35 | expect | |\n" + + " | 36 | expires | |\n" + + " | 37 | from | |\n" + + " | 38 | host | |\n" + + " | 39 | if-match | |\n" + + " | 40 | if-modified-since | |\n" + + " | 41 | if-none-match | |\n" + + " | 42 | if-range | |\n" + + " | 43 | if-unmodified-since | |\n" + + " | 44 | last-modified | |\n" + + " | 45 | link | |\n" + + " | 46 | location | |\n" + + " | 47 | max-forwards | |\n" + + " | 48 | proxy-authenticate | |\n" + + " | 49 | proxy-authorization | |\n" + + " | 50 | range | |\n" + + " | 51 | referer | |\n" + + " | 52 | refresh | |\n" + + " | 53 | retry-after | |\n" + + " | 54 | server | |\n" + + " | 55 | set-cookie | |\n" + + " | 56 | strict-transport-security | |\n" + + " | 57 | transfer-encoding | |\n" + + " | 58 | user-agent | |\n" + + " | 59 | vary | |\n" + + " | 60 | via | |\n" + + " | 61 | www-authenticate | |\n"; + // @formatter:on + + private static final int STATIC_TABLE_LENGTH = createStaticEntries().size(); + private final Random rnd = newRandom(); + + @Test + public void staticData() { + HeaderTable table = new HeaderTable(0); + Map staticHeaderFields = createStaticEntries(); + + Map minimalIndexes = new HashMap<>(); + + for (Map.Entry e : staticHeaderFields.entrySet()) { + Integer idx = e.getKey(); + String hName = e.getValue().name; + Integer midx = minimalIndexes.get(hName); + if (midx == null) { + minimalIndexes.put(hName, idx); + } else { + minimalIndexes.put(hName, Math.min(idx, midx)); + } + } + + staticHeaderFields.entrySet().forEach( + e -> { + // lookup + HeaderField actualHeaderField = table.get(e.getKey()); + HeaderField expectedHeaderField = e.getValue(); + assertEquals(actualHeaderField, expectedHeaderField); + + // reverse lookup (name, value) + String hName = expectedHeaderField.name; + String hValue = expectedHeaderField.value; + int expectedIndex = e.getKey(); + int actualIndex = table.indexOf(hName, hValue); + + assertEquals(actualIndex, expectedIndex); + + // reverse lookup (name) + int expectedMinimalIndex = minimalIndexes.get(hName); + int actualMinimalIndex = table.indexOf(hName, "blah-blah"); + + assertEquals(-actualMinimalIndex, expectedMinimalIndex); + } + ); + } + + @Test + public void constructorSetsMaxSize() { + int size = rnd.nextInt(64); + HeaderTable t = new HeaderTable(size); + assertEquals(t.size(), 0); + assertEquals(t.maxSize(), size); + } + + @Test + public void negativeMaximumSize() { + int maxSize = -(rnd.nextInt(100) + 1); // [-100, -1] + IllegalArgumentException e = + assertVoidThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).setMaxSize(maxSize)); + assertExceptionMessageContains(e, "maxSize"); + } + + @Test + public void zeroMaximumSize() { + HeaderTable table = new HeaderTable(0); + table.setMaxSize(0); + assertEquals(table.maxSize(), 0); + } + + @Test + public void negativeIndex() { + int idx = -(rnd.nextInt(256) + 1); // [-256, -1] + IllegalArgumentException e = + assertVoidThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).get(idx)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void zeroIndex() { + IllegalArgumentException e = + assertThrows(IllegalArgumentException.class, + () -> new HeaderTable(0).get(0)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void length() { + HeaderTable table = new HeaderTable(0); + assertEquals(table.length(), STATIC_TABLE_LENGTH); + } + + @Test + public void indexOutsideStaticRange() { + HeaderTable table = new HeaderTable(0); + int idx = table.length() + (rnd.nextInt(256) + 1); + IllegalArgumentException e = + assertThrows(IllegalArgumentException.class, + () -> table.get(idx)); + assertExceptionMessageContains(e, "index"); + } + + @Test + public void entryPutAfterStaticArea() { + HeaderTable table = new HeaderTable(256); + int idx = table.length() + 1; + assertThrows(IllegalArgumentException.class, () -> table.get(idx)); + + byte[] bytes = new byte[32]; + rnd.nextBytes(bytes); + String name = new String(bytes, StandardCharsets.ISO_8859_1); + String value = "custom-value"; + + table.put(name, value); + HeaderField f = table.get(idx); + assertEquals(name, f.name); + assertEquals(value, f.value); + } + + @Test + public void staticTableHasZeroSize() { + HeaderTable table = new HeaderTable(0); + assertEquals(0, table.size()); + } + + @Test + public void lowerIndexPriority() { + HeaderTable table = new HeaderTable(256); + int oldLength = table.length(); + table.put("bender", "rodriguez"); + table.put("bender", "rodriguez"); + table.put("bender", "rodriguez"); + + assertEquals(table.length(), oldLength + 3); // more like an assumption + int i = table.indexOf("bender", "rodriguez"); + assertEquals(oldLength + 1, i); + } + + @Test + public void lowerIndexPriority2() { + HeaderTable table = new HeaderTable(256); + int oldLength = table.length(); + int idx = rnd.nextInt(oldLength) + 1; + HeaderField f = table.get(idx); + table.put(f.name, f.value); + assertEquals(table.length(), oldLength + 1); + int i = table.indexOf(f.name, f.value); + assertEquals(idx, i); + } + + // TODO: negative indexes check + // TODO: ensure full table clearance when adding huge header field + // TODO: ensure eviction deletes minimum needed entries, not more + + @Test + public void fifo() { + HeaderTable t = new HeaderTable(Integer.MAX_VALUE); + // Let's add a series of header fields + int NUM_HEADERS = 32; + for (int i = 1; i <= NUM_HEADERS; i++) { + String s = String.valueOf(i); + t.put(s, s); + } + // They MUST appear in a FIFO order: + // newer entries are at lower indexes + // older entries are at higher indexes + for (int j = 1; j <= NUM_HEADERS; j++) { + HeaderField f = t.get(STATIC_TABLE_LENGTH + j); + int actualName = Integer.parseInt(f.name); + int expectedName = NUM_HEADERS - j + 1; + assertEquals(expectedName, actualName); + } + // Entries MUST be evicted in the order they were added: + // the newer the entry the later it is evicted + for (int k = 1; k <= NUM_HEADERS; k++) { + HeaderField f = t.evictEntry(); + assertEquals(String.valueOf(k), f.name); + } + } + + @Test + public void indexOf() { + HeaderTable t = new HeaderTable(Integer.MAX_VALUE); + // Let's put a series of header fields + int NUM_HEADERS = 32; + for (int i = 1; i <= NUM_HEADERS; i++) { + String s = String.valueOf(i); + t.put(s, s); + } + // and verify indexOf (reverse lookup) returns correct indexes for + // full lookup + for (int j = 1; j <= NUM_HEADERS; j++) { + String s = String.valueOf(j); + int actualIndex = t.indexOf(s, s); + int expectedIndex = STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1; + assertEquals(expectedIndex, actualIndex); + } + // as well as for just a name lookup + for (int j = 1; j <= NUM_HEADERS; j++) { + String s = String.valueOf(j); + int actualIndex = t.indexOf(s, "blah"); + int expectedIndex = -(STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1); + assertEquals(expectedIndex, actualIndex); + } + // lookup for non-existent name returns 0 + assertEquals(0, t.indexOf("chupacabra", "1")); + } + + @Test + public void testToString() { + HeaderTable table = new HeaderTable(0); + { + table.setMaxSize(2048); + assertEquals("entries: 0; used 0/2048 (0.0%)", table.toString()); + } + + { + String name = "custom-name"; + String value = "custom-value"; + int size = 512; + + table.setMaxSize(size); + table.put(name, value); + String s = table.toString(); + + int used = name.length() + value.length() + 32; + double ratio = used * 100.0 / size; + + String expected = format("entries: 1; used %s/%s (%.1f%%)", used, size, ratio); + assertEquals(expected, s); + } + + { + table.setMaxSize(78); + table.put(":method", ""); + table.put(":status", ""); + String s = table.toString(); + assertEquals("entries: 2; used 78/78 (100.0%)", s); + } + } + + @Test + public void stateString() { + HeaderTable table = new HeaderTable(256); + table.put("custom-key", "custom-header"); + // @formatter:off + assertEquals("[ 1] (s = 55) custom-key: custom-header\n" + + " Table size: 55", table.getStateString()); + // @formatter:on + } + + private static Map createStaticEntries() { + Pattern line = Pattern.compile( + "\\|\\s*(?\\d+?)\\s*\\|\\s*(?.+?)\\s*\\|\\s*(?.*?)\\s*\\|"); + Matcher m = line.matcher(SPEC); + Map result = new HashMap<>(); + while (m.find()) { + int index = Integer.parseInt(m.group("index")); + String name = m.group("name"); + String value = m.group("value"); + HeaderField f = new HeaderField(name, value); + result.put(index, f); + } + return Collections.unmodifiableMap(result); // lol + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java new file mode 100644 index 00000000000..502c7051a79 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/HuffmanTest.java @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; +import static org.testng.Assert.*; + +public final class HuffmanTest { + + // + // https://tools.ietf.org/html/rfc7541#appendix-B + // + private static final String SPEC = + // @formatter:off + " code as bits as hex len\n" + + " sym aligned to MSB aligned in\n" + + " to LSB bits\n" + + " ( 0) |11111111|11000 1ff8 [13]\n" + + " ( 1) |11111111|11111111|1011000 7fffd8 [23]\n" + + " ( 2) |11111111|11111111|11111110|0010 fffffe2 [28]\n" + + " ( 3) |11111111|11111111|11111110|0011 fffffe3 [28]\n" + + " ( 4) |11111111|11111111|11111110|0100 fffffe4 [28]\n" + + " ( 5) |11111111|11111111|11111110|0101 fffffe5 [28]\n" + + " ( 6) |11111111|11111111|11111110|0110 fffffe6 [28]\n" + + " ( 7) |11111111|11111111|11111110|0111 fffffe7 [28]\n" + + " ( 8) |11111111|11111111|11111110|1000 fffffe8 [28]\n" + + " ( 9) |11111111|11111111|11101010 ffffea [24]\n" + + " ( 10) |11111111|11111111|11111111|111100 3ffffffc [30]\n" + + " ( 11) |11111111|11111111|11111110|1001 fffffe9 [28]\n" + + " ( 12) |11111111|11111111|11111110|1010 fffffea [28]\n" + + " ( 13) |11111111|11111111|11111111|111101 3ffffffd [30]\n" + + " ( 14) |11111111|11111111|11111110|1011 fffffeb [28]\n" + + " ( 15) |11111111|11111111|11111110|1100 fffffec [28]\n" + + " ( 16) |11111111|11111111|11111110|1101 fffffed [28]\n" + + " ( 17) |11111111|11111111|11111110|1110 fffffee [28]\n" + + " ( 18) |11111111|11111111|11111110|1111 fffffef [28]\n" + + " ( 19) |11111111|11111111|11111111|0000 ffffff0 [28]\n" + + " ( 20) |11111111|11111111|11111111|0001 ffffff1 [28]\n" + + " ( 21) |11111111|11111111|11111111|0010 ffffff2 [28]\n" + + " ( 22) |11111111|11111111|11111111|111110 3ffffffe [30]\n" + + " ( 23) |11111111|11111111|11111111|0011 ffffff3 [28]\n" + + " ( 24) |11111111|11111111|11111111|0100 ffffff4 [28]\n" + + " ( 25) |11111111|11111111|11111111|0101 ffffff5 [28]\n" + + " ( 26) |11111111|11111111|11111111|0110 ffffff6 [28]\n" + + " ( 27) |11111111|11111111|11111111|0111 ffffff7 [28]\n" + + " ( 28) |11111111|11111111|11111111|1000 ffffff8 [28]\n" + + " ( 29) |11111111|11111111|11111111|1001 ffffff9 [28]\n" + + " ( 30) |11111111|11111111|11111111|1010 ffffffa [28]\n" + + " ( 31) |11111111|11111111|11111111|1011 ffffffb [28]\n" + + " ' ' ( 32) |010100 14 [ 6]\n" + + " '!' ( 33) |11111110|00 3f8 [10]\n" + + " '\"' ( 34) |11111110|01 3f9 [10]\n" + + " '#' ( 35) |11111111|1010 ffa [12]\n" + + " '$' ( 36) |11111111|11001 1ff9 [13]\n" + + " '%' ( 37) |010101 15 [ 6]\n" + + " '&' ( 38) |11111000 f8 [ 8]\n" + + " ''' ( 39) |11111111|010 7fa [11]\n" + + " '(' ( 40) |11111110|10 3fa [10]\n" + + " ')' ( 41) |11111110|11 3fb [10]\n" + + " '*' ( 42) |11111001 f9 [ 8]\n" + + " '+' ( 43) |11111111|011 7fb [11]\n" + + " ',' ( 44) |11111010 fa [ 8]\n" + + " '-' ( 45) |010110 16 [ 6]\n" + + " '.' ( 46) |010111 17 [ 6]\n" + + " '/' ( 47) |011000 18 [ 6]\n" + + " '0' ( 48) |00000 0 [ 5]\n" + + " '1' ( 49) |00001 1 [ 5]\n" + + " '2' ( 50) |00010 2 [ 5]\n" + + " '3' ( 51) |011001 19 [ 6]\n" + + " '4' ( 52) |011010 1a [ 6]\n" + + " '5' ( 53) |011011 1b [ 6]\n" + + " '6' ( 54) |011100 1c [ 6]\n" + + " '7' ( 55) |011101 1d [ 6]\n" + + " '8' ( 56) |011110 1e [ 6]\n" + + " '9' ( 57) |011111 1f [ 6]\n" + + " ':' ( 58) |1011100 5c [ 7]\n" + + " ';' ( 59) |11111011 fb [ 8]\n" + + " '<' ( 60) |11111111|1111100 7ffc [15]\n" + + " '=' ( 61) |100000 20 [ 6]\n" + + " '>' ( 62) |11111111|1011 ffb [12]\n" + + " '?' ( 63) |11111111|00 3fc [10]\n" + + " '@' ( 64) |11111111|11010 1ffa [13]\n" + + " 'A' ( 65) |100001 21 [ 6]\n" + + " 'B' ( 66) |1011101 5d [ 7]\n" + + " 'C' ( 67) |1011110 5e [ 7]\n" + + " 'D' ( 68) |1011111 5f [ 7]\n" + + " 'E' ( 69) |1100000 60 [ 7]\n" + + " 'F' ( 70) |1100001 61 [ 7]\n" + + " 'G' ( 71) |1100010 62 [ 7]\n" + + " 'H' ( 72) |1100011 63 [ 7]\n" + + " 'I' ( 73) |1100100 64 [ 7]\n" + + " 'J' ( 74) |1100101 65 [ 7]\n" + + " 'K' ( 75) |1100110 66 [ 7]\n" + + " 'L' ( 76) |1100111 67 [ 7]\n" + + " 'M' ( 77) |1101000 68 [ 7]\n" + + " 'N' ( 78) |1101001 69 [ 7]\n" + + " 'O' ( 79) |1101010 6a [ 7]\n" + + " 'P' ( 80) |1101011 6b [ 7]\n" + + " 'Q' ( 81) |1101100 6c [ 7]\n" + + " 'R' ( 82) |1101101 6d [ 7]\n" + + " 'S' ( 83) |1101110 6e [ 7]\n" + + " 'T' ( 84) |1101111 6f [ 7]\n" + + " 'U' ( 85) |1110000 70 [ 7]\n" + + " 'V' ( 86) |1110001 71 [ 7]\n" + + " 'W' ( 87) |1110010 72 [ 7]\n" + + " 'X' ( 88) |11111100 fc [ 8]\n" + + " 'Y' ( 89) |1110011 73 [ 7]\n" + + " 'Z' ( 90) |11111101 fd [ 8]\n" + + " '[' ( 91) |11111111|11011 1ffb [13]\n" + + " '\\' ( 92) |11111111|11111110|000 7fff0 [19]\n" + + " ']' ( 93) |11111111|11100 1ffc [13]\n" + + " '^' ( 94) |11111111|111100 3ffc [14]\n" + + " '_' ( 95) |100010 22 [ 6]\n" + + " '`' ( 96) |11111111|1111101 7ffd [15]\n" + + " 'a' ( 97) |00011 3 [ 5]\n" + + " 'b' ( 98) |100011 23 [ 6]\n" + + " 'c' ( 99) |00100 4 [ 5]\n" + + " 'd' (100) |100100 24 [ 6]\n" + + " 'e' (101) |00101 5 [ 5]\n" + + " 'f' (102) |100101 25 [ 6]\n" + + " 'g' (103) |100110 26 [ 6]\n" + + " 'h' (104) |100111 27 [ 6]\n" + + " 'i' (105) |00110 6 [ 5]\n" + + " 'j' (106) |1110100 74 [ 7]\n" + + " 'k' (107) |1110101 75 [ 7]\n" + + " 'l' (108) |101000 28 [ 6]\n" + + " 'm' (109) |101001 29 [ 6]\n" + + " 'n' (110) |101010 2a [ 6]\n" + + " 'o' (111) |00111 7 [ 5]\n" + + " 'p' (112) |101011 2b [ 6]\n" + + " 'q' (113) |1110110 76 [ 7]\n" + + " 'r' (114) |101100 2c [ 6]\n" + + " 's' (115) |01000 8 [ 5]\n" + + " 't' (116) |01001 9 [ 5]\n" + + " 'u' (117) |101101 2d [ 6]\n" + + " 'v' (118) |1110111 77 [ 7]\n" + + " 'w' (119) |1111000 78 [ 7]\n" + + " 'x' (120) |1111001 79 [ 7]\n" + + " 'y' (121) |1111010 7a [ 7]\n" + + " 'z' (122) |1111011 7b [ 7]\n" + + " '{' (123) |11111111|1111110 7ffe [15]\n" + + " '|' (124) |11111111|100 7fc [11]\n" + + " '}' (125) |11111111|111101 3ffd [14]\n" + + " '~' (126) |11111111|11101 1ffd [13]\n" + + " (127) |11111111|11111111|11111111|1100 ffffffc [28]\n" + + " (128) |11111111|11111110|0110 fffe6 [20]\n" + + " (129) |11111111|11111111|010010 3fffd2 [22]\n" + + " (130) |11111111|11111110|0111 fffe7 [20]\n" + + " (131) |11111111|11111110|1000 fffe8 [20]\n" + + " (132) |11111111|11111111|010011 3fffd3 [22]\n" + + " (133) |11111111|11111111|010100 3fffd4 [22]\n" + + " (134) |11111111|11111111|010101 3fffd5 [22]\n" + + " (135) |11111111|11111111|1011001 7fffd9 [23]\n" + + " (136) |11111111|11111111|010110 3fffd6 [22]\n" + + " (137) |11111111|11111111|1011010 7fffda [23]\n" + + " (138) |11111111|11111111|1011011 7fffdb [23]\n" + + " (139) |11111111|11111111|1011100 7fffdc [23]\n" + + " (140) |11111111|11111111|1011101 7fffdd [23]\n" + + " (141) |11111111|11111111|1011110 7fffde [23]\n" + + " (142) |11111111|11111111|11101011 ffffeb [24]\n" + + " (143) |11111111|11111111|1011111 7fffdf [23]\n" + + " (144) |11111111|11111111|11101100 ffffec [24]\n" + + " (145) |11111111|11111111|11101101 ffffed [24]\n" + + " (146) |11111111|11111111|010111 3fffd7 [22]\n" + + " (147) |11111111|11111111|1100000 7fffe0 [23]\n" + + " (148) |11111111|11111111|11101110 ffffee [24]\n" + + " (149) |11111111|11111111|1100001 7fffe1 [23]\n" + + " (150) |11111111|11111111|1100010 7fffe2 [23]\n" + + " (151) |11111111|11111111|1100011 7fffe3 [23]\n" + + " (152) |11111111|11111111|1100100 7fffe4 [23]\n" + + " (153) |11111111|11111110|11100 1fffdc [21]\n" + + " (154) |11111111|11111111|011000 3fffd8 [22]\n" + + " (155) |11111111|11111111|1100101 7fffe5 [23]\n" + + " (156) |11111111|11111111|011001 3fffd9 [22]\n" + + " (157) |11111111|11111111|1100110 7fffe6 [23]\n" + + " (158) |11111111|11111111|1100111 7fffe7 [23]\n" + + " (159) |11111111|11111111|11101111 ffffef [24]\n" + + " (160) |11111111|11111111|011010 3fffda [22]\n" + + " (161) |11111111|11111110|11101 1fffdd [21]\n" + + " (162) |11111111|11111110|1001 fffe9 [20]\n" + + " (163) |11111111|11111111|011011 3fffdb [22]\n" + + " (164) |11111111|11111111|011100 3fffdc [22]\n" + + " (165) |11111111|11111111|1101000 7fffe8 [23]\n" + + " (166) |11111111|11111111|1101001 7fffe9 [23]\n" + + " (167) |11111111|11111110|11110 1fffde [21]\n" + + " (168) |11111111|11111111|1101010 7fffea [23]\n" + + " (169) |11111111|11111111|011101 3fffdd [22]\n" + + " (170) |11111111|11111111|011110 3fffde [22]\n" + + " (171) |11111111|11111111|11110000 fffff0 [24]\n" + + " (172) |11111111|11111110|11111 1fffdf [21]\n" + + " (173) |11111111|11111111|011111 3fffdf [22]\n" + + " (174) |11111111|11111111|1101011 7fffeb [23]\n" + + " (175) |11111111|11111111|1101100 7fffec [23]\n" + + " (176) |11111111|11111111|00000 1fffe0 [21]\n" + + " (177) |11111111|11111111|00001 1fffe1 [21]\n" + + " (178) |11111111|11111111|100000 3fffe0 [22]\n" + + " (179) |11111111|11111111|00010 1fffe2 [21]\n" + + " (180) |11111111|11111111|1101101 7fffed [23]\n" + + " (181) |11111111|11111111|100001 3fffe1 [22]\n" + + " (182) |11111111|11111111|1101110 7fffee [23]\n" + + " (183) |11111111|11111111|1101111 7fffef [23]\n" + + " (184) |11111111|11111110|1010 fffea [20]\n" + + " (185) |11111111|11111111|100010 3fffe2 [22]\n" + + " (186) |11111111|11111111|100011 3fffe3 [22]\n" + + " (187) |11111111|11111111|100100 3fffe4 [22]\n" + + " (188) |11111111|11111111|1110000 7ffff0 [23]\n" + + " (189) |11111111|11111111|100101 3fffe5 [22]\n" + + " (190) |11111111|11111111|100110 3fffe6 [22]\n" + + " (191) |11111111|11111111|1110001 7ffff1 [23]\n" + + " (192) |11111111|11111111|11111000|00 3ffffe0 [26]\n" + + " (193) |11111111|11111111|11111000|01 3ffffe1 [26]\n" + + " (194) |11111111|11111110|1011 fffeb [20]\n" + + " (195) |11111111|11111110|001 7fff1 [19]\n" + + " (196) |11111111|11111111|100111 3fffe7 [22]\n" + + " (197) |11111111|11111111|1110010 7ffff2 [23]\n" + + " (198) |11111111|11111111|101000 3fffe8 [22]\n" + + " (199) |11111111|11111111|11110110|0 1ffffec [25]\n" + + " (200) |11111111|11111111|11111000|10 3ffffe2 [26]\n" + + " (201) |11111111|11111111|11111000|11 3ffffe3 [26]\n" + + " (202) |11111111|11111111|11111001|00 3ffffe4 [26]\n" + + " (203) |11111111|11111111|11111011|110 7ffffde [27]\n" + + " (204) |11111111|11111111|11111011|111 7ffffdf [27]\n" + + " (205) |11111111|11111111|11111001|01 3ffffe5 [26]\n" + + " (206) |11111111|11111111|11110001 fffff1 [24]\n" + + " (207) |11111111|11111111|11110110|1 1ffffed [25]\n" + + " (208) |11111111|11111110|010 7fff2 [19]\n" + + " (209) |11111111|11111111|00011 1fffe3 [21]\n" + + " (210) |11111111|11111111|11111001|10 3ffffe6 [26]\n" + + " (211) |11111111|11111111|11111100|000 7ffffe0 [27]\n" + + " (212) |11111111|11111111|11111100|001 7ffffe1 [27]\n" + + " (213) |11111111|11111111|11111001|11 3ffffe7 [26]\n" + + " (214) |11111111|11111111|11111100|010 7ffffe2 [27]\n" + + " (215) |11111111|11111111|11110010 fffff2 [24]\n" + + " (216) |11111111|11111111|00100 1fffe4 [21]\n" + + " (217) |11111111|11111111|00101 1fffe5 [21]\n" + + " (218) |11111111|11111111|11111010|00 3ffffe8 [26]\n" + + " (219) |11111111|11111111|11111010|01 3ffffe9 [26]\n" + + " (220) |11111111|11111111|11111111|1101 ffffffd [28]\n" + + " (221) |11111111|11111111|11111100|011 7ffffe3 [27]\n" + + " (222) |11111111|11111111|11111100|100 7ffffe4 [27]\n" + + " (223) |11111111|11111111|11111100|101 7ffffe5 [27]\n" + + " (224) |11111111|11111110|1100 fffec [20]\n" + + " (225) |11111111|11111111|11110011 fffff3 [24]\n" + + " (226) |11111111|11111110|1101 fffed [20]\n" + + " (227) |11111111|11111111|00110 1fffe6 [21]\n" + + " (228) |11111111|11111111|101001 3fffe9 [22]\n" + + " (229) |11111111|11111111|00111 1fffe7 [21]\n" + + " (230) |11111111|11111111|01000 1fffe8 [21]\n" + + " (231) |11111111|11111111|1110011 7ffff3 [23]\n" + + " (232) |11111111|11111111|101010 3fffea [22]\n" + + " (233) |11111111|11111111|101011 3fffeb [22]\n" + + " (234) |11111111|11111111|11110111|0 1ffffee [25]\n" + + " (235) |11111111|11111111|11110111|1 1ffffef [25]\n" + + " (236) |11111111|11111111|11110100 fffff4 [24]\n" + + " (237) |11111111|11111111|11110101 fffff5 [24]\n" + + " (238) |11111111|11111111|11111010|10 3ffffea [26]\n" + + " (239) |11111111|11111111|1110100 7ffff4 [23]\n" + + " (240) |11111111|11111111|11111010|11 3ffffeb [26]\n" + + " (241) |11111111|11111111|11111100|110 7ffffe6 [27]\n" + + " (242) |11111111|11111111|11111011|00 3ffffec [26]\n" + + " (243) |11111111|11111111|11111011|01 3ffffed [26]\n" + + " (244) |11111111|11111111|11111100|111 7ffffe7 [27]\n" + + " (245) |11111111|11111111|11111101|000 7ffffe8 [27]\n" + + " (246) |11111111|11111111|11111101|001 7ffffe9 [27]\n" + + " (247) |11111111|11111111|11111101|010 7ffffea [27]\n" + + " (248) |11111111|11111111|11111101|011 7ffffeb [27]\n" + + " (249) |11111111|11111111|11111111|1110 ffffffe [28]\n" + + " (250) |11111111|11111111|11111101|100 7ffffec [27]\n" + + " (251) |11111111|11111111|11111101|101 7ffffed [27]\n" + + " (252) |11111111|11111111|11111101|110 7ffffee [27]\n" + + " (253) |11111111|11111111|11111101|111 7ffffef [27]\n" + + " (254) |11111111|11111111|11111110|000 7fffff0 [27]\n" + + " (255) |11111111|11111111|11111011|10 3ffffee [26]\n" + + " EOS (256) |11111111|11111111|11111111|111111 3fffffff [30]"; + // @formatter:on + + @Test + public void read_table() { + Pattern line = Pattern.compile( + "\\(\\s*(?\\d+)\\s*\\)\\s*(?(\\|(0|1)+)+)\\s*" + + "(?[0-9a-zA-Z]+)\\s*\\[\\s*(?\\d+)\\s*\\]"); + Matcher m = line.matcher(SPEC); + int i = 0; + while (m.find()) { + String ascii = m.group("ascii"); + String binary = m.group("binary").replaceAll("\\|", ""); + String hex = m.group("hex"); + String len = m.group("len"); + + // Several sanity checks for the data read from the table, just to + // make sure what we read makes sense + assertEquals(parseInt(len), binary.length()); + assertEquals(parseInt(binary, 2), parseInt(hex, 16)); + + int expected = parseInt(ascii); + + // TODO: find actual eos, do not hardcode it! + byte[] bytes = intToBytes(0x3fffffff, 30, + parseInt(hex, 16), parseInt(len)); + + StringBuilder actual = new StringBuilder(); + Huffman.Reader t = new Huffman.Reader(); + t.read(ByteBuffer.wrap(bytes), actual, false, true); + + // What has been read MUST represent a single symbol + assertEquals(actual.length(), 1, "ascii: " + ascii); + + // It's a lot more visual to compare char as codes rather than + // characters (as some of them might not be visible) + assertEquals(actual.charAt(0), expected); + i++; + } + assertEquals(i, 257); // 256 + EOS + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.1 + // + @Test + public void read_1() { + read("f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"); + } + + @Test + public void write_1() { + write("www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.2 + // + @Test + public void read_2() { + read("a8eb 1064 9cbf", "no-cache"); + } + + @Test + public void write_2() { + write("no-cache", "a8eb 1064 9cbf"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.3 + // + @Test + public void read_3() { + read("25a8 49e9 5ba9 7d7f", "custom-key"); + } + + @Test + public void write_3() { + write("custom-key", "25a8 49e9 5ba9 7d7f"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.4.3 + // + @Test + public void read_4() { + read("25a8 49e9 5bb8 e8b4 bf", "custom-value"); + } + + @Test + public void write_4() { + write("custom-value", "25a8 49e9 5bb8 e8b4 bf"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_5() { + read("6402", "302"); + } + + @Test + public void write_5() { + write("302", "6402"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_6() { + read("aec3 771a 4b", "private"); + } + + @Test + public void write_6() { + write("private", "aec3 771a 4b"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_7() { + read("d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", + "Mon, 21 Oct 2013 20:13:21 GMT"); + } + + @Test + public void write_7() { + write("Mon, 21 Oct 2013 20:13:21 GMT", + "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.1 + // + @Test + public void read_8() { + read("9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", + "https://www.example.com"); + } + + @Test + public void write_8() { + write("https://www.example.com", + "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.2 + // + @Test + public void read_9() { + read("640e ff", "307"); + } + + @Test + public void write_9() { + write("307", "640e ff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_10() { + read("d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff", + "Mon, 21 Oct 2013 20:13:22 GMT"); + } + + @Test + public void write_10() { + write("Mon, 21 Oct 2013 20:13:22 GMT", + "d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_11() { + read("9bd9 ab", "gzip"); + } + + @Test + public void write_11() { + write("gzip", "9bd9 ab"); + } + + // + // https://tools.ietf.org/html/rfc7541#appendix-C.6.3 + // + @Test + public void read_12() { + read("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 " + + "d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 " + + "3160 65c0 03ed 4ee5 b106 3d50 07", + "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); + } + + @Test + public void test_trie_has_no_empty_nodes() { + Huffman.Node root = Huffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); + backlog.push(root); + while (!backlog.isEmpty()) { + Huffman.Node n = backlog.pop(); + // The only type of nodes we couldn't possibly catch during + // construction is an empty node: no children and no char + if (n.left != null) { + backlog.push(n.left); + } + if (n.right != null) { + backlog.push(n.right); + } + assertFalse(!n.charIsSet && n.left == null && n.right == null, + "Empty node in the trie"); + } + } + + @Test + public void test_trie_has_257_nodes() { + int count = 0; + Huffman.Node root = Huffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); + backlog.push(root); + while (!backlog.isEmpty()) { + Huffman.Node n = backlog.pop(); + if (n.left != null) { + backlog.push(n.left); + } + if (n.right != null) { + backlog.push(n.right); + } + if (n.isLeaf()) { + count++; + } + } + assertEquals(count, 257); + } + + @Test + public void cant_encode_outside_byte() { + TestHelper.Block coding = + () -> new Huffman.Writer() + .from(((char) 256) + "", 0, 1) + .write(ByteBuffer.allocate(1)); + RuntimeException e = + TestHelper.assertVoidThrows(RuntimeException.class, coding); + TestHelper.assertExceptionMessageContains(e, "char"); + } + + private static void read(String hexdump, String decoded) { + ByteBuffer source = SpecHelper.toBytes(hexdump); + Appendable actual = new StringBuilder(); + new Huffman.Reader().read(source, actual, true); + assertEquals(actual.toString(), decoded); + } + + private static void write(String decoded, String hexdump) { + int n = Huffman.INSTANCE.lengthOf(decoded); + ByteBuffer destination = ByteBuffer.allocate(n); // Extra margin (1) to test having more bytes in the destination than needed is ok + Huffman.Writer writer = new Huffman.Writer(); + BuffersTestingKit.forEachSplit(destination, byteBuffers -> { + writer.from(decoded, 0, decoded.length()); + boolean written = false; + for (ByteBuffer b : byteBuffers) { + int pos = b.position(); + written = writer.write(b); + b.position(pos); + } + assertTrue(written); + ByteBuffer concated = BuffersTestingKit.concat(byteBuffers); + String actual = SpecHelper.toHexdump(concated); + assertEquals(actual, hexdump); + writer.reset(); + }); + } + + // + // It's not very pretty, yes I know that + // + // hex: + // + // |31|30|...|N-1|...|01|00| + // \ / + // codeLength + // + // hex <<= 32 - codeLength; (align to MSB): + // + // |31|30|...|32-N|...|01|00| + // \ / + // codeLength + // + // EOS: + // + // |31|30|...|M-1|...|01|00| + // \ / + // eosLength + // + // eos <<= 32 - eosLength; (align to MSB): + // + // pad with MSBs of EOS: + // + // |31|30|...|32-N|32-N-1|...|01|00| + // | 32|...| + // + // Finally, split into byte[] + // + private byte[] intToBytes(int eos, int eosLength, int hex, int codeLength) { + hex <<= 32 - codeLength; + eos >>= codeLength - (32 - eosLength); + hex |= eos; + int n = (int) Math.ceil(codeLength / 8.0); + byte[] result = new byte[n]; + for (int i = 0; i < n; i++) { + result[i] = (byte) (hex >> (32 - 8 * (i + 1))); + } + return result; + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java new file mode 100644 index 00000000000..88bd906514e --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/SpecHelper.java @@ -0,0 +1,70 @@ +/* + * 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 sun.net.httpclient.hpack; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +// +// THIS IS NOT A TEST +// +public final class SpecHelper { + + private SpecHelper() { + throw new AssertionError(); + } + + public static ByteBuffer toBytes(String hexdump) { + Pattern hexByte = Pattern.compile("[0-9a-fA-F]{2}"); + List bytes = new ArrayList<>(); + Matcher matcher = hexByte.matcher(hexdump); + while (matcher.find()) { + bytes.add(matcher.group(0)); + } + ByteBuffer result = ByteBuffer.allocate(bytes.size()); + for (String f : bytes) { + result.put((byte) Integer.parseInt(f, 16)); + } + result.flip(); + return result; + } + + public static String toHexdump(ByteBuffer bb) { + List words = new ArrayList<>(); + int i = 0; + while (bb.hasRemaining()) { + if (i % 2 == 0) { + words.add(""); + } + byte b = bb.get(); + String hex = Integer.toHexString(256 + Byte.toUnsignedInt(b)).substring(1); + words.set(i / 2, words.get(i / 2) + hex); + i++; + } + return words.stream().collect(Collectors.joining(" ")); + } +} diff --git a/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java new file mode 100644 index 00000000000..b042b5f4cee --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/sun/net/httpclient/hpack/TestHelper.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.net.httpclient.hpack; + +import org.testng.annotations.Test; + +import java.util.Objects; +import java.util.Random; + +public final class TestHelper { + + public static Random newRandom() { + long seed = Long.getLong("jdk.test.lib.random.seed", System.currentTimeMillis()); + System.out.println("new java.util.Random(" + seed + ")"); + return new Random(seed); + } + + public static T assertVoidThrows(Class clazz, Block code) { + return assertThrows(clazz, () -> { + code.run(); + return null; + }); + } + + public static T assertThrows(Class clazz, ReturningBlock code) { + Objects.requireNonNull(clazz, "clazz == null"); + Objects.requireNonNull(code, "code == null"); + try { + code.run(); + } catch (Throwable t) { + if (clazz.isInstance(t)) { + return clazz.cast(t); + } + throw new AssertionError("Expected to catch exception of type " + + clazz.getCanonicalName() + ", instead caught " + + t.getClass().getCanonicalName(), t); + + } + throw new AssertionError( + "Expected to catch exception of type " + clazz.getCanonicalName() + + ", but caught nothing"); + } + + public static T assertDoesNotThrow(ReturningBlock code) { + Objects.requireNonNull(code, "code == null"); + try { + return code.run(); + } catch (Throwable t) { + throw new AssertionError( + "Expected code block to exit normally, instead " + + "caught " + t.getClass().getCanonicalName(), t); + } + } + + public static void assertVoidDoesNotThrow(Block code) { + Objects.requireNonNull(code, "code == null"); + try { + code.run(); + } catch (Throwable t) { + throw new AssertionError( + "Expected code block to exit normally, instead " + + "caught " + t.getClass().getCanonicalName(), t); + } + } + + + public static void assertExceptionMessageContains(Throwable t, + CharSequence firstSubsequence, + CharSequence... others) { + assertCharSequenceContains(t.getMessage(), firstSubsequence, others); + } + + public static void assertCharSequenceContains(CharSequence s, + CharSequence firstSubsequence, + CharSequence... others) { + if (s == null) { + throw new NullPointerException("Exception message is null"); + } + String str = s.toString(); + String missing = null; + if (!str.contains(firstSubsequence.toString())) { + missing = firstSubsequence.toString(); + } else { + for (CharSequence o : others) { + if (!str.contains(o.toString())) { + missing = o.toString(); + break; + } + } + } + if (missing != null) { + throw new AssertionError("CharSequence '" + s + "'" + " does not " + + "contain subsequence '" + missing + "'"); + } + } + + public interface ReturningBlock { + T run() throws Throwable; + } + + public interface Block { + void run() throws Throwable; + } + + // tests + + @Test + public void assertThrows() { + assertThrows(NullPointerException.class, () -> ((Object) null).toString()); + } + + @Test + public void assertThrowsWrongType() { + try { + assertThrows(IllegalArgumentException.class, () -> ((Object) null).toString()); + } catch (AssertionError e) { + Throwable cause = e.getCause(); + String message = e.getMessage(); + if (cause != null + && cause instanceof NullPointerException + && message != null + && message.contains("instead caught")) { + return; + } + } + throw new AssertionError(); + } + + @Test + public void assertThrowsNoneCaught() { + try { + assertThrows(IllegalArgumentException.class, () -> null); + } catch (AssertionError e) { + Throwable cause = e.getCause(); + String message = e.getMessage(); + if (cause == null + && message != null + && message.contains("but caught nothing")) { + return; + } + } + throw new AssertionError(); + } +} diff --git a/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java b/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java index 2a2121e249d..0d2d7fd35a4 100644 --- a/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java +++ b/jdk/test/java/security/Signature/TestInitSignWithMyOwnRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,9 +55,9 @@ class TestRandomSource extends SecureRandom { int count = 0; - public int nextInt() { + @Override + public void nextBytes(byte[] rs) { count++; - return 0; } public boolean isUsed() { diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java new file mode 100644 index 00000000000..d0a1f189e92 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package tck.java.time.format; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.testng.annotations.Test; + +/** + * Test localized behavior of formatter. + */ +@Test +public class TCKLocalizedOffsetIdPrinterParser { + @Test + public void test_localized_offset_parse() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.S O") + .withLocale(Locale.ENGLISH); + String date = formatter.format(ZonedDateTime.now(ZoneOffset.UTC)); + formatter.parse(date) ; + } +} diff --git a/jdk/test/java/util/ServiceLoader/modules/BasicTest.java b/jdk/test/java/util/ServiceLoader/modules/MiscTests.java similarity index 82% rename from jdk/test/java/util/ServiceLoader/modules/BasicTest.java rename to jdk/test/java/util/ServiceLoader/modules/MiscTests.java index 3b64a1d7d9a..5a99a30737c 100644 --- a/jdk/test/java/util/ServiceLoader/modules/BasicTest.java +++ b/jdk/test/java/util/ServiceLoader/modules/MiscTests.java @@ -30,11 +30,11 @@ import static org.testng.Assert.*; /* * @test - * @run testng BasicTest + * @run testng MiscTests * @summary Basic test of ServiceLoader with modules */ -public class BasicTest { +public class MiscTests { @Test public void testEmptyLayer() { @@ -43,18 +43,6 @@ public class BasicTest { assertFalse(sl.iterator().hasNext()); } - @Test - public void testBootLayer() { - ServiceLoader sl - = ServiceLoader.load(Layer.boot(), Provider.class); - boolean found = false; - for (Provider provider : sl) { - if (provider.getName().equals("SunJCE")) - found = true; - } - assertTrue(found); - } - @Test(expectedExceptions = { NullPointerException.class }) public void testNullLayer() { ServiceLoader.load(null, Provider.class); diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java index a1ce49682b4..f730567013d 100644 --- a/jdk/test/java/util/TimeZone/Bug6772689.java +++ b/jdk/test/java/util/TimeZone/Bug6772689.java @@ -24,7 +24,6 @@ /* * @test * @bug 6772689 - * @key intermittent * @summary Test for standard-to-daylight transitions at midnight: * date stays on the given day. */ diff --git a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java new file mode 100644 index 00000000000..4a5757824fd --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @ignore 8148454 + * @bug 8152183 8148454 + * @author a.stepanov + * @summary check that TIFFields are derived properly for multi-page tiff + * @run main MultiPageImageTIFFFieldTest + */ + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.*; +import javax.imageio.plugins.tiff.*; + + +public class MultiPageImageTIFFFieldTest { + + private final static String FILENAME = "test.tiff"; + private final static int W1 = 20, H1 = 40, W2 = 100, H2 = 15; + private final static Color C1 = Color.BLACK, C2 = Color.RED; + + private final static int N_WIDTH = BaselineTIFFTagSet.TAG_IMAGE_WIDTH; + private final static int N_HEIGHT = BaselineTIFFTagSet.TAG_IMAGE_LENGTH; + + private static final String DESCRIPTION_1[] = {"Description-1", "abc ABC"}; + private static final String DESCRIPTION_2[] = {"Description-2", "1-2-3"}; + private final static int N_DESCRIPTION = + BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION; + + private final static String EXIF_DATA_1[] = {"2001:01:01 00:00:01"}; + private final static String EXIF_DATA_2[] = {"2002:02:02 00:00:02"}; + private final static int N_EXIF = ExifTIFFTagSet.TAG_DATE_TIME_ORIGINAL; + + private final static String GPS_DATA[] = { + ExifGPSTagSet.STATUS_MEASUREMENT_IN_PROGRESS}; + private final static int N_GPS = ExifGPSTagSet.TAG_GPS_STATUS; + + private final static short FAX_DATA = + FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED; + private final static int N_FAX = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA; + + private static final byte[] ICC_PROFILE_2 = + ICC_ProfileRGB.getInstance(ColorSpace.CS_sRGB).getData(); + private static final int N_ICC = BaselineTIFFTagSet.TAG_ICC_PROFILE; + + private static final int N_BPS = BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE; + + private static final int + COMPRESSION_1 = BaselineTIFFTagSet.COMPRESSION_DEFLATE, + COMPRESSION_2 = BaselineTIFFTagSet.COMPRESSION_LZW; + private static final int N_COMPRESSION = BaselineTIFFTagSet.TAG_COMPRESSION; + + private static final int + GRAY_1 = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO, + GRAY_2 = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, + RGB = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB; + + private static final int N_PHOTO = + BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION; + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data[], + int num) { + + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, data.length, data)); + } + + private void checkASCIIField(TIFFDirectory d, + String what, + String data[], + int num) { + + String notFound = what + " field was not found"; + check(d.containsTIFFField(num), notFound); + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == data.length, "invalid " + what + " data count"); + for (int i = 0; i < data.length; i++) { + check(f.getValueAsString(i).equals(data[i]), + "invalid " + what + " data"); + } + } + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img1 = + new BufferedImage(W1, H1, BufferedImage.TYPE_BYTE_GRAY); + Graphics g = img1.getGraphics(); + g.setColor(C1); + g.fillRect(0, 0, W1, H1); + g.dispose(); + + BufferedImage img2 = + new BufferedImage(W2, H2, BufferedImage.TYPE_INT_RGB); + g = img2.getGraphics(); + g.setColor(C2); + g.fillRect(0, 0, W2, H2); + g.dispose(); + + ImageWriteParam param1 = writer.getDefaultWriteParam(); + param1.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param1.setCompressionType("Deflate"); + param1.setCompressionQuality(0.5f); + + ImageWriteParam param2 = writer.getDefaultWriteParam(); + param2.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param2.setCompressionType("LZW"); + param2.setCompressionQuality(0.5f); + + IIOMetadata + md1 = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img1), param1), + md2 = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img2), param2); + + TIFFDirectory + dir1 = TIFFDirectory.createFromMetadata(md1), + dir2 = TIFFDirectory.createFromMetadata(md2); + + addASCIIField(dir1, "ImageDescription", DESCRIPTION_1, N_DESCRIPTION); + addASCIIField(dir2, "ImageDescription", DESCRIPTION_2, N_DESCRIPTION); + + addASCIIField(dir1, "GPSStatus", GPS_DATA, N_GPS); + addASCIIField(dir2, "GPSStatus", GPS_DATA, N_GPS); + + addASCIIField(dir1, "DateTimeOriginal", EXIF_DATA_1, N_EXIF); + addASCIIField(dir2, "DateTimeOriginal", EXIF_DATA_2, N_EXIF); + + TIFFTag faxTag = new TIFFTag( + "CleanFaxData", N_FAX, 1 << TIFFTag.TIFF_SHORT); + dir1.addTIFFField(new TIFFField(faxTag, FAX_DATA)); + dir2.addTIFFField(new TIFFField(faxTag, FAX_DATA)); + + dir2.addTIFFField(new TIFFField( + new TIFFTag("ICC Profile", N_ICC, 1 << TIFFTag.TIFF_UNDEFINED), + TIFFTag.TIFF_UNDEFINED, ICC_PROFILE_2.length, ICC_PROFILE_2)); + + writer.prepareWriteSequence(null); + writer.writeToSequence( + new IIOImage(img1, null, dir1.getAsMetadata()), param1); + writer.writeToSequence( + new IIOImage(img2, null, dir2.getAsMetadata()), param2); + writer.endWriteSequence(); + + ios.flush(); + writer.dispose(); + } + s.close(); + } + + private void checkBufferedImages(BufferedImage im1, BufferedImage im2) { + + check(im1.getWidth() == W1, "invalid width for image 1"); + check(im1.getHeight() == H1, "invalid height for image 1"); + check(im2.getWidth() == W2, "invalid width for image 2"); + check(im2.getHeight() == H2, "invalid height for image 2"); + + Color + c1 = new Color(im1.getRGB(W1 / 2, H1 / 2)), + c2 = new Color(im2.getRGB(W2 / 2, H2 / 2)); + + check(c1.equals(C1), "invalid image 1 color"); + check(c2.equals(C2), "invalid image 2 color"); + } + + private void readAndCheckImage() throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s, false, true); + + int ni = reader.getNumImages(true); + check(ni == 2, "invalid number of images"); + + // check TIFFImageReadParam for multipage image + TIFFImageReadParam + param1 = new TIFFImageReadParam(), param2 = new TIFFImageReadParam(); + + param1.addAllowedTagSet(ExifTIFFTagSet.getInstance()); + param1.addAllowedTagSet(ExifGPSTagSet.getInstance()); + + param2.addAllowedTagSet(ExifTIFFTagSet.getInstance()); + param2.addAllowedTagSet(GeoTIFFTagSet.getInstance()); + + // FaxTIFFTagSet is allowed by default + param2.removeAllowedTagSet(FaxTIFFTagSet.getInstance()); + + + // read images and metadata + IIOImage i1 = reader.readAll(0, param1), i2 = reader.readAll(1, param2); + BufferedImage + bi1 = (BufferedImage) i1.getRenderedImage(), + bi2 = (BufferedImage) i2.getRenderedImage(); + + // check rendered images, just in case + checkBufferedImages(bi1, bi2); + + TIFFDirectory + dir1 = TIFFDirectory.createFromMetadata(i1.getMetadata()), + dir2 = TIFFDirectory.createFromMetadata(i2.getMetadata()); + + // check ASCII fields + checkASCIIField( + dir1, "image 1 description", DESCRIPTION_1, N_DESCRIPTION); + checkASCIIField( + dir2, "image 2 description", DESCRIPTION_2, N_DESCRIPTION); + + checkASCIIField(dir1, "image 1 datetime", EXIF_DATA_1, N_EXIF); + checkASCIIField(dir2, "image 2 datetime", EXIF_DATA_2, N_EXIF); + + // check sizes + TIFFField f = dir1.getTIFFField(N_WIDTH); + check((f.getCount() == 1) && (f.getAsInt(0) == W1), + "invalid width field for image 1"); + f = dir2.getTIFFField(N_WIDTH); + check((f.getCount() == 1) && (f.getAsInt(0) == W2), + "invalid width field for image 2"); + + f = dir1.getTIFFField(N_HEIGHT); + check((f.getCount() == 1) && (f.getAsInt(0) == H1), + "invalid height field for image 1"); + f = dir2.getTIFFField(N_HEIGHT); + check((f.getCount() == 1) && (f.getAsInt(0) == H2), + "invalid height field for image 2"); + + // check fax data + check(dir1.containsTIFFField(N_FAX), "image 2 TIFF directory " + + "must contain clean fax data"); + f = dir1.getTIFFField(N_FAX); + check( + (f.getCount() == 1) && f.isIntegral() && (f.getAsInt(0) == FAX_DATA), + "invalid clean fax data"); + + check(!dir2.containsTIFFField(N_FAX), "image 2 TIFF directory " + + "must not contain fax fields"); + + // check GPS data + checkASCIIField(dir1, "GPS status", GPS_DATA, N_GPS); + + check(!dir2.containsTIFFField(N_GPS), "image 2 TIFF directory " + + "must not contain GPS fields"); + + // check ICC profile data + check(!dir1.containsTIFFField(N_ICC), "image 1 TIFF directory " + + "must not contain ICC Profile field"); + check(dir2.containsTIFFField(N_ICC), "image 2 TIFF directory " + + "must contain ICC Profile field"); + + f = dir2.getTIFFField(N_ICC); + check(f.getType() == TIFFTag.TIFF_UNDEFINED, + "invalid ICC profile field type"); + int cnt = f.getCount(); + byte icc[] = f.getAsBytes(); + check((cnt == ICC_PROFILE_2.length) && (cnt == icc.length), + "invalid ICC profile"); + for (int i = 0; i < cnt; i++) { + check(icc[i] == ICC_PROFILE_2[i], "invalid ICC profile data"); + } + + // check component sizes + check(dir1.getTIFFField(N_BPS).isIntegral() && + dir2.getTIFFField(N_BPS).isIntegral(), + "invalid bits per sample type"); + int sz1[] = bi1.getColorModel().getComponentSize(), + sz2[] = bi2.getColorModel().getComponentSize(), + bps1[] = dir1.getTIFFField(N_BPS).getAsInts(), + bps2[] = dir2.getTIFFField(N_BPS).getAsInts(); + + check((bps1.length == sz1.length) && (bps2.length == sz2.length), + "invalid component size count"); + + for (int i = 0; i < bps1.length; i++) { + check(bps1[i] == sz1[i], "image 1: invalid bits per sample data"); + } + + for (int i = 0; i < bps2.length; i++) { + check(bps2[i] == sz2[i], "image 2: invalid bits per sample data"); + } + + // check compression data + check(dir1.containsTIFFField(N_COMPRESSION) && + dir2.containsTIFFField(N_COMPRESSION), + "compression info lost"); + f = dir1.getTIFFField(N_COMPRESSION); + check(f.isIntegral() && (f.getCount() == 1) && + (f.getAsInt(0) == COMPRESSION_1), "invalid image 1 compression data"); + + f = dir2.getTIFFField(N_COMPRESSION); + check(f.isIntegral() && (f.getCount() == 1) && + (f.getAsInt(0) == COMPRESSION_2), "invalid image 2 compression data"); + + // check photometric interpretation + f = dir1.getTIFFField(N_PHOTO); + check(f.isIntegral() && (f.getCount() == 1) && + ((f.getAsInt(0) == GRAY_1) || (f.getAsInt(0) == GRAY_2)), + "invalid photometric interpretation for image 1"); + + f = dir2.getTIFFField(N_PHOTO); + check(f.isIntegral() && (f.getCount() == 1) && (f.getAsInt(0) == RGB), + "invalid photometric interpretation for image 2"); + } + + public void run() { + + try { + writeImage(); + readAndCheckImage(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void check(boolean ok, String msg) { + + if (!ok) { throw new RuntimeException(msg); } + } + + public static void main(String[] args) { + (new MultiPageImageTIFFFieldTest()).run(); + } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java new file mode 100644 index 00000000000..39c2474512c --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8149028 + * @author a.stepanov + * @summary some simple checks for TIFFDirectory + * @run main TIFFDirectoryTest + */ + +import java.util.List; +import java.util.ArrayList; +import javax.imageio.metadata.*; +import javax.imageio.plugins.tiff.*; + + +public class TIFFDirectoryTest { + + private static void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void run() { + + int type = TIFFTag.TIFF_LONG, dt = 1 << type; + int n0 = 1000, n1 = 1001, n2 = 1002, n3 = 1003; + + TIFFTag tag1 = new TIFFTag(Integer.toString(n1), n1, dt); + TIFFTag tag2 = new TIFFTag(Integer.toString(n2), n2, dt); + TIFFTag tag3 = new TIFFTag(Integer.toString(n3), n3, dt); + TIFFTag parent = new TIFFTag(Integer.toString(n0), n0, dt); + + // tag sets array must not be null + boolean ok = false; + try { new TIFFDirectory(null, parent); } + catch (NullPointerException e) { ok = true; } + check(ok, "can construct TIFFDirectory with null tagsets array"); + + // but can be empty + TIFFTagSet emptySets[] = {}; + TIFFDirectory d = new TIFFDirectory(emptySets, parent); + check(d.getTagSets().length == 0, "invalid number of tag sets"); + check(d.getParentTag().getName().equals(Integer.toString(n0)) && + (d.getParentTag().getNumber() == n0), "invalid parent tag"); + + + // add tags + List tags = new ArrayList<>(); + tags.add(tag1); + tags.add(tag2); + TIFFTagSet ts1 = new TIFFTagSet(tags); + + tags.clear(); + tags.add(tag3); + TIFFTagSet ts2 = new TIFFTagSet(tags); + + TIFFTagSet sets[] = {ts1, ts2}; + d = new TIFFDirectory(sets, parent); + + check(d.getTagSets().length == sets.length, "invalid number of tag sets"); + + // check getTag() + for (int i = n1; i <= n3; i++) { + TIFFTag t = d.getTag(i); + check(t.getNumber() == i, "invalid tag number"); + check(t.getName().equals(Integer.toString(i)), "invalid tag name"); + check(t.getDataTypes() == dt, "invalid tag data types"); + } + + TIFFDirectory d2; + try { d2 = d.clone(); } + catch (CloneNotSupportedException e) { throw new RuntimeException(e); } + + // check removeTagSet() + d.removeTagSet(ts2); + check(d.getTagSets().length == 1, "invalid number of tag sets"); + check(d.getTagSets()[0].getTag(n1).getName().equals(Integer.toString(n1)), + "invalid tag name"); + check(d.getTagSets()[0].getTag(n2).getName().equals(Integer.toString(n2)), + "invalid tag name"); + + d.removeTagSet(ts1); + check(d.getTagSets().length == 0, "invalid number of tag sets"); + + // check cloned data + check(d2.getTagSets().length == sets.length, + "invalid number of tag sets"); + TIFFTagSet sets2[] = d2.getTagSets(); + check(sets2.length == sets.length, "invalid number of tag sets"); + check( + (sets2[0].getTag(Integer.toString(n1)).getNumber() == n1) && + (sets2[0].getTag(Integer.toString(n2)).getNumber() == n2) && + (sets2[0].getTag(Integer.toString(n0)) == null) && + (sets2[1].getTag(Integer.toString(n3)).getNumber() == n3) && + (sets2[1].getTag(Integer.toString(n0)) == null), "invalid data"); + + check( + (sets2[0].getTag(Integer.toString(n1)).getDataTypes() == dt) && + (sets2[0].getTag(Integer.toString(n2)).getDataTypes() == dt) && + (sets2[1].getTag(Integer.toString(n3)).getDataTypes() == dt), + "invalid data type"); + + // must not be able to call removeTagSet with null argument + ok = false; + try { d.removeTagSet(null); } + catch (NullPointerException e) { ok = true; } + check(ok, "must not be able to use null as an argument for remove"); + + // check parent tag + check( d.getParentTag().getName().equals(Integer.toString(n0)) && + d2.getParentTag().getName().equals(Integer.toString(n0)), + "invalid parent tag name"); + + check(( d.getParentTag().getNumber() == n0) && + (d2.getParentTag().getNumber() == n0), + "invalid parent tag number"); + + check(( d.getParentTag().getDataTypes() == dt) && + (d2.getParentTag().getDataTypes() == dt), + "invalid parent data type"); + + d.addTagSet(ts1); + d.addTagSet(ts2); + + // add the same tag set twice and check that nothing changed + d.addTagSet(ts2); + + check(d.getTagSets().length == 2, "invalid number of tag sets"); + + // check field operations + check(d.getNumTIFFFields() == 0, "invalid TIFFFields number"); + check(d.getTIFFField(Integer.MAX_VALUE) == null, + "must return null TIFFField"); + + long offset = 4L; + long a[] = {Long.MIN_VALUE, 0, Long.MAX_VALUE}; + int v = 100500; + TIFFField + f1 = new TIFFField(tag1, type, offset, d), + f2 = new TIFFField(tag2, v), + f3 = new TIFFField(tag3, type, a.length, a); + + d.addTIFFField(f1); + d.addTIFFField(f2); + d.addTIFFField(f3); + + check(d.containsTIFFField(n1) && + d.containsTIFFField(n2) && + d.containsTIFFField(n3) && + !d.containsTIFFField(n0), "invalid containsTIFFField() results"); + + check(d.getTIFFField(n0) == null, "can get unadded field"); + + check(d.getNumTIFFFields() == 3, "invalid TIFFFields number"); + + check(d.getTIFFField(n1).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n1).getAsLong(0) == offset, "invalid offset"); + + check(d.getTIFFField(n2).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n2).getAsInt(0) == v, "invalid TIFFField value"); + + check(d.getTIFFField(n3).getCount() == a.length, + "invalid TIFFField count"); + for (int i = 0; i < a.length; ++i) { + check(d.getTIFFField(n3).getAsLong(i) == a[i], + "invalid TIFFField value"); + } + + TIFFField nested = d.getTIFFField(n1).getDirectory().getTIFFField(n1); + check(nested.getTag().getNumber() == n1, "invalid tag number"); + check(nested.getCount() == 1, "invalid field count"); + check(nested.getAsLong(0) == offset, "invalid offset"); + + // check that the field is overwritten correctly + int v2 = 1 << 16; + d.addTIFFField(new TIFFField(tag3, v2)); + check(d.getTIFFField(n3).getCount() == 1, "invalid TIFFField count"); + check(d.getTIFFField(n3).getAsInt(0)== v2, "invalid TIFFField value"); + check(d.getNumTIFFFields() == 3, "invalid TIFFFields number"); + + // check removeTIFFField() + d.removeTIFFField(n3); + check(d.getNumTIFFFields() == 2, "invalid TIFFFields number"); + check(d.getTIFFField(n3) == null, "can get removed field"); + + d.removeTIFFFields(); + check((d.getTIFFField(n1) == null) && (d.getTIFFField(n2) == null), + "can get removed field"); + check((d.getNumTIFFFields() == 0) && (d.getTIFFFields().length == 0), + "invalid TIFFFields number"); + + // check that array returned by getTIFFFields() is sorted + // by tag number (as it stated in the docs) + d.addTIFFField(f3); + d.addTIFFField(f1); + d.addTIFFField(f2); + + TIFFField fa[] = d.getTIFFFields(); + check(fa.length == 3, "invalid number of fields"); + check((fa[0].getTagNumber() == n1) && + (fa[1].getTagNumber() == n2) && + (fa[2].getTagNumber() == n3), + "array of the fields must be sorted by tag number"); + + d.removeTIFFFields(); + d.addTIFFField(f2); + + // test getAsMetaData / createFromMetadata + try { + d2 = TIFFDirectory.createFromMetadata(d.getAsMetadata()); + } catch (IIOInvalidTreeException e) { + throw new RuntimeException(e); + } + + // check new data + check(d2.getTagSets().length == sets.length, + "invalid number of tag sets"); + sets2 = d2.getTagSets(); + check(sets2.length == sets.length, "invalid number of tag sets"); + check( + (sets2[0].getTag(Integer.toString(n1)).getNumber() == n1) && + (sets2[0].getTag(Integer.toString(n2)).getNumber() == n2) && + (sets2[0].getTag(Integer.toString(n0)) == null) && + (sets2[1].getTag(Integer.toString(n3)).getNumber() == n3) && + (sets2[1].getTag(Integer.toString(n0)) == null), "invalid data"); + + check( + (sets2[0].getTag(Integer.toString(n1)).getDataTypes() == dt) && + (sets2[0].getTag(Integer.toString(n2)).getDataTypes() == dt) && + (sets2[1].getTag(Integer.toString(n3)).getDataTypes() == dt), + "invalid data type"); + + check(!d2.containsTIFFField(n1) && + d2.containsTIFFField(n2) && + !d2.containsTIFFField(n3), "invalid containsTIFFField() results"); + check(d2.getTIFFField(n2).getCount() == 1, "invalid TIFFField count"); + check(d2.getTIFFField(n2).getAsInt(0) == v, "invalid TIFFField value"); + + check((d2.getParentTag().getNumber() == n0) && + d2.getParentTag().getName().equals(Integer.toString(n0)), + "invalid parent tag"); + } + + public static void main(String[] args) { (new TIFFDirectoryTest()).run(); } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java new file mode 100644 index 00000000000..45477608016 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryWriteReadTest.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8149028 + * @author a.stepanov + * @summary a simple write-read test for TIFFDirectory + * @run main TIFFDirectoryWriteReadTest + */ + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.*; +import javax.imageio.plugins.tiff.*; + + +public class TIFFDirectoryWriteReadTest { + + private final static String FILENAME = "test.tiff"; + private final static int SZ = 100; + private final static Color C = Color.RED; + + private static final String COPYRIGHT[] = {"Copyright 123ABC.."}; + private static final String DESCRIPTION[] = {"Test Image", "Description"}; + private static final String SOFTWARE[] = {"test", "software", "123"}; + + private static final long RES_X[][] = {{2, 1}}, RES_Y[][] = {{1, 1}}; + + private static final byte[] ICC_PROFILE = + ICC_ProfileRGB.getInstance(ColorSpace.CS_sRGB).getData(); + + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data[], + int num) { + + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, data.length, data)); + } + + private void checkASCIIField(TIFFDirectory d, + String what, + String data[], + int num) { + + String notFound = what + " field was not found"; + check(d.containsTIFFField(num), notFound); + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == data.length, "invalid " + what + " data count"); + for (int i = 0; i < data.length; i++) { + check(f.getValueAsString(i).equals(data[i]), + "invalid " + what + " data"); + } + } + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img = new BufferedImage( + SZ, SZ, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(C); + g.fillRect(0, 0, SZ, SZ); + g.dispose(); + + IIOMetadata metadata = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img), writer.getDefaultWriteParam()); + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + addASCIIField(dir, "Copyright", + COPYRIGHT, BaselineTIFFTagSet.TAG_COPYRIGHT); + + addASCIIField(dir, "ImageDescription", + DESCRIPTION, BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION); + + addASCIIField(dir, "Software", + SOFTWARE, BaselineTIFFTagSet.TAG_SOFTWARE); + + dir.addTIFFField(new TIFFField( + new TIFFTag("XResolution", BaselineTIFFTagSet.TAG_X_RESOLUTION, + 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_X)); + dir.addTIFFField(new TIFFField( + new TIFFTag("YResolution", BaselineTIFFTagSet.TAG_Y_RESOLUTION, + 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_Y)); + + dir.addTIFFField(new TIFFField( + new TIFFTag("ICC Profile", BaselineTIFFTagSet.TAG_ICC_PROFILE, + 1 << TIFFTag.TIFF_UNDEFINED), + TIFFTag.TIFF_UNDEFINED, ICC_PROFILE.length, ICC_PROFILE)); + + IIOMetadata data = dir.getAsMetadata(); + writer.write(new IIOImage(img, null, data)); + + ios.flush(); + writer.dispose(); + } + s.close(); + } + + + + private void readAndCheckImage() throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s); + + int ni = reader.getNumImages(true); + check(ni == 1, "invalid number of images"); + + // check image + BufferedImage img = reader.read(0); + check(img.getWidth() == SZ && img.getHeight() == SZ, + "invalid image size"); + + Color c = new Color(img.getRGB(SZ / 2, SZ / 2)); + check(C.equals(c), "invalid image color"); + + IIOMetadata metadata = reader.readAll(0, null).getMetadata(); + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + reader.dispose(); + s.close(); + + // ===== perform tag checks ===== + + checkASCIIField(dir, "copyright", COPYRIGHT, + BaselineTIFFTagSet.TAG_COPYRIGHT); + + checkASCIIField(dir, "description", DESCRIPTION, + BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION); + + checkASCIIField(dir, "software", SOFTWARE, + BaselineTIFFTagSet.TAG_SOFTWARE); + + TIFFField f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH); + check(f.getCount() == 1, "invalid width field count"); + int w = f.getAsInt(0); + check(w == SZ, "invalid width"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH); + check(f.getCount() == 1, "invalid height field count"); + int h = f.getAsInt(0); + check(h == SZ, "invalid height"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); + // RGB: 3 x 8 bits for R, G and B components + int bps[] = f.getAsInts(); + check((f.getCount() == 3) && (bps.length == 3), "invalid BPS count"); + for (int b: bps) { check(b == 8, "invalid bits per sample"); } + + // RGB: PhotometricInterpretation = 2 + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); + check(f.getCount() == 1, "invalid count"); + check(f.getAsInt(0) == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB, + "invalid photometric interpretation value"); + + String rat = " resolution must be rational"; + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION); + check(f.getType() == TIFFTag.TIFF_RATIONAL, "x" + rat); + check(f.getCount() == 1 && + f.getAsInt(0) == (int) (RES_X[0][0] / RES_X[0][1]), + "invalid x resolution"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION); + check(f.getType() == TIFFTag.TIFF_RATIONAL, "y" + rat); + check(f.getCount() == 1 && + f.getAsInt(0) == (int) (RES_Y[0][0] / RES_Y[0][1]), + "invalid y resolution"); + + f = dir.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE); + check(f.getType() == TIFFTag.TIFF_UNDEFINED, + "invalid ICC profile field type"); + int cnt = f.getCount(); + byte icc[] = f.getAsBytes(); + check((cnt == ICC_PROFILE.length) && (cnt == icc.length), + "invalid ICC profile"); + for (int i = 0; i < cnt; i++) { + check(icc[i] == ICC_PROFILE[i], "invalid ICC profile"); + } + } + + public void run() { + + try { + writeImage(); + readAndCheckImage(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + public static void main(String[] args) { + (new TIFFDirectoryWriteReadTest()).run(); + } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java new file mode 100644 index 00000000000..a50929e8a46 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8152183 + * @author a.stepanov + * @summary Some checks for TIFFField methods + * @run main TIFFFieldTest + */ + +import java.util.List; +import java.util.ArrayList; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.plugins.tiff.*; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class TIFFFieldTest { + + private final static String NAME = "tag"; // tag name + private final static int NUM = 12345; // tag number + private final static int MIN_TYPE = TIFFTag.MIN_DATATYPE; + private final static int MAX_TYPE = TIFFTag.MAX_DATATYPE; + private final static String CONSTRUCT = "can construct TIFFField with "; + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void testConstructors() { + + // test constructors + + TIFFTag tag = new TIFFTag( + NAME, NUM, 1 << TIFFTag.TIFF_SHORT | 1 << TIFFTag.TIFF_LONG); + TIFFField f; + + // constructor: TIFFField(tag, value) + boolean ok = false; + try { new TIFFField(null, 0); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid count"); + + // check value type recognition + int v = 1 << 16; + f = new TIFFField(tag, v - 1); + check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short"); + check(f.isIntegral(), "must be integral"); + f = new TIFFField(tag, v); + check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long"); + + // other checks + check(f.getAsLongs().length == 1, "invalid long[] size"); + check(f.isIntegral(), "must be integral"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + check(f.getValueAsString(0).equals(String.valueOf(v)), + "invalid string representation of value"); + check(f.getTag().getNumber() == f.getTagNumber(), + "invalid tag number"); + check(f.getCount() == 1, "invalid count"); + check(f.getTagNumber() == NUM, "invalid tag number"); + + // constructor: TIFFField(tag, type, count) + int type = TIFFTag.TIFF_SHORT; + + ok = false; + try { new TIFFField(null, type, 1); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, MAX_TYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid type tag"); + + // check that count == 1 for TIFF_IFD_POINTER + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL + // (see fix for JDK-8149120) + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for Rational"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for SRational"); + + ok = false; + try { new TIFFField(tag, type, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "with invalid data count"); + + f = new TIFFField(tag, type, 0); + check(f.getCount() == 0, "invalid count"); + check(!f.hasDirectory(), "must not have directory"); + + // constructor: TIFFField(tag, type, count, data) + double a[] = {0.1, 0.2, 0.3}; + ok = false; + try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, a.length - 1, a); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data count"); + + String a2[] = {"one", "two"}; + ok = false; + try { new TIFFField(tag, type, 2, a2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + + // constructor: TIFFField(tag, type, offset, dir) + List tags = new ArrayList<>(); + tags.add(tag); + TIFFTagSet sets[] = {new TIFFTagSet(tags)}; + TIFFDirectory dir = new TIFFDirectory(sets, null); + + ok = false; + try { new TIFFField(null, type, 4L, dir); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, 0L, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "non-positive offset"); + + long offset = 4; + + for (int t = MIN_TYPE; t <= MAX_TYPE; t++) { + + tag = new TIFFTag(NAME, NUM, 1 << t); + + // only TIFF_LONG and TIFF_IFD_POINTER types are allowed + if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) { + + f = new TIFFField(tag, t, offset, dir); + check(f.hasDirectory(), "must have directory"); + + check(f.getDirectory().getTag(NUM).getName().equals(NAME), + "invalid tag name"); + + check(f.getCount() == 1, "invalid count"); + check(f.getAsLong(0) == offset, "invalid offset"); + } else { + ok = false; + try { new TIFFField(tag, t, offset, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + } + } + + type = TIFFTag.TIFF_IFD_POINTER; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + + type = TIFFTag.TIFF_LONG; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + } + + private void testTypes() { + + // test getTypeName(), getTypeByName() methods + + boolean ok = false; + try { TIFFField.getTypeName(MIN_TYPE - 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + ok = false; + try { TIFFField.getTypeName(MAX_TYPE + 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + String name = TIFFField.getTypeName(type); + check(TIFFField.getTypeByName(name) == type, "invalid type"); + } + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + TIFFField f = new TIFFField(tag, type, 1); + check(f.getType() == type, "invalid type"); + + // check that invalid data types can not be used + for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) { + if (type2 != type) { + ok = false; + try { new TIFFField(tag, type2, 1); } // invalid type + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid type was successfully set"); + } + } + } + } + + private void testGetAs() { + + // test getAs...() methods + + int type = TIFFTag.TIFF_SHORT; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); + + short v = 123; + TIFFField f = new TIFFField(tag, v); + + check(f.getAsInt(0) == (int) v, "invalid int value"); + check(f.getAsLong(0) == (long) v, "invalid long value"); + check(f.getAsFloat(0) == (float) v, "invalid float value"); + check(f.getAsDouble(0) == (double) v, "invalid double value"); + check(f.getValueAsString(0).equals(Short.toString(v)), + "invalid string representation"); + + check(f.getAsInts().length == 1, "inavlid array size"); + check((int) v == f.getAsInts()[0], "invalid int value"); + + float fa[] = {0.01f, 1.01f}; + type = TIFFTag.TIFF_FLOAT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa); + check(f.getCount() == fa.length, "invalid count"); + float fa2[] = f.getAsFloats(); + check(fa2.length == fa.length, "invalid array size"); + + for (int i = 0; i < fa.length; i++) { + check(fa2[i] == fa[i], "invalid value"); + check(f.getAsDouble(i) == fa[i], "invalid value"); + check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int + check(f.getValueAsString(i).equals(Float.toString(fa[i])), + "invalid string representation"); + } + + byte ba[] = {-1, -10, -100}; + type = TIFFTag.TIFF_BYTE; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba); + check(f.getCount() == ba.length, "invalid count"); + byte ba2[] = f.getAsBytes(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ba.length; i++) { + check(ba[i] == ba2[i], "invalid value"); + check(ba[i] == (byte) f.getAsDouble(i), "invalid value"); + check(ba[i] == (byte) f.getAsLong(i), "invalid value"); + + int unsigned = ba[i] & 0xff; + check(f.getAsInt(i) == unsigned, "must be treated as unsigned"); + } + + char ca[] = {'a', 'z', 0xffff}; + type = TIFFTag.TIFF_SHORT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca); + check(f.getCount() == ca.length, "invalid count"); + char ca2[] = f.getAsChars(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ca.length; i++) { + check(ca[i] == ca2[i], "invalid value"); + check(ca[i] == (char) f.getAsDouble(i), "invalid value"); + check(ca[i] == (char) f.getAsLong(i), "invalid value"); + check(ca[i] == (char) f.getAsInt(i), "invalid value"); + } + + type = TIFFTag.TIFF_DOUBLE; + double da[] = {0.1, 0.2, 0.3}; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, da.length, da); + check(!f.isIntegral(), "isIntegral must be false"); + + double da2[] = f.getAsDoubles(); + check(f.getData() instanceof double[], "invalid data type"); + double da3[] = (double[]) f.getData(); + check((da.length == da2.length) && + (da.length == da2.length) && + (da.length == f.getCount()), + "invalid data count"); + for (int i = 0; i < da.length; ++i) { + check(da[i] == da2[i], "invalid data"); + check(da[i] == da3[i], "invalid data"); + } + + boolean ok = false; + try { f.getAsShorts(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { f.getAsRationals(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with negative count"); + + int n = 3; + Object + RA = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL, n), + SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n); + check(RA instanceof long[][], "invalid data type"); + check(SRA instanceof int[][], "invalid data type"); + + long ra[][] = (long[][]) RA; + int sra[][] = (int[][]) SRA; + check((ra.length == n) && (sra.length == n), "invalid data size"); + for (int i = 0; i < n; i++) { + check((ra[i].length == 2) && (sra[i].length == 2), + "invalid data size"); + ra[i][0] = 1; ra[i][1] = 5 + i; + sra[i][0] = -1; sra[i][1] = 5 + i; + } + + type = TIFFTag.TIFF_RATIONAL; + TIFFField f1 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, ra); + type = TIFFTag.TIFF_SRATIONAL; + TIFFField f2 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, sra); + + check((f1.getCount() == ra.length) && (f2.getCount() == sra.length), + "invalid data count"); + + check(f1.getAsRationals().length == n, "invalid data count"); + check(f2.getAsSRationals().length == n, "invalid data count"); + for (int i = 0; i < n; i++) { + long r[] = f1.getAsRational(i); + check(r.length == 2, "invalid data format"); + check((r[0] == 1) && (r[1] == i + 5), "invalid data"); + + int sr[] = f2.getAsSRational(i); + check(sr.length == 2, "invalid data format"); + check((sr[0] == -1) && (sr[1] == i + 5), "invalid data"); + + // check string representation + String s = Long.toString(r[0]) + "/" + Long.toString(r[1]); + check(s.equals(f1.getValueAsString(i)), + "invalid string representation"); + + s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]); + check(s.equals(f2.getValueAsString(i)), + "invalid string representation"); + + // see the documentation for getAsInt: + // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated + // by dividing the numerator into the denominator using + // double-precision arithmetic and then casting to int + check(f1.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + check(f2.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + } + + ok = false; + try { f1.getAsRational(ra.length); } + catch (ArrayIndexOutOfBoundsException e) { ok = true; } + check(ok, "invalid index"); + + String sa[] = {"-1.e-25", "22", "-1.23E5"}; + type = TIFFTag.TIFF_ASCII; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa); + + // test clone() method + TIFFField cloned = null; + try { cloned = f.clone(); } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + + check(f.getCount() == cloned.getCount(), "invalid cloned field count"); + + check(f.getCount() == sa.length, "invalid data count"); + for (int i = 0; i < sa.length; i++) { + check(sa[i].equals(f.getAsString(i)), "invalid data"); + // see docs: "data in TIFF_ASCII format will be parsed as by + // the Double.parseDouble method, with the result cast to int" + check(f.getAsInt(i) == + (int) Double.parseDouble(sa[i]), "invalid data"); + check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data"); + + check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data"); + } + } + + private void testCreateFromNode() { + + int type = TIFFTag.TIFF_LONG; + + List tags = new ArrayList<>(); + int v = 1234567; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + tags.add(tag); + TIFFTagSet ts = new TIFFTagSet(tags); + + boolean ok = false; + try { TIFFField.createFromMetadataNode(ts, null); } + catch (NullPointerException e) { ok = true; } + check(ok, "can create TIFFField from a null node"); + + TIFFField f = new TIFFField(tag, v); + Node node = f.getAsNativeNode(); + check(node.getNodeName().equals(f.getClass().getSimpleName()), + "invalid node name"); + + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + String an = attrs.item(i).getNodeName().toLowerCase(); + String av = attrs.item(i).getNodeValue(); + if (an.contains("name")) { + check(av.equals(NAME), "invalid tag name"); + } else if (an.contains("number")) { + check(av.equals(Integer.toString(NUM)), "invalid tag number"); + } + } + + // invalid node + IIOMetadataNode nok = new IIOMetadataNode("NOK"); + + ok = false; + try { TIFFField.createFromMetadataNode(ts, nok); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid node name"); + + TIFFField f2 = TIFFField.createFromMetadataNode(ts, node); + check(f2.getType() == type, "invalid type"); + check(f2.getTagNumber() == NUM, "invalid tag number"); + check(f2.getTag().getName().equals(NAME), "invalid tag name"); + check(f2.getCount() == 1, "invalid count"); + check(f2.getAsInt(0) == v, "invalid value"); + } + + public static void main(String[] args) { + + TIFFFieldTest test = new TIFFFieldTest(); + test.testConstructors(); + test.testCreateFromNode(); + test.testTypes(); + test.testGetAs(); + } +} diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java new file mode 100644 index 00000000000..34fd5ed8983 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8149028 + * @author a.stepanov + * @summary check TIFFDirectory manipulation + * by means of TIFFImageReadParam + * @run main TIFFImageReadParamTest + */ + + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.plugins.tiff.*; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; + +public class TIFFImageReadParamTest { + + private final static String FILENAME = "test.tiff"; + private final static int SZ = 100; + private final static Color C = Color.RED; + + private final static String GEO_DATA = "test params"; + private final static int GEO_N = GeoTIFFTagSet.TAG_GEO_ASCII_PARAMS; + + private final static String EXIF_DATA = "2000:01:01 00:00:01"; + private final static int EXIF_N = ExifTIFFTagSet.TAG_DATE_TIME_ORIGINAL; + + private final static String GPS_DATA = + ExifGPSTagSet.STATUS_MEASUREMENT_IN_PROGRESS; + private final static int GPS_N = ExifGPSTagSet.TAG_GPS_STATUS; + + private final static short FAX_DATA = + FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED; + private final static int FAX_N = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA; + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void addASCIIField(TIFFDirectory d, + String name, + String data, + int num) { + + String a[] = {data}; + d.addTIFFField(new TIFFField( + new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII), + TIFFTag.TIFF_ASCII, 1, a)); + } + + private void checkASCIIValue(TIFFDirectory d, + String what, + String data, + int num) { + + TIFFField f = d.getTIFFField(num); + check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII"); + check(f.getCount() == 1, "invalid " + what + " data count"); + check(f.getValueAsString(0).equals(data), + "invalid " + what + " data"); + } + + + private void writeImage() throws Exception { + + OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img = + new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(C); + g.fillRect(0, 0, SZ, SZ); + g.dispose(); + + IIOMetadata metadata = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img), writer.getDefaultWriteParam()); + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + // add some extension tags + addASCIIField(dir, "GeoAsciiParamsTag", GEO_DATA, GEO_N); + addASCIIField(dir, "DateTimeOriginal", EXIF_DATA, EXIF_N); + addASCIIField(dir, "GPSStatus", GPS_DATA, GPS_N); + + dir.addTIFFField(new TIFFField(new TIFFTag( + "CleanFaxData", FAX_N, 1 << TIFFTag.TIFF_SHORT), FAX_DATA)); + + IIOMetadata data = dir.getAsMetadata(); + + writer.write(new IIOImage(img, null, data)); + + ios.flush(); + writer.dispose(); + } + } + + private void checkImage(BufferedImage img) { + + check(img.getWidth() == SZ, "invalid image width"); + check(img.getHeight() == SZ, "invalid image height"); + Color c = new Color(img.getRGB(SZ / 2, SZ / 2)); + check(c.equals(C), "invalid image color"); + } + + private TIFFDirectory getDir(TIFFTagSet[] add, + TIFFTagSet[] remove) throws Exception { + + ImageReader reader = getTIFFReader(); + + ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); + reader.setInput(s, false, true); + + int ni = reader.getNumImages(true); + check(ni == 1, "invalid number of images: " + ni); + + TIFFImageReadParam param = new TIFFImageReadParam(); + for (TIFFTagSet ts: add) { param.addAllowedTagSet(ts); } + for (TIFFTagSet ts: remove) { param.removeAllowedTagSet(ts); } + + IIOImage img = reader.readAll(0, param); + + // just in case, check image + checkImage((BufferedImage) img.getRenderedImage()); + + IIOMetadata metadata = img.getMetadata(); + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + reader.dispose(); + s.close(); + + return dir; + } + + private void simpleChecks() { + + TIFFImageReadParam param = new TIFFImageReadParam(); + + java.util.List allowed = param.getAllowedTagSets(); + + // see docs + check(allowed.contains(BaselineTIFFTagSet.getInstance()), + "must contain BaselineTIFFTagSet"); + check(allowed.contains(FaxTIFFTagSet.getInstance()), + "must contain FaxTIFFTagSet"); + check(allowed.contains(ExifParentTIFFTagSet.getInstance()), + "must contain ExifParentTIFFTagSet"); + check(allowed.contains(GeoTIFFTagSet.getInstance()), + "must contain GeoTIFFTagSet"); + + TIFFTagSet gps = ExifGPSTagSet.getInstance(); + param.addAllowedTagSet(gps); + check(param.getAllowedTagSets().contains(gps), + "must contain ExifGPSTagSet"); + + param.removeAllowedTagSet(gps); + check(!param.getAllowedTagSets().contains(gps), + "must not contain ExifGPSTagSet"); + + // check that repeating remove goes properly + param.removeAllowedTagSet(gps); + + boolean ok = false; + try { param.addAllowedTagSet(null); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "must not be able to add null tag set"); + + ok = false; + try { param.removeAllowedTagSet(null); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "must not be able to remove null tag set"); + } + + private void run() { + + simpleChecks(); + + try { + + writeImage(); + + TIFFTagSet + empty[] = {}, + geo[] = { GeoTIFFTagSet.getInstance() }, + exif[] = { ExifTIFFTagSet.getInstance() }, + gps[] = { ExifGPSTagSet.getInstance() }, + fax[] = { FaxTIFFTagSet.getInstance() }; + + // default param state + TIFFDirectory dir = getDir(empty, empty); + // Geo and Fax are default allowed tag sets + check(dir.containsTIFFField(GEO_N), "must contain Geo field"); + checkASCIIValue(dir, "Geo", GEO_DATA, GEO_N); + check(dir.containsTIFFField(FAX_N), "must contain Fax field"); + check( + (dir.getTIFFField(FAX_N).getCount() == 1) && + (dir.getTIFFField(FAX_N).getAsInt(0) == FAX_DATA), + "invalid Fax field value"); + + // corresponding tag sets are non-default + check(!dir.containsTIFFField(EXIF_N), "must not contain Geo field"); + check(!dir.containsTIFFField(GPS_N), "must not contain GPS field"); + + // remove Fax + dir = getDir(empty, fax); + check(!dir.containsTIFFField(FAX_N), "must not contain Fax field"); + + // add EXIF, remove Geo + dir = getDir(exif, geo); + check(dir.containsTIFFField(EXIF_N), "must contain EXIF field"); + checkASCIIValue(dir, "EXIF", EXIF_DATA, EXIF_N); + check(!dir.containsTIFFField(GEO_N), "must not contain Geo field"); + + // add GPS + dir = getDir(gps, empty); + check(dir.containsTIFFField(GPS_N), "must contain GPS field"); + checkASCIIValue(dir, "GPS", GPS_DATA, GPS_N); + + } catch (Exception e) { throw new RuntimeException(e); } + } + + public static void main(String[] args) { + (new TIFFImageReadParamTest()).run(); + } +} diff --git a/jdk/test/javax/imageio/stream/NullStreamCheckTest.java b/jdk/test/javax/imageio/stream/NullStreamCheckTest.java new file mode 100644 index 00000000000..f763b9de1e6 --- /dev/null +++ b/jdk/test/javax/imageio/stream/NullStreamCheckTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8044289 + * @summary Test verifies that when some of the read() and write() methods + * are not able to get stream from createImageInputStream() and + * createImageOutputStream() are we doing null check for stream + * and throwing IOException as per specification. + * @run main NullStreamCheckTest + */ + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import javax.imageio.ImageIO; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.spi.ImageOutputStreamSpi; + +public class NullStreamCheckTest { + + // get ImageIORegistry default instance. + private static final IIORegistry localRegistry = IIORegistry. + getDefaultInstance(); + // stream variables needed for input and output. + static LocalOutputStream outputStream = new LocalOutputStream(); + static LocalInputStream inputStream = new LocalInputStream(); + + static final int width = 50, height = 50; + + // input and output BufferedImage needed while read and write. + static BufferedImage inputImage = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + // creates test file needed for read and write in local directory. + private static File createTestFile(String name) throws IOException { + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep; + File directory = new File(filePath); + File tmpTestFile = File.createTempFile(name, ".png", directory); + directory.delete(); + return tmpTestFile; + } + + /* if we catch expected IOException message return + * false otherwise return true. + */ + private static boolean verifyOutputExceptionMessage(IOException ex) { + String message = ex.getMessage(); + return (!message.equals("Can't create an ImageOutputStream!")); + } + + /* if we catch expected IOException message return + * false otherwise return true. + */ + private static boolean verifyInputExceptionMessage(IOException ex) { + String message = ex.getMessage(); + return (!message.equals("Can't create an ImageInputStream!")); + } + + private static void verifyFileWrite() throws IOException { + File outputTestFile = createTestFile("outputTestFile"); + try { + ImageIO.write(inputImage, "png", outputTestFile); + } catch (IOException ex) { + if (verifyOutputExceptionMessage(ex)) + throw ex; + } finally { + outputTestFile.delete(); + } + } + + private static void verifyStreamWrite() throws IOException { + try { + ImageIO.write(inputImage, "png", outputStream); + } catch (IOException ex) { + if (verifyOutputExceptionMessage(ex)) + throw ex; + } finally { + try { + outputStream.close(); + } catch (IOException ex) { + throw ex; + } + } + } + + private static void verifyFileRead() throws IOException { + File inputTestFile = createTestFile("inputTestFile"); + try { + ImageIO.read(inputTestFile); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } finally { + inputTestFile.delete(); + } + } + + private static void verifyStreamRead() throws IOException { + try { + ImageIO.read(inputStream); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } finally { + try { + inputStream.close(); + } catch (IOException ex) { + throw ex; + } + } + } + + private static void verifyUrlRead() throws IOException { + URL url; + File inputTestUrlFile = createTestFile("inputTestFile"); + try { + try { + url = inputTestUrlFile.toURI().toURL(); + } catch (MalformedURLException ex) { + throw ex; + } + + try { + ImageIO.read(url); + } catch (IOException ex) { + if (verifyInputExceptionMessage(ex)) + throw ex; + } + } finally { + inputTestUrlFile.delete(); + } + } + + public static void main(String[] args) throws IOException, + MalformedURLException { + + /* deregister ImageOutputStreamSpi so that we creatImageOutputStream + * returns null while writing. + */ + localRegistry.deregisterAll(ImageOutputStreamSpi.class); + /* verify possible ImageIO.write() scenario's for null stream output + * from createImageOutputStream() API in ImageIO class. + */ + verifyFileWrite(); + verifyStreamWrite(); + + /* deregister ImageInputStreamSpi so that we creatImageInputStream + * returns null while reading. + */ + localRegistry.deregisterAll(ImageInputStreamSpi.class); + /* verify possible ImageIO.read() scenario's for null stream output + * from createImageInputStream API in ImageIO class. + */ + verifyFileRead(); + verifyStreamRead(); + verifyUrlRead(); + } + + static class LocalOutputStream extends OutputStream { + + @Override + public void write(int i) throws IOException { + } + } + + static class LocalInputStream extends InputStream { + + @Override + public int read() throws IOException { + return 0; + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java new file mode 100644 index 00000000000..54e404dcf6f --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits16ToFromFloatArray.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.*; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits16ToFromFloatArray { + + private static final int SIZE = 16; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static short MID_U = (short) (Short.MAX_VALUE + 1); + private static short MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) (Short.MIN_VALUE >> 8), (byte) (Short.MIN_VALUE & 0xff), 0, + 0, (byte) (Short.MAX_VALUE >> 8), (byte) (Short.MAX_VALUE & 0xff) + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, (byte) (MID_U >> 8), (byte) (MID_U & 0xff), + (byte) (MAX_U >> 8), (byte) (MAX_U >> 8) + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) (Short.MIN_VALUE & 0xff), (byte) (Short.MIN_VALUE >> 8), 0, + 0, (byte) (Short.MAX_VALUE & 0xff), (byte) (Short.MAX_VALUE >> 8) + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, (byte) (MID_U & 0xff), (byte) (MID_U >> 8), + (byte) (MAX_U >> 8), (byte) (MAX_U >> 8) + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println("enc = " + enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java new file mode 100644 index 00000000000..1bd215435d2 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits24ToFromFloatArray.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits24ToFromFloatArray { + + private static final int SIZE = 24; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static int MIN_S = -8_388_608; + private static int MAX_S = 8_388_607; + + private static int MID_U = 0xFFFFFF / 2 + 1; + private static int MAX_U = 0xFFFFFF; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((MIN_S >> 16) & 0xff), + (byte) ((MIN_S >> 8) & 0xff), + (byte) ((MIN_S >> 0) & 0xff), + 0, 0, 0, + (byte) ((MAX_S >> 16) & 0xff), + (byte) ((MAX_S >> 8) & 0xff), + (byte) ((MAX_S >> 0) & 0xff), + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) ((MIN_S >> 0) & 0xff), + (byte) ((MIN_S >> 8) & 0xff), + (byte) ((MIN_S >> 16) & 0xff), + 0, 0, 0, + (byte) ((MAX_S >> 0) & 0xff), + (byte) ((MAX_S >> 8) & 0xff), + (byte) ((MAX_S >> 16) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println(enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java new file mode 100644 index 00000000000..7a550a54df3 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits32ToFromFloatArray.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits32ToFromFloatArray { + + private static final int SIZE = 32; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static int MID_U = (int) (Integer.MAX_VALUE + 1); + private static int MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((Integer.MIN_VALUE >> 24) & 0xff), + (byte) ((Integer.MIN_VALUE >> 16) & 0xff), + (byte) ((Integer.MIN_VALUE >> 8) & 0xff), + (byte) ((Integer.MIN_VALUE >> 0) & 0xff), + 0, 0, 0, 0, + (byte) ((Integer.MAX_VALUE >> 24) & 0xff), + (byte) ((Integer.MAX_VALUE >> 16) & 0xff), + (byte) ((Integer.MAX_VALUE >> 8) & 0xff), + (byte) ((Integer.MAX_VALUE >> 0) & 0xff), + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, 0, + (byte) ((MID_U >> 24) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MAX_U >> 24) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + (byte) ((Integer.MIN_VALUE >> 0) & 0xff), + (byte) ((Integer.MIN_VALUE >> 8) & 0xff), + (byte) ((Integer.MIN_VALUE >> 16) & 0xff), + (byte) ((Integer.MIN_VALUE >> 24) & 0xff), + 0, 0, 0, 0, + (byte) ((Integer.MAX_VALUE >> 0) & 0xff), + (byte) ((Integer.MAX_VALUE >> 8) & 0xff), + (byte) ((Integer.MAX_VALUE >> 16) & 0xff), + (byte) ((Integer.MAX_VALUE >> 24) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, 0, + (byte) ((MID_U >> 0) & 0xff), + (byte) ((MID_U >> 8) & 0xff), + (byte) ((MID_U >> 16) & 0xff), + (byte) ((MID_U >> 24) & 0xff), + (byte) ((MAX_U >> 0) & 0xff), + (byte) ((MAX_U >> 8) & 0xff), + (byte) ((MAX_U >> 16) & 0xff), + (byte) ((MAX_U >> 24) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java new file mode 100644 index 00000000000..558835bcb52 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits64ToFromFloatArray.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits64ToFromFloatArray { + + private static final int SIZE = 64; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static long MID_U = (long) (Long.MAX_VALUE + 1); + private static long MAX_U = -1; + + // BIG ENDIAN + private static final byte[] SIGNED_BIG = { + (byte) ((Long.MIN_VALUE >> 56) & 0xff), + (byte) ((Long.MIN_VALUE >> 48) & 0xff), + (byte) ((Long.MIN_VALUE >> 40) & 0xff), + (byte) ((Long.MIN_VALUE >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + 0, 0, 0, 0, + 0, 0, 0, 0, + (byte) ((Long.MAX_VALUE >> 56) & 0xff), + (byte) ((Long.MAX_VALUE >> 48) & 0xff), + (byte) ((Long.MAX_VALUE >> 40) & 0xff), + (byte) ((Long.MAX_VALUE >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + }; + + private static final byte[] UNSIGNED_BIG = { + 0, 0, 0, 0, + 0, 0, 0, 0, + (byte) ((MID_U >> 56) & 0xff), + (byte) ((MID_U >> 48) & 0xff), + (byte) ((MID_U >> 40) & 0xff), + (byte) ((MID_U >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MAX_U >> 56) & 0xff), + (byte) ((MAX_U >> 48) & 0xff), + (byte) ((MAX_U >> 40) & 0xff), + (byte) ((MAX_U >> 32) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + }; + + // LITTLE ENDIAN + private static final byte[] SIGNED_LITTLE = { + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((Long.MIN_VALUE >> 32) & 0xff), + (byte) ((Long.MIN_VALUE >> 40) & 0xff), + (byte) ((Long.MIN_VALUE >> 48) & 0xff), + (byte) ((Long.MIN_VALUE >> 56) & 0xff), + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((Long.MAX_VALUE >> 32) & 0xff), + (byte) ((Long.MAX_VALUE >> 40) & 0xff), + (byte) ((Long.MAX_VALUE >> 48) & 0xff), + (byte) ((Long.MAX_VALUE >> 56) & 0xff), + }; + + private static final byte[] UNSIGNED_LITTLE = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MID_U >> 32) & 0xff), + (byte) ((MID_U >> 40) & 0xff), + (byte) ((MID_U >> 48) & 0xff), + (byte) ((MID_U >> 56) & 0xff), + 0, 0, 0, 0, // current javasound impl will ignore this + (byte) ((MAX_U >> 32) & 0xff), + (byte) ((MAX_U >> 40) & 0xff), + (byte) ((MAX_U >> 48) & 0xff), + (byte) ((MAX_U >> 56) & 0xff), + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED_BIG, true); + test(PCM_UNSIGNED, UNSIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_LITTLE, false); + test(PCM_SIGNED, SIGNED_BIG, true); + } + + private static void test(final Encoding enc, final byte[] expected, + boolean end) { + System.err.println(enc); + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + end); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java new file mode 100644 index 00000000000..1d4ab606745 --- /dev/null +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/Bits8ToFromFloatArray.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; + +import com.sun.media.sound.AudioFloatConverter; + +import static javax.sound.sampled.AudioFormat.Encoding.*; + +/** + * @test + * @bug 8152501 + * @modules java.desktop/com.sun.media.sound + */ +public final class Bits8ToFromFloatArray { + + private static final int SIZE = 8; + + private static final float[] FLOATS = {-1.0f, 0, 1.0f}; + + private static final byte[] SIGNED = {Byte.MIN_VALUE, 0, Byte.MAX_VALUE}; + + private static final byte[] UNSIGNED = { + 0, (byte) (Byte.MAX_VALUE + 1), (byte) -1 + }; + + public static void main(final String[] args) { + test(PCM_UNSIGNED, UNSIGNED); + test(PCM_SIGNED, SIGNED); + } + + private static void test(final Encoding enc, final byte[] expected) { + AudioFormat af = new AudioFormat(enc, 44100, SIZE, 1, SIZE / 8, 44100, + true); + byte[] bytes = new byte[FLOATS.length * af.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(af); + + conv.toByteArray(FLOATS, bytes); + + if (!Arrays.equals(bytes, expected)) { + System.err.println("Actual: " + Arrays.toString(bytes)); + System.err.println("Expected: " + Arrays.toString(expected)); + throw new RuntimeException(); + } + + float[] floats = new float[bytes.length / af.getFrameSize()]; + conv.toFloatArray(bytes, floats); + + if (!Arrays.equals(floats, FLOATS)) { + System.err.println("Actual: " + Arrays.toString(floats)); + System.err.println("Expected: " + Arrays.toString(FLOATS)); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java b/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java new file mode 100644 index 00000000000..122b819255c --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/DeserializedJFileChooser/DeserializedJFileChooserTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8146301 + * @summary Enter key does not work in a deserialized JFileChooser. + * @run main DeserializedJFileChooserTest + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class DeserializedJFileChooserTest { + + private static int state = -1; + private static JFileChooser deserialized; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater( () -> { + try { + JFileChooser jfc = new JFileChooser(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(jfc); + oos.close(); + ByteArrayInputStream bis = + new ByteArrayInputStream(bos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bis); + deserialized = (JFileChooser) ois.readObject(); + state = deserialized.showOpenDialog(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.delay(1000); + if (state != JFileChooser.APPROVE_OPTION) { + deserialized.cancelSelection(); + throw new RuntimeException("Failed"); + } + } +} diff --git a/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java b/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java new file mode 100644 index 00000000000..6af5c95e473 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.beans.PropertyVetoException; + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; + +/** + * @test + * @bug 8144166 + * @requires (os.family == "mac") + */ +public final class DockIconRepaint { + + private static volatile Color color; + + private static JFrame frame; + + private static JInternalFrame jif; + + private static Robot robot; + + private static Point iconLoc; + + private static Rectangle iconBounds; + + public static void main(final String[] args) throws Exception { + robot = new Robot(); + EventQueue.invokeAndWait(DockIconRepaint::createUI); + try { + robot.waitForIdle(); + color = Color.BLUE; + test(); + color = Color.RED; + test(); + color = Color.GREEN; + test(); + } finally { + frame.dispose(); + } + } + + private static void test() throws Exception { + // maximize the frame to force repaint + EventQueue.invokeAndWait(() -> { + try { + jif.setIcon(false); + jif.setMaximum(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + }); + robot.waitForIdle(); + Thread.sleep(1000); + // minimize the frame to dock, the icon should be up2date + EventQueue.invokeAndWait(() -> { + try { + jif.setIcon(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + iconLoc = jif.getDesktopIcon().getLocationOnScreen(); + iconBounds = jif.getDesktopIcon().getBounds(); + }); + robot.waitForIdle(); + Thread.sleep(1000); + + final Color c = robot.getPixelColor(iconLoc.x + iconBounds.width / 2, + iconLoc.y + iconBounds.height / 2); + if (c.getRGB() != color.getRGB()) { + System.err.println("Exp: " + Integer.toHexString(color.getRGB())); + System.err.println("Actual: " + Integer.toHexString(c.getRGB())); + throw new RuntimeException("Wrong color."); + } + } + + private static void createUI() { + frame = new JFrame(); + frame.setUndecorated(true); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + final JDesktopPane pane = new JDesktopPane(); + final JPanel panel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + g.setColor(color); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + jif = new JInternalFrame(); + jif.add(panel); + jif.setVisible(true); + jif.setSize(300, 300); + pane.add(jif); + frame.add(pane); + frame.setVisible(true); + } +} diff --git a/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java b/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java new file mode 100644 index 00000000000..0a0df91379f --- /dev/null +++ b/jdk/test/javax/swing/JPopupMenu/6949414/JPopupMenuEndlessLoopTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 6949414 6424606 + * @summary JMenu.buildMenuElementArray() endless loop + * @run main/timeout=5 JPopupMenuEndlessLoopTest + */ +public class JPopupMenuEndlessLoopTest { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + + JPopupMenu popup = new JPopupMenu("Popup Menu"); + JMenu menu = new JMenu("Menu"); + menu.add(new JMenuItem("Menu Item")); + popup.add(menu); + menu.doClick(); + MenuElement[] elems = MenuSelectionManager + .defaultManager().getSelectedPath(); + + if (elems == null || elems.length == 0) { + throw new RuntimeException("Empty Selection"); + } + + if (elems[0] != popup || elems[1] != menu) { + throw new RuntimeException("Necessary menus are not selected!"); + } + }); + } +} diff --git a/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java b/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java new file mode 100644 index 00000000000..834da2ef522 --- /dev/null +++ b/jdk/test/javax/swing/JTabbedPane/8137169/ScrollableTabbedPaneTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8137169 + * @summary verifies TabbedScrollPane minimum height for all Look and Feels + * @library ../../regtesthelpers + * @build Util + * @run main ScrollableTabbedPaneTest + */ + +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class ScrollableTabbedPaneTest { + + private static JFrame frame; + private static JTabbedPane pane; + private static Robot robot; + private static volatile String errorString = ""; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.delay(1000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName(), + lookAndFeelItem.getName()); + } + if (!"".equals(errorString)) { + throw new RuntimeException("Error Log:\n" + errorString); + } + } + + private static void executeCase(String lookAndFeelString, String shortLAF) + throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createUI(shortLAF); + stepsToExecute(shortLAF); + + createLeftUI(shortLAF); + stepsToExecute(shortLAF); + + createRightUI(shortLAF); + stepsToExecute(shortLAF); + } + } + + private static void stepsToExecute(String shortLAF) throws Exception { + robot.delay(100); + runTestCase(shortLAF); + robot.delay(1000); + cleanUp(); + robot.delay(1000); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static void createUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + private static void createLeftUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + pane.setTabPlacement(SwingConstants.LEFT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + + private static void createRightUI(final String shortLAF) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(shortLAF); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + pane = new JTabbedPane(); + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + pane.setTabPlacement(SwingConstants.RIGHT); + frame.add(pane); + frame.setSize(500, 500); + } + }); + } + + private static void runTestCase(String shortLAF) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + int i = 0; + int value= 0; + do { + String title = "Tab" + (i + 1); + pane.addTab(title, new JPanel()); + int tempValue = pane.getMinimumSize().height; + if(value==0) { + value = tempValue; + } + if(value != tempValue) { + String error = "[" + shortLAF + + "]: [Error]: TabbedScrollPane fails"; + errorString += error; + } + + ++i; + } while (i < 10); + } + }); + } +} + diff --git a/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java b/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java new file mode 100644 index 00000000000..c8e2492de2f --- /dev/null +++ b/jdk/test/javax/swing/LookAndFeel/6897701/JMenuItemsTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 6897701 + * @summary Verify JMenu and JMenuItem Disabled state for Nimbus LAF + * @run main JMenuItemsTest + */ +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class JMenuItemsTest { + + private static JFrame mainFrame; + private static JMenu disabledMenu; + private static JMenuItem disabledMenuItem; + + public JMenuItemsTest() { + createUI(); + } + + private void createUI() { + + mainFrame = new JFrame("Test"); + + disabledMenu = new JMenu("Disabled Menu"); + disabledMenu.setForeground(Color.BLUE); + disabledMenu.setEnabled(false); + + disabledMenuItem = new JMenuItem("Disabled MenuItem"); + disabledMenuItem.setForeground(Color.BLUE); + disabledMenuItem.setEnabled(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar = new JMenuBar(); + menuBar.add(disabledMenu); + menuBar.add(disabledMenuItem); + + mainFrame.add(menuBar); + mainFrame.pack(); + mainFrame.setVisible(true); + } + + private void dispose() { + mainFrame.dispose(); + } + + private void testDisabledStateOfJMenu() { + + // Test disabled JMenu state + Rectangle rect = disabledMenu.getBounds(); + BufferedImage image = new BufferedImage(rect.width, rect.height, + BufferedImage.TYPE_INT_ARGB); + disabledMenu.paint(image.getGraphics()); + int y = image.getHeight() / 2; + for (int x = 0; x < image.getWidth(); x++) { + Color c = new Color(image.getRGB(x, y)); + if (c.equals(Color.BLUE)) { + dispose(); + throw new RuntimeException("JMenu Disabled" + + " State not Valid."); + } + } + + } + + private void testDisabledStateOfJMenuItem() { + + // Test disabled JMenuItem state + Rectangle rect = disabledMenuItem.getBounds(); + BufferedImage image = new BufferedImage(rect.width, rect.height, + BufferedImage.TYPE_INT_ARGB); + disabledMenuItem.paint(image.getGraphics()); + int y = image.getHeight() / 2; + for (int x = 0; x < image.getWidth(); x++) { + Color c = new Color(image.getRGB(x, y)); + if (c.equals(Color.BLUE)) { + dispose(); + throw new RuntimeException("JMenuItem Disabled" + + " State not Valid."); + } + } + + } + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + SwingUtilities.invokeAndWait(() -> { + + try { + JMenuItemsTest obj = new JMenuItemsTest(); + obj.testDisabledStateOfJMenu(); + obj.testDisabledStateOfJMenuItem(); + obj.dispose(); + + } catch (Exception ex) { + throw ex; + } + + }); + } +} diff --git a/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java b/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java new file mode 100644 index 00000000000..fce9408717d --- /dev/null +++ b/jdk/test/javax/swing/text/html/CSS/ColorValue/RGBColorValueTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +/* + * @test + * @bug 8149631 + * @summary rgb(...) CSS color values are not parsed properly + * @run main RGBColorValueTest + */ + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.StyleSheet; + +import static javax.swing.text.html.CSS.Attribute.*; + +public class RGBColorValueTest { + + public static void main(String[] args) { + StyleSheet styleSheet = new StyleSheet(); + AttributeSet attributeSet = styleSheet. + getDeclaration("border-color: rgb(1, 2, 3) rgb(1, 2, 4);"); + if (!attributeSet.getAttribute(BORDER_TOP_COLOR).toString() + .equals("rgb(1, 2, 3)") || + !attributeSet.getAttribute(BORDER_BOTTOM_COLOR).toString() + .equals("rgb(1, 2, 3)") || + !attributeSet.getAttribute(BORDER_RIGHT_COLOR).toString() + .equals("rgb(1, 2, 4)") || + !attributeSet.getAttribute(BORDER_LEFT_COLOR).toString() + .equals("rgb(1, 2, 4)") ) { + throw new RuntimeException("Failed"); + } + } +} diff --git a/jdk/test/jdk/internal/jrtfs/PathOps.java b/jdk/test/jdk/internal/jrtfs/PathOps.java index 2a28e0571e2..2170ae869ab 100644 --- a/jdk/test/jdk/internal/jrtfs/PathOps.java +++ b/jdk/test/jdk/internal/jrtfs/PathOps.java @@ -43,15 +43,15 @@ public class PathOps { private Path path; private Exception exc; - private PathOps(String s) { + private PathOps(String first, String... more) { out.println(); - input = s; + input = first; try { - path = fs.getPath(s); - out.format("%s -> %s", s, path); + path = fs.getPath(first, more); + out.format("%s -> %s", first, path); } catch (Exception x) { exc = x; - out.format("%s -> %s", s, x); + out.format("%s -> %s", first, x); } out.println(); } @@ -175,6 +175,13 @@ public class PathOps { return this; } + PathOps resolveSibling(String other, String expected) { + out.format("test resolveSibling %s\n", other); + checkPath(); + check(path.resolveSibling(other), expected); + return this; + } + PathOps relativize(String other, String expected) { out.format("test relativize %s\n", other); checkPath(); @@ -220,6 +227,10 @@ public class PathOps { return new PathOps(s); } + static PathOps test(String first, String... more) { + return new PathOps(first, more); + } + // -- PathOpss -- static void header(String s) { @@ -231,6 +242,26 @@ public class PathOps { static void doPathOpTests() { header("Path operations"); + // construction + test("/") + .string("/"); + test("/", "") + .string("/"); + test("/", "foo") + .string("/foo"); + test("/", "/foo") + .string("/foo"); + test("/", "foo/") + .string("/foo"); + test("foo", "bar", "gus") + .string("foo/bar/gus"); + test("") + .string(""); + test("", "/") + .string("/"); + test("", "foo", "", "bar", "", "/gus") + .string("foo/bar/gus"); + // all components test("/a/b/c") .root("/") @@ -254,6 +285,10 @@ public class PathOps { .root(null) .parent(null) .name("foo"); + test("") + .root(null) + .parent(null) + .name(""); // startsWith test("") @@ -261,6 +296,7 @@ public class PathOps { .notStarts("/"); test("/") .starts("/") + .notStarts("") .notStarts("/foo"); test("/foo") .starts("/") @@ -278,6 +314,7 @@ public class PathOps { .notStarts(""); test("foo") .starts("foo") + .notStarts("") .notStarts("f"); test("foo/bar") .starts("foo") @@ -293,12 +330,14 @@ public class PathOps { .notEnds("/"); test("/") .ends("/") + .notEnds("") .notEnds("foo") .notEnds("/foo"); test("/foo") .ends("foo") .ends("/foo") - .notEnds("/"); + .notEnds("/") + .notEnds("fool"); test("/foo/bar") .ends("bar") .ends("foo/bar") @@ -312,13 +351,31 @@ public class PathOps { .ends("/foo/bar") .notEnds("/bar"); test("foo") - .ends("foo"); + .ends("foo") + .notEnds("") + .notEnds("oo") + .notEnds("oola"); test("foo/bar") .ends("bar") .ends("bar/") .ends("foo/bar/") - .ends("foo/bar"); - + .ends("foo/bar") + .notEnds("r") + .notEnds("barmaid") + .notEnds("/bar") + .notEnds("ar") + .notEnds("barack") + .notEnds("/bar") + .notEnds("o/bar"); + test("foo/bar/gus") + .ends("gus") + .ends("bar/gus") + .ends("foo/bar/gus") + .notEnds("g") + .notEnds("/gus") + .notEnds("r/gus") + .notEnds("barack/gus") + .notEnds("bar/gust"); // elements test("a/b/c") @@ -339,16 +396,54 @@ public class PathOps { // resolve test("/tmp") .resolve("foo", "/tmp/foo") - .resolve("/foo", "/foo"); + .resolve("/foo", "/foo") + .resolve("", "/tmp"); test("tmp") .resolve("foo", "tmp/foo") + .resolve("/foo", "/foo") + .resolve("", "tmp"); + test("") + .resolve("", "") + .resolve("foo", "foo") .resolve("/foo", "/foo"); + // resolveSibling + test("foo") + .resolveSibling("bar", "bar") + .resolveSibling("/bar", "/bar") + .resolveSibling("", ""); + test("foo/bar") + .resolveSibling("gus", "foo/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "foo"); + test("/foo") + .resolveSibling("gus", "/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "/"); + test("/foo/bar") + .resolveSibling("gus", "/foo/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "/foo"); + test("") + .resolveSibling("foo", "foo") + .resolveSibling("/foo", "/foo") + .resolve("", ""); + // relativize test("/a/b/c") .relativize("/a/b/c", "") .relativize("/a/b/c/d/e", "d/e") - .relativize("/a/x", "../../x"); + .relativize("/a/x", "../../x") + .relativize("/x", "../../../x"); + test("a/b/c") + .relativize("a/b/c/d", "d") + .relativize("a/x", "../../x") + .relativize("x", "../../../x") + .relativize("", "../../.."); + test("") + .relativize("a", "a") + .relativize("a/b/c", "a/b/c") + .relativize("", ""); // normalize test("/") diff --git a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java index f6d111475ef..81336e20299 100644 --- a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java +++ b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java @@ -31,6 +31,7 @@ import java.net.URI; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; public class WithSecurityManager { public static void main(String[] args) throws Exception { @@ -61,7 +62,7 @@ public class WithSecurityManager { // check FileSystems.newFileSystem try { - FileSystems.newFileSystem(URI.create("jrt:/"), null); + FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap()); if (!allow) throw new RuntimeException("access not expected"); } catch (SecurityException se) { if (allow) diff --git a/jdk/test/jdk/internal/jrtfs/remote/Main.java b/jdk/test/jdk/internal/jrtfs/remote/Main.java index 8ef6303526d..9b22c8308d3 100644 --- a/jdk/test/jdk/internal/jrtfs/remote/Main.java +++ b/jdk/test/jdk/internal/jrtfs/remote/Main.java @@ -30,6 +30,7 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.stream.Stream; /** @@ -69,11 +70,12 @@ public class Main { private static FileSystem createFsWithURLClassloader(String javaHome) throws IOException{ URL url = Paths.get(javaHome, "jrt-fs.jar").toUri().toURL(); URLClassLoader loader = new URLClassLoader(new URL[] { url }); - return FileSystems.newFileSystem(URI.create("jrt:/"), null, loader); + return FileSystems.newFileSystem(URI.create("jrt:/"), + Collections.emptyMap(), + loader); } private static FileSystem createFsByInstalledProvider() throws IOException { return FileSystems.getFileSystem(URI.create("jrt:/")); } } - diff --git a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java index 2c3d588369f..7ea315ad5d6 100644 --- a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java +++ b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8141609 + * @bug 8141609 8154403 * @summary Verify JDK 8 can use jrt-fs.jar to work with jrt file system. * @run main RemoteRuntimeImageTest */ @@ -63,7 +63,6 @@ public class RemoteRuntimeImageTest { String java = jdk8Path.resolve("bin/java").toAbsolutePath().toString(); String javac = jdk8Path.resolve("bin/javac").toAbsolutePath().toString(); - Files.createDirectories(Paths.get(".", CLASSES_DIR)); String jrtJar = Paths.get(TEST_JAVAHOME, JRTFS_JAR).toAbsolutePath().toString(); @@ -121,4 +120,3 @@ public class RemoteRuntimeImageTest { return version.startsWith("\"1.8"); } } - diff --git a/jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java b/jdk/test/jdk/internal/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java similarity index 100% rename from jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java rename to jdk/test/jdk/internal/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java diff --git a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java similarity index 94% rename from jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java rename to jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java index d4805fb1d2d..2be9c57a649 100644 --- a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -47,7 +47,7 @@ import java.util.stream.Stream; * @test * @bug 8010117 * @summary Verify if CallerSensitive methods are annotated with - * sun.reflect.CallerSensitive annotation + * CallerSensitive annotation * @modules jdk.jdeps/com.sun.tools.classfile jdk.jdeps/com.sun.tools.jdeps * @build CallerSensitiveFinder * @run main/othervm/timeout=900 CallerSensitiveFinder @@ -97,7 +97,7 @@ public class CallerSensitiveFinder { } private ReferenceFinder.Filter getFilter() { - final String classname = "sun/reflect/Reflection"; + final String classname = "jdk/internal/reflect/Reflection"; final String method = "getCallerClass"; return new ReferenceFinder.Filter() { public boolean accept(ConstantPool cpool, CPRefInfo cpref) { @@ -115,6 +115,12 @@ public class CallerSensitiveFinder { return new ReferenceFinder.Visitor() { public void visit(ClassFile cf, Method m, List refs) { try { + // ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass + // which is a "special" delegate to the internal getCallerClass + if (cf.getName().equals("sun/reflect/Reflection") && + m.getName(cf.constant_pool).equals("getCallerClass")) + return; + String name = String.format("%s#%s %s", cf.getName(), m.getName(cf.constant_pool), m.descriptor.getValue(cf.constant_pool)); @@ -160,7 +166,7 @@ public class CallerSensitiveFinder { } } - private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;"; + private static final String CALLER_SENSITIVE_ANNOTATION = "Ljdk/internal/reflect/CallerSensitive;"; private static boolean isCallerSensitive(Method m, ConstantPool cp) throws ConstantPoolException { diff --git a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java b/jdk/test/jdk/internal/reflect/CallerSensitive/MissingCallerSensitive.java similarity index 90% rename from jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java rename to jdk/test/jdk/internal/reflect/CallerSensitive/MissingCallerSensitive.java index fb2b6c20a7b..b9d4706fe40 100644 --- a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/MissingCallerSensitive.java @@ -26,7 +26,7 @@ * @test * @bug 8010117 * @summary Test CallerSensitiveFinder to find missing annotation - * @modules java.base/sun.reflect + * @modules java.base/jdk.internal.reflect * jdk.jdeps/com.sun.tools.classfile * jdk.jdeps/com.sun.tools.jdeps * @compile -XDignore.symbol.file MissingCallerSensitive.java @@ -38,6 +38,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Stream; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; public class MissingCallerSensitive { public static void main(String[] args) throws Exception { @@ -56,14 +58,14 @@ public class MissingCallerSensitive { } } - @sun.reflect.CallerSensitive + @CallerSensitive public ClassLoader getCallerLoader() { - Class c = sun.reflect.Reflection.getCallerClass(); + Class c = Reflection.getCallerClass(); return c.getClassLoader(); } public ClassLoader missingCallerSensitiveAnnotation() { - Class c = sun.reflect.Reflection.getCallerClass(); + Class c = Reflection.getCallerClass(); return c.getClassLoader(); } } diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClass.java b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClass.java similarity index 87% rename from jdk/test/sun/reflect/Reflection/GetCallerClass.java rename to jdk/test/jdk/internal/reflect/Reflection/GetCallerClass.java index 8c822a5f517..163a80ad088 100644 --- a/jdk/test/sun/reflect/Reflection/GetCallerClass.java +++ b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClass.java @@ -24,14 +24,14 @@ package boot; public class GetCallerClass { - @sun.reflect.CallerSensitive + @jdk.internal.reflect.CallerSensitive public ClassLoader getCallerLoader() { - Class c = sun.reflect.Reflection.getCallerClass(); + Class c = jdk.internal.reflect.Reflection.getCallerClass(); return c.getClassLoader(); } public ClassLoader missingCallerSensitiveAnnotation() { - Class c = sun.reflect.Reflection.getCallerClass(); + Class c = jdk.internal.reflect.Reflection.getCallerClass(); return c.getClassLoader(); } } diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.java similarity index 96% rename from jdk/test/sun/reflect/Reflection/GetCallerClassTest.java rename to jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.java index 3e96f4b0a70..059da32a9c1 100644 --- a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java +++ b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.java @@ -23,8 +23,8 @@ import boot.GetCallerClass; import java.lang.reflect.*; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; public class GetCallerClassTest { private final GetCallerClass gcc; // boot.GetCallerClass is in bootclasspath @@ -104,7 +104,7 @@ public class GetCallerClassTest { throw new RuntimeException("Unexpected error: " + e.getMessage(), e); } - if (!stackTrace[0].getClassName().equals("sun.reflect.Reflection") || + if (!stackTrace[0].getClassName().equals("jdk.internal.reflect.Reflection") || !stackTrace[0].getMethodName().equals("getCallerClass")) { throw new RuntimeException("Unexpected error: " + e.getMessage(), e); } diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.sh similarity index 90% rename from jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh rename to jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.sh index b6d0ddad6f6..e2aa6f9f8d9 100644 --- a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh +++ b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassTest.sh @@ -23,8 +23,8 @@ # @test # @bug 8010117 -# @summary Test if the VM enforces sun.reflect.Reflection.getCallerClass -# be called by methods annotated with sun.reflect.CallerSensitive +# @summary Test if the VM enforces Reflection.getCallerClass +# be called by methods annotated with CallerSensitive # # @run shell GetCallerClassTest.sh @@ -55,7 +55,7 @@ BCP=${TESTCLASSES}/bcp rm -rf ${BCP} mkdir ${BCP} -EXTRAOPTS="-XaddExports:java.base/sun.reflect=ALL-UNNAMED" +EXTRAOPTS="-XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED" # Compile GetCallerClass in bootclasspath ${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} ${EXTRAOPTS} \ diff --git a/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassWithDepth.java b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassWithDepth.java new file mode 100644 index 00000000000..c220db3f432 --- /dev/null +++ b/jdk/test/jdk/internal/reflect/Reflection/GetCallerClassWithDepth.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8025799 + * @summary Reflection.getCallerClass(int) + * @modules java.base/jdk.internal.reflect + * @run main GetCallerClassWithDepth + */ + +import jdk.internal.reflect.Reflection; + +public class GetCallerClassWithDepth { + public static void main(String[] args) throws Exception { + Class c = Test.test(); + assertEquals(c, GetCallerClassWithDepth.class); + Class caller = Test.caller(); + assertEquals(caller, GetCallerClassWithDepth.class); + Test.selfTest(); + + try { + Reflection.getCallerClass(-1); + throw new RuntimeException("getCallerClass(-1) should fail"); + } catch (Error e) { + System.out.println("Expected: " + e.getMessage()); + } + } + + public Class getCallerClass() { + // 0: Reflection 1: getCallerClass 2: Test.test 3: main + return Reflection.getCallerClass(3); + } + + static void assertEquals(Class c, Class expected) { + if (c != expected) { + throw new RuntimeException("Incorrect caller: " + c); + } + } + + static class Test { + // Returns the caller of this method + public static Class test() { + return new GetCallerClassWithDepth().getCallerClass(); + } + + // Returns the caller of this method + public static Class caller() { + // 0: Reflection 1: Test.caller 2: main + return Reflection.getCallerClass(2); + } + public static void selfTest() { + // 0: Reflection 1: Test.selfTest + Class c = Reflection.getCallerClass(1); + assertEquals(c, Test.class); + Inner1.deep(); + } + + static class Inner1 { + static void deep() { + deeper(); + } + static void deeper() { + Inner2.deepest(); + } + static class Inner2 { + static void deepest() { + // 0: Reflection 1: deepest 2: deeper 3: deep 4: Test.selfTest + Class c = Reflection.getCallerClass(4); + assertEquals(c, Test.class); + } + } + } + } +} diff --git a/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java b/jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTest.java similarity index 96% rename from jdk/test/sun/reflect/constantPool/ConstantPoolTest.java rename to jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTest.java index fab27c6fe91..1ab4573ea00 100644 --- a/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java +++ b/jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTest.java @@ -24,21 +24,21 @@ /* * @test * @bug 8141615 - * @summary Tests new public methods at sun.reflect.ConstantPool + * @summary Tests new public methods at ConstantPool * @modules java.base/jdk.internal.misc - * java.base/sun.reflect + * java.base/jdk.internal.reflect * @library /lib/testlibrary * @compile ConstantPoolTestDummy.jasm - * @run main sun.reflect.constantPool.ConstantPoolTest + * @run main jdk.internal.reflect.constantPool.ConstantPoolTest */ -package sun.reflect.constantPool; +package jdk.internal.reflect.constantPool; import java.util.HashMap; import java.util.Map; import jdk.internal.misc.SharedSecrets; import jdk.testlibrary.Asserts; -import sun.reflect.ConstantPool; +import jdk.internal.reflect.ConstantPool; public class ConstantPoolTest { diff --git a/jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm b/jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm similarity index 95% rename from jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm rename to jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm index cb3daaff8c9..3884f1644ff 100644 --- a/jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm +++ b/jdk/test/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm @@ -21,7 +21,7 @@ * questions. */ -package sun/reflect/constantPool; +package jdk/internal/reflect/constantPool; super public #2; //class ConstantPoolTestDummy version 52:0 @@ -41,7 +41,7 @@ const #7 = Asciz "LineNumberTable"; const #8 = Asciz "SourceFile"; const #9 = Asciz "ConstantPoolTestDummy.java"; const #10 = NameAndType #4:#5; // "":"()V" -const #11 = Asciz "sun/reflect/constantPool/ConstantPoolTestDummy"; +const #11 = Asciz "jdk/internal/reflect/constantPool/ConstantPoolTestDummy"; const #12 = Asciz "java/lang/Object"; const #13 = long 6l; const #15 = int 1; @@ -76,7 +76,7 @@ const #44 = Asciz "Lookup"; const #45 = class #47; // java/lang/invoke/MethodHandles const #46 = Asciz "java/lang/invoke/MethodHandles$Lookup"; const #47 = Asciz "java/lang/invoke/MethodHandles"; -const #48 = Field #2.#49; // sun/reflect/constantPool/ConstantPoolTestDummy.myField:"I" +const #48 = Field #2.#49; // jdk/internal/reflect/constantPool/ConstantPoolTestDummy.myField:"I" const #49 = NameAndType #50:#51; // myField:"I" const #50 = Asciz "myField"; const #51 = Asciz "I"; diff --git a/jdk/test/sanity/client/lib/SwingSet3/README b/jdk/test/sanity/client/lib/SwingSet3/README index 1952a70cd26..cf0406460ef 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/README +++ b/jdk/test/sanity/client/lib/SwingSet3/README @@ -1,4 +1,4 @@ This content of this src folder was originally taken from SwingSet3 demo project: https://java.net/projects/swingset3/. Then it was modified to increase testability and remove extra content and extra dependencies. -Do NOT modify files in it. \ No newline at end of file +This is NOT the official location of the SwingSet3 demo. \ No newline at end of file diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java index 728e0543b68..e3aa888e5f3 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/ButtonDemo.java @@ -215,7 +215,6 @@ public final class ButtonDemo extends JPanel { javax.swing.SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(buttonDemo); frame.pack(); frame.setVisible(true); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java index 5fc080f95bb..f204e64437d 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/combobox/ComboBoxDemo.java @@ -120,7 +120,6 @@ public class ComboBoxDemo extends JPanel implements ActionListener { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ComboBoxDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java index b8dce72ba9e..02b55129f60 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/list/ListDemo.java @@ -90,7 +90,6 @@ public final class ListDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ListDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java index 0e8c1e46a13..ca04135c2a1 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/optionpane/OptionPaneDemo.java @@ -93,7 +93,6 @@ public class OptionPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new OptionPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java index e49b47926ea..5e9d38bd7a3 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/progressbar/ProgressBarDemo.java @@ -64,7 +64,6 @@ public class ProgressBarDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ProgressBarDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java index 5a492ea53fd..40fb29cfaa6 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/scrollpane/ScrollPaneDemo.java @@ -64,7 +64,6 @@ public class ScrollPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ScrollPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java index 0694a843341..97dbd2d5002 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/SpinnerDemo.java @@ -58,7 +58,6 @@ public class SpinnerDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new SpinnerDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java index 0bc0cd78f0f..64bc9b2ccaf 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/splitpane/SplitPaneDemo.java @@ -86,7 +86,6 @@ public class SplitPaneDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new SplitPaneDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java index be7c9a7e7d0..16537bfccf5 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/textfield/TextFieldDemo.java @@ -115,7 +115,6 @@ public class TextFieldDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new TextFieldDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java index 5adf5f7a62b..625c9fe1fda 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/togglebutton/ToggleButtonDemo.java @@ -151,7 +151,6 @@ public class ToggleButtonDemo extends JPanel implements ChangeListener { public static void main(String[] args) { JFrame frame = new JFrame(ToggleButtonDemo.class.getAnnotation(DemoProperties.class).value()); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ToggleButtonDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java index 1a4c555945e..e6f8e326571 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tree/TreeDemo.java @@ -65,7 +65,6 @@ public class TreeDemo extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(DEMO_TITLE); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new TreeDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); diff --git a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java index cf83135d1e8..89b87776ba2 100644 --- a/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java +++ b/jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java @@ -150,7 +150,6 @@ public final class WindowDemo extends JPanel { JFrame frame = new JFrame(); WindowDemo demo = new WindowDemo(); frame.add(demo); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); demo.start(); diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassWithDepth.java b/jdk/test/sun/reflect/Reflection/GetCallerClassWithDepth.java index 8e7c9cc9d13..1b2650d8543 100644 --- a/jdk/test/sun/reflect/Reflection/GetCallerClassWithDepth.java +++ b/jdk/test/sun/reflect/Reflection/GetCallerClassWithDepth.java @@ -23,12 +23,13 @@ /* * @test - * @bug 8025799 - * @summary sun.reflect.Reflection.getCallerClass(int) - * @modules java.base/sun.reflect - * @run main GetCallerClassWithDepth + * @bug 8137058 + * @summary Basic test for the unsupported Reflection.getCallerClass(int) + * @modules jdk.unsupported */ +import sun.reflect.Reflection; + public class GetCallerClassWithDepth { public static void main(String[] args) throws Exception { Class c = Test.test(); @@ -38,7 +39,7 @@ public class GetCallerClassWithDepth { Test.selfTest(); try { - sun.reflect.Reflection.getCallerClass(-1); + Reflection.getCallerClass(-1); throw new RuntimeException("getCallerClass(-1) should fail"); } catch (Error e) { System.out.println("Expected: " + e.getMessage()); @@ -47,7 +48,7 @@ public class GetCallerClassWithDepth { public Class getCallerClass() { // 0: Reflection 1: getCallerClass 2: Test.test 3: main - return sun.reflect.Reflection.getCallerClass(3); + return Reflection.getCallerClass(3); } static void assertEquals(Class c, Class expected) { @@ -65,11 +66,11 @@ public class GetCallerClassWithDepth { // Returns the caller of this method public static Class caller() { // 0: Reflection 1: Test.caller 2: main - return sun.reflect.Reflection.getCallerClass(2); + return Reflection.getCallerClass(2); } public static void selfTest() { // 0: Reflection 1: Test.selfTest - Class c = sun.reflect.Reflection.getCallerClass(1); + Class c = Reflection.getCallerClass(1); assertEquals(c, Test.class); Inner1.deep(); } @@ -84,7 +85,7 @@ public class GetCallerClassWithDepth { static class Inner2 { static void deepest() { // 0: Reflection 1: deepest 2: deeper 3: deep 4: Test.selfTest - Class c = sun.reflect.Reflection.getCallerClass(4); + Class c = Reflection.getCallerClass(4); assertEquals(c, Test.class); } } diff --git a/jdk/test/sun/reflect/ReflectionFactory/NewConstructorForSerialization.java b/jdk/test/sun/reflect/ReflectionFactory/NewConstructorForSerialization.java new file mode 100644 index 00000000000..377cf10d6e1 --- /dev/null +++ b/jdk/test/sun/reflect/ReflectionFactory/NewConstructorForSerialization.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8137058 + * @summary Basic test for the unsupported newConstructorForSerialization + * @modules jdk.unsupported + */ + +import java.lang.reflect.Constructor; +import sun.reflect.ReflectionFactory; + +public class NewConstructorForSerialization { + + private static Constructor getConstructor(Class type) + throws NoSuchMethodException + { + ReflectionFactory factory = ReflectionFactory.getReflectionFactory(); + Constructor objectConstructor = type.getConstructor((Class[]) null); + + @SuppressWarnings("unchecked") + Constructor c = (Constructor) factory + .newConstructorForSerialization(type, objectConstructor); + return c; + } + + public static void main(String[] args) throws Exception { + System.out.println(getConstructor(Object.class).newInstance()); + System.out.println(getConstructor(Foo.class).newInstance()); + System.out.println(getConstructor(Bar.class).newInstance()); + } + + static class Foo { + public Foo() { } + } + + static class Bar extends Foo { + public Bar() { } + } +} diff --git a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java index 0013bd86e03..38d37966f23 100644 --- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java +++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,18 @@ * questions. */ + /* + * @test + * @bug 8023546 8151834 + * @modules java.base/sun.security.x509 + * java.base/sun.security.tools.keytool + * @summary Test prime exponent (p) lengths 63 and 65 bytes with SunMSCAPI. + * The seed 76 has the fastest test execution now (only 5 rounds) and is + * hard-coded in run tag. This number might change if algorithms for + * RSA key pair generation or BigInteger prime searching gets updated. + * @requires os.family == "windows" + * @run main SmallPrimeExponentP 76 + */ import sun.security.tools.keytool.CertAndKeyGen; import sun.security.x509.X500Name; @@ -28,50 +40,63 @@ import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateCrtKey; +import java.util.Random; -/* - * @test - * @bug 8023546 - * @key intermittent - * @modules java.base/sun.security.x509 - * java.base/sun.security.tools.keytool - * @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently - * @requires os.family == "windows" - */ public class SmallPrimeExponentP { public static void main(String argv[]) throws Exception { - String osName = System.getProperty("os.name"); - if (!osName.startsWith("Windows")) { - System.out.println("Not windows"); - return; - } + long seed = Long.parseLong(argv[0]); + System.out.println("Seed for SecureRandom = " + seed + "L"); + KeyStore ks = KeyStore.getInstance("Windows-MY"); ks.load(null, null); + CertAndKeyGen ckg = new CertAndKeyGen("RSA", "SHA1withRSA"); - ckg.setRandom(new SecureRandom()); - boolean see63 = false, see65 = false; + ckg.setRandom(new MySecureRandom(seed)); + + boolean see63 = false; + boolean see65 = false; while (!see63 || !see65) { ckg.generate(1024); RSAPrivateCrtKey k = (RSAPrivateCrtKey) ckg.getPrivateKey(); + int len = k.getPrimeExponentP().toByteArray().length; + System.out.println("Length of P = " + len); if (len == 63 || len == 65) { if (len == 63) { - if (see63) continue; - else see63 = true; + if (see63) { + continue; + } else { + see63 = true; + } } if (len == 65) { - if (see65) continue; - else see65 = true; + if (see65) { + continue; + } else { + see65 = true; + } } - System.err.print(len); ks.setKeyEntry("anything", k, null, new X509Certificate[]{ - ckg.getSelfCertificate(new X500Name("CN=Me"), 1000) + ckg.getSelfCertificate(new X500Name("CN=Me"), 1000) }); } - System.err.print('.'); } ks.store(null, null); } + + static class MySecureRandom extends SecureRandom { + + final Random random; + + public MySecureRandom(long seed) { + random = new Random(seed); + } + + @Override + public void nextBytes(byte[] bytes) { + random.nextBytes(bytes); + } + } } diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java b/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java new file mode 100644 index 00000000000..b70129e0042 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + * @library .. + * @run main/othervm SupportedDHKeys + * @run main/othervm SupportedDHKeys sm + */ + +import java.math.BigInteger; + +import java.security.*; +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +public class SupportedDHKeys extends PKCS11Test { + + /* + * Sizes and values for various lengths. + */ + private enum SupportedKeySize { + dhp512(512), dhp768(768), dhp832(832), + dhp1024(1024), dhp1536(1536), dhp2048(2048); + + // the underlying pkcs11 may not support the following sizes yet + // + // dhp3072(3072), dhp4096(4096), dhp6144(6144), + // dhp8192(8192); + + final int primeSize; + + SupportedKeySize(int primeSize) { + this.primeSize = primeSize; + } + } + + @Override + public void main(Provider provider) throws Exception { + if (provider.getService("KeyPairGenerator", "DiffieHellman") == null) { + System.out.println("No support of DH KeyPairGenerator, skipping"); + return; + } + + for (SupportedKeySize keySize : SupportedKeySize.values()) { + System.out.println("Checking " + keySize.primeSize + " ..."); + KeyPairGenerator kpg = + KeyPairGenerator.getInstance("DiffieHellman", provider); + kpg.initialize(keySize.primeSize); + KeyPair kp = kpg.generateKeyPair(); + checkKeyPair(kp, keySize.primeSize); + + DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); + BigInteger p = publicKey.getParams().getP(); + BigInteger g = publicKey.getParams().getG(); + kpg.initialize(new DHParameterSpec(p, g)); + kp = kpg.generateKeyPair(); + checkKeyPair(kp, keySize.primeSize); + } + } + + private static void checkKeyPair(KeyPair kp, int pSize) throws Exception { + + DHPrivateKey privateKey = (DHPrivateKey)kp.getPrivate(); + BigInteger p = privateKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + // System.out.println("P(" + pSize + "): " + p.toString()); + if (!p.isProbablePrime(128)) { + throw new Exception("Good luck, the modulus is composite!"); + } + + DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); + p = publicKey.getParams().getP(); + if (p.bitLength() != pSize) { + throw new Exception( + "Invalid modulus size: " + p.bitLength() + "/" + pSize); + } + + BigInteger leftOpen = BigInteger.ONE; + BigInteger rightOpen = p.subtract(BigInteger.ONE); + + BigInteger x = privateKey.getX(); + if ((x.compareTo(leftOpen) <= 0) || + (x.compareTo(rightOpen) >= 0)) { + throw new Exception( + "X outside range [2, p - 2]: x: " + x + " p: " + p); + } + + BigInteger y = publicKey.getY(); + if ((y.compareTo(leftOpen) <= 0) || + (y.compareTo(rightOpen) >= 0)) { + throw new Exception( + "Y outside range [2, p - 2]: x: " + x + " p: " + p); + } + } + + public static void main(String[] args) throws Exception { + main(new SupportedDHKeys(), args); + } +} diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java b/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java new file mode 100644 index 00000000000..0725171cb53 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + * @library .. + * @run main/othervm UnsupportedDHKeys + * @run main/othervm UnsupportedDHKeys sm + */ + +import java.math.BigInteger; + +import java.security.*; +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +public class UnsupportedDHKeys extends PKCS11Test { + + /* + * Sizes and values for various lengths. + */ + private enum UnsupportedKeySize { + // not multiple of 64 + dhp513(513), dhp769(769), dhp895(895), + dhp1023(1023), dhp1535(1535), dhp2047(2047), + + // unsupported + dhp2176(2176), dhp3008(3008), dhp4032(4032), + dhp5120(5120), dhp6400(6400), dhp7680(7680), + dhp8191(8191), dhp8128(8128), dhp8260(8260); + + final int primeSize; + + UnsupportedKeySize(int primeSize) { + this.primeSize = primeSize; + } + } + + @Override + public void main(Provider provider) throws Exception { + if (provider.getService("KeyPairGenerator", "DiffieHellman") == null) { + System.out.println("No supported of DH KeyPairGenerator, skipping"); + return; + } + + for (UnsupportedKeySize keySize : UnsupportedKeySize.values()) { + try { + System.out.println("Checking " + keySize.primeSize + " ..."); + KeyPairGenerator kpg = + KeyPairGenerator.getInstance("DiffieHellman", provider); + kpg.initialize(keySize.primeSize); + + throw new Exception("Should not support " + keySize.primeSize); + } catch (InvalidParameterException ipe) { + System.out.println("\tOk, unsupported"); + } + } + } + + public static void main(String[] args) throws Exception { + main(new UnsupportedDHKeys(), args); + } +} diff --git a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java index 840e1ce3dcf..4655678c31e 100644 --- a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java +++ b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java @@ -23,8 +23,8 @@ /** * @test - * @bug 7196382 - * @summary Ensure that 2048-bit DH key pairs can be generated + * @bug 7196382 8072452 + * @summary Ensure that DH key pairs can be generated for 512 - 8192 bits * @author Valerie Peng * @library .. * @run main/othervm TestDH2048 @@ -54,11 +54,45 @@ public class TestDH2048 extends PKCS11Test { return; } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); - kpg.initialize(2048); + kpg.initialize(512); KeyPair kp1 = kpg.generateKeyPair(); - checkUnsupportedKeySize(kpg, 1536); - checkUnsupportedKeySize(kpg, 2176); - checkUnsupportedKeySize(kpg, 3072); + + kpg.initialize(768); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(1024); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(1536); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(2048); + kp1 = kpg.generateKeyPair(); + + try { + kpg.initialize(3072); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(4096); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(6144); + kp1 = kpg.generateKeyPair(); + + kpg.initialize(8192); + kp1 = kpg.generateKeyPair(); + } catch (InvalidParameterException ipe) { + // NSS (as of version 3.13) has a hard coded maximum limit + // of 2236 or 3072 bits for DHE keys. + System.out.println("4096-bit DH key pair generation: " + ipe); + if (!p.getName().equals("SunPKCS11-NSS")) { + throw ipe; + } + } + + // key size must be multiples of 64 though + checkUnsupportedKeySize(kpg, 2048 + 63); + checkUnsupportedKeySize(kpg, 3072 + 32); } public static void main(String[] args) throws Exception { diff --git a/jdk/test/sun/security/provider/DSA/SupportedDSAParamGen.java b/jdk/test/sun/security/provider/DSA/SupportedDSAParamGen.java new file mode 100644 index 00000000000..1a10b4ce272 --- /dev/null +++ b/jdk/test/sun/security/provider/DSA/SupportedDSAParamGen.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8072452 + * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits + * @run main/timeout=300 SupportedDSAParamGen 1024 160 + * @run main/timeout=300 SupportedDSAParamGen 2048 224 + * @run main/timeout=300 SupportedDSAParamGen 2048 256 + * @run main/timeout=450 SupportedDSAParamGen 3072 256 + */ +import java.security.*; +import java.security.spec.*; +import java.security.interfaces.*; + +public class SupportedDSAParamGen { + + public static void main(String[] args) throws Exception { + AlgorithmParameterGenerator apg = + AlgorithmParameterGenerator.getInstance("DSA", "SUN"); + + DSAGenParameterSpec spec = new DSAGenParameterSpec( + Integer.valueOf(args[0]).intValue(), + Integer.valueOf(args[1]).intValue()); + + System.out.println("Generating (" + spec.getPrimePLength() + + ", " + spec.getSubprimeQLength() + ") DSA Parameters"); + long start = System.currentTimeMillis(); + apg.init(spec, null); + AlgorithmParameters param = apg.generateParameters(); + long stop = System.currentTimeMillis(); + System.out.println("Time: " + (stop - start) + " ms."); + checkParamStrength(param, spec); + } + + private static void checkParamStrength(AlgorithmParameters param, + DSAGenParameterSpec genParam) throws Exception { + + String algo = param.getAlgorithm(); + if (!algo.equalsIgnoreCase("DSA")) { + throw new Exception("Unexpected type of parameters: " + algo); + } + + DSAParameterSpec spec = param.getParameterSpec(DSAParameterSpec.class); + int valueL = spec.getP().bitLength(); + int strength = genParam.getPrimePLength(); + if (strength != valueL) { + System.out.println( + "P: Expected " + strength + " but actual " + valueL); + throw new Exception("Wrong P strength"); + } + + int valueN = spec.getQ().bitLength(); + strength = genParam.getSubprimeQLength(); + if (strength != valueN) { + System.out.println( + "Q: Expected " + strength + " but actual " + valueN); + throw new Exception("Wrong Q strength"); + } + } +} diff --git a/jdk/test/sun/security/provider/DSA/TestDSA2.java b/jdk/test/sun/security/provider/DSA/TestDSA2.java index 00691535ac1..320acce4880 100644 --- a/jdk/test/sun/security/provider/DSA/TestDSA2.java +++ b/jdk/test/sun/security/provider/DSA/TestDSA2.java @@ -60,8 +60,8 @@ public class TestDSA2 { boolean[] expectedToPass = { true, true, true, true, true, true, true, true }; test(1024, expectedToPass); - boolean[] expectedToPass2 = { true, true, true, true, - true, true, true, true }; + boolean[] expectedToPass2 = { true, false, true, true, + true, false, true, true }; test(2048, expectedToPass2); } diff --git a/jdk/test/sun/security/provider/DSA/TestKeyPairGenerator.java b/jdk/test/sun/security/provider/DSA/TestKeyPairGenerator.java index 10483d5e66c..bfd47b23adf 100644 --- a/jdk/test/sun/security/provider/DSA/TestKeyPairGenerator.java +++ b/jdk/test/sun/security/provider/DSA/TestKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,18 @@ /* * @test - * @bug 4800108 - * @summary verify that precomputed DSA parameters are always used (512, 768, 1024, 2048 bit) + * @bug 4800108 8072452 + * @summary verify that precomputed DSA parameters are always used (512, 768, + * 1024, 2048, 3072 bit) * @run main/othervm/timeout=15 TestKeyPairGenerator */ -// this fix is really a performance fix, so this test is not foolproof -// without it, it will take a minute or more (unless you have a very fast machine) -// with the fix, the test should complete in <2 seconds -// use 15 second timeout to leave some room +// +// This fix is really a performance fix, so this test is not foolproof. +// Without the precomputed parameters, it will take a minute or more +// (unless you have a very fast machine). With the fix, the test should +// complete in less than 2 seconds. Use 15 second timeout to leave some room. +// import java.security.*; import java.security.interfaces.*; @@ -82,8 +85,11 @@ public class TestKeyPairGenerator { kp = kpg.generateKeyPair(); checkKeyLength(kp, 2048); + kpg.initialize(3072); + kp = kpg.generateKeyPair(); + checkKeyLength(kp, 3072); + long stop = System.currentTimeMillis(); System.out.println("Time: " + (stop - start) + " ms."); } - } diff --git a/jdk/test/sun/security/rsa/SpecTest.java b/jdk/test/sun/security/rsa/SpecTest.java index c13f1d91989..24cddfe3591 100644 --- a/jdk/test/sun/security/rsa/SpecTest.java +++ b/jdk/test/sun/security/rsa/SpecTest.java @@ -20,32 +20,32 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @bug 8044199 8137231 + * @key intermittent + * @summary Check same KeyPair's private key and public key have same modulus. + * also check public key's public exponent equals to given spec's public + * exponent. Only key size 1024 is tested with RSAKeyGenParameterSpec.F0 (3). + * @run main SpecTest 512 + * @run main SpecTest 768 + * @run main SpecTest 1024 + * @run main SpecTest 1024 3 + * @run main SpecTest 2048 + * @run main/timeout=240 SpecTest 4096 + * @run main/timeout=240 SpecTest 5120 + */ import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.security.interfaces.RSAKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.RSAKeyGenParameterSpec; -/** - * @test - * @bug 8044199 - * @key intermittent - * @summary Check same KeyPair's private key and public key have same modulus. - * also check public key's public exponent equals to given spec's public - * exponent. - * @run main SpecTest 512 - * @run main SpecTest 768 - * @run main SpecTest 1024 - * @run main SpecTest 2048 - * @run main/timeout=240 SpecTest 4096 - * @run main/timeout=240 SpecTest 5120 - */ public class SpecTest { + /** * ALGORITHM name, fixed as RSA. */ @@ -70,14 +70,14 @@ public class SpecTest { // test the getModulus method if ((priv instanceof RSAKey) && (pub instanceof RSAKey)) { if (!priv.getModulus().equals(pub.getModulus())) { - System.err.println("priv.getModulus() = " + priv.getModulus()); - System.err.println("pub.getModulus() = " + pub.getModulus()); + System.out.println("priv.getModulus() = " + priv.getModulus()); + System.out.println("pub.getModulus() = " + pub.getModulus()); passed = false; } if (!pubExponent.equals(pub.getPublicExponent())) { - System.err.println("pubExponent = " + pubExponent); - System.err.println("pub.getPublicExponent() = " + System.out.println("pubExponent = " + pubExponent); + System.out.println("pub.getPublicExponent() = " + pub.getPublicExponent()); passed = false; } @@ -85,36 +85,26 @@ public class SpecTest { return passed; } - public static void main(String[] args) { - int failCount = 0; + public static void main(String[] args) throws Exception { - // Test key size. - int size = Integer.parseInt(args[0]); + int size = 0; - try { - KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); - kpg1.initialize(new RSAKeyGenParameterSpec(size, - RSAKeyGenParameterSpec.F4)); - if (!specTest(kpg1.generateKeyPair(), - RSAKeyGenParameterSpec.F4)) { - failCount++; - } - - KeyPairGenerator kpg2 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); - kpg2.initialize(new RSAKeyGenParameterSpec(size, - RSAKeyGenParameterSpec.F0)); - if (!specTest(kpg2.generateKeyPair(), RSAKeyGenParameterSpec.F0)) { - failCount++; - } - } catch (NoSuchAlgorithmException | NoSuchProviderException - | InvalidAlgorithmParameterException ex) { - ex.printStackTrace(System.err); - failCount++; + if (args.length >= 1) { + size = Integer.parseInt(args[0]); + } else { + throw new RuntimeException("Missing keysize to test with"); } - if (failCount != 0) { - throw new RuntimeException("There are " + failCount - + " tests failed."); + BigInteger publicExponent + = (args.length >= 2) ? new BigInteger(args[1]) : RSAKeyGenParameterSpec.F4; + + System.out.println("Running test with key size: " + size + + " and public exponent: " + publicExponent); + + KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(KEYALG, PROVIDER); + kpg1.initialize(new RSAKeyGenParameterSpec(size, publicExponent)); + if (!specTest(kpg1.generateKeyPair(), publicExponent)) { + throw new RuntimeException("Test failed."); } } } diff --git a/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java b/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java index 9d8ee1d5287..f2e06337dd3 100644 --- a/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java +++ b/jdk/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,106 +37,88 @@ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2 * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2 */ - -import java.net.*; -import java.util.*; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; import javax.net.ssl.*; import java.security.Security; import java.security.KeyStore; import java.security.KeyFactory; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; +import java.util.concurrent.CountDownLatch; public class MD2InTrustAnchor { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = false; - /* * Certificates and key used in the test. */ - // It's a trust anchor signed with MD2 hash function. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + - "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + - "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + - "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + - "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + - "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + - "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + - "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + - "-----END CERTIFICATE-----"; + private static final String TRUSTED_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + + "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + + "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + + "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + + "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + + "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + + "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + + "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + + "-----END CERTIFICATE-----"; // The certificate issued by above trust anchor, signed with MD5 - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + - "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + - "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + - "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + - "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + - "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + - "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + - "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + - "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + - "yvudOlX4BkVR0l1K\n" + - "-----END CERTIFICATE-----"; + private static final String TARGET_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + + "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + + "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + + "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + + "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + + "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + + "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + + "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + + "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + + "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + + "yvudOlX4BkVR0l1K\n" + + "-----END CERTIFICATE-----"; // Private key in the format of PKCS#8. - static String targetPrivateKey = - "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + - "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + - "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + - "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + - "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + - "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + - "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + - "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + - "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + - "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + - "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + - "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + - "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + - "njWHoKY3axDQ8OU=\n"; + private static final String TARGET_PRIV_KEY_STR = "MIICdwIBADANBgkqhkiG9w0B\n" + + "AQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4F5NVEtFXCbEFcVLRjMp3AL3j\n" + + "LswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa9+uHt0Z9Wmh4wjHAZhX5Tm5x\n" + + "p4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPMKBpyzK6rusorkwpWywTyvH1s\n" + + "016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+KSH9tFt+WQbiojjz9ac49trkv\n" + + "Ufu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck5mOIYV4uZK8jfNMSQ8v0tFEe\n" + + "IPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+HaY3d76hR5qly+Ys+Ww0CQQDj\n" + + "eOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ6t0v/xryVIdvOYcRBvKnqEog\n" + + "OH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7ez3TDpU9w1B0JXklcV5HddYsR\n" + + "qp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3ML11xwwJBAKsZ+Hur3x0tUY29\n" + + "No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDElhIM6Rqv12kwCMuQE9i7vo1o3\n" + + "WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXsekdXAA4d2d5zGI7q/aGD9SYU6\n" + + "phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRTA5kokFb+E3Gplu29tJvCUpfw\n" + + "gBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiEnjWHoKY3axDQ8OU="; - - static char passphrase[] = "passphrase".toCharArray(); + private static final char PASSPHRASE[] = "passphrase".toCharArray(); /* * Is the server ready to serve? */ - volatile static boolean serverReady = false; + private static volatile CountDownLatch sync = new CountDownLatch(1); /* * Turn on SSL debugging? */ - static boolean debug = false; + private static final boolean DEBUG = false; /* * Define the server side of the test. @@ -144,29 +126,30 @@ public class MD2InTrustAnchor { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doServerSide() throws Exception { - SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, - targetPrivateKey); + private void doServerSide() throws Exception { + SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR, + TARGET_PRIV_KEY_STR); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); - SSLServerSocket sslServerSocket = - (SSLServerSocket)sslssf.createServerSocket(serverPort); - sslServerSocket.setNeedClientAuth(true); - serverPort = sslServerSocket.getLocalPort(); + try (SSLServerSocket sslServerSocket + = (SSLServerSocket) sslssf.createServerSocket(serverPort)) { + sslServerSocket.setNeedClientAuth(true); + serverPort = sslServerSocket.getLocalPort(); + /* + * Signal Client, we're ready for his connect. + */ + System.out.println("Signal server ready"); + sync.countDown(); - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; + System.out.println("Waiting for client connection"); + try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslIS.read(); - sslOS.write('A'); - sslOS.flush(); - - sslSocket.close(); + sslIS.read(); + sslOS.write('A'); + sslOS.flush(); + } + } } /* @@ -175,33 +158,31 @@ public class MD2InTrustAnchor { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doClientSide() throws Exception { + private void doClientSide() throws Exception { /* * Wait for server to get started. */ - while (!serverReady) { - Thread.sleep(50); - } + System.out.println("Waiting for server ready"); + sync.await(); - SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, - targetPrivateKey); + SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR, + TARGET_PRIV_KEY_STR); SSLSocketFactory sslsf = context.getSocketFactory(); - SSLSocket sslSocket = - (SSLSocket)sslsf.createSocket("localhost", serverPort); + System.out.println("Connect to server on port: " + serverPort); + try (SSLSocket sslSocket + = (SSLSocket) sslsf.createSocket("localhost", serverPort)) { + // enable the specified TLS protocol + sslSocket.setEnabledProtocols(new String[]{tlsProtocol}); - // enable the specified TLS protocol - sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslOS.write('B'); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); + sslOS.write('B'); + sslOS.flush(); + sslIS.read(); + } } /* @@ -240,10 +221,10 @@ public class MD2InTrustAnchor { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); + RSAPrivateKey priKey + = (RSAPrivateKey) kf.generatePrivate(priKeySpec); // generate certificate chain is = new ByteArrayInputStream(keyCertStr.getBytes()); @@ -257,7 +238,7 @@ public class MD2InTrustAnchor { chain[0] = keyCert; // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); + ks.setKeyEntry("Whatever", priKey, PASSPHRASE, chain); } // create SSL context @@ -267,7 +248,7 @@ public class MD2InTrustAnchor { SSLContext ctx = SSLContext.getInstance(tlsProtocol); if (keyCertStr != null && !keyCertStr.isEmpty()) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); + kmf.init(ks, PASSPHRASE); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ks = null; @@ -278,12 +259,10 @@ public class MD2InTrustAnchor { return ctx; } - // use any free port by default - volatile int serverPort = 0; + private volatile int serverPort = 0; - volatile Exception serverException = null; - volatile Exception clientException = null; + private volatile Exception serverException = null; public static void main(String[] args) throws Exception { // MD5 is used in this test case, don't disable MD5 algorithm. @@ -292,140 +271,61 @@ public class MD2InTrustAnchor { Security.setProperty("jdk.tls.disabledAlgorithms", "SSLv3, RC4, DH keySize < 768"); - if (debug) + if (DEBUG) { System.setProperty("javax.net.debug", "all"); + } /* * Get the customized arguments. */ parseArguments(args); - /* * Start the tests. */ - new MD2InTrustAnchor(); + new MD2InTrustAnchor().runTest(); } - Thread clientThread = null; - Thread serverThread = null; + private Thread serverThread = null; /* - * Primary constructor, used to drive remainder of the test. + * Used to drive remainder of the test. * * Fork off the other side, then do your work. */ - MD2InTrustAnchor() throws Exception { - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - // swallow for now. Show later - } + public void runTest() throws Exception { + startServerThread(); + doClientSide(); /* * Wait for other side to close down. */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } + serverThread.join(); - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - String whichRemote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - whichRemote = "server"; - } else { - remote = clientException; - local = serverException; - whichRemote = "client"; - } - - /* - * If both failed, return the curthread's exception, but also - * print the remote side Exception - */ - if ((local != null) && (remote != null)) { - System.out.println(whichRemote + " also threw:"); - remote.printStackTrace(); - System.out.println(); - throw local; - } - - if (remote != null) { - throw remote; - } - - if (local != null) { - throw local; + if (serverException != null) { + throw serverException; } } - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } + private void startServerThread() { + serverThread = new Thread() { + @Override + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + e.printStackTrace(System.out); + serverException = e; + sync.countDown(); } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; } - } - } + }; - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } + serverThread.start(); } } diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java index 4e516970d4d..915416c0802 100644 --- a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java @@ -29,6 +29,7 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Set; public class Main { @@ -40,7 +41,8 @@ public class Main { validate(Main.class.getModule().getDescriptor()); // read m1/module-info.class - FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), null); + FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), + Collections.emptyMap()); Path path = fs.getPath("/", "modules", "m1", "module-info.class"); validate(ModuleDescriptor.read(Files.newInputStream(path))); } diff --git a/jdk/test/tools/launcher/Arrrghs.java b/jdk/test/tools/launcher/Arrrghs.java index cb36d2dfe8a..9045e010473 100644 --- a/jdk/test/tools/launcher/Arrrghs.java +++ b/jdk/test/tools/launcher/Arrrghs.java @@ -489,7 +489,7 @@ public class Arrrghs extends TestHelper { return; } - TestResult tr = null; + TestResult tr; // a missing class createJar("MIA", new File("some.jar"), new File("Foo"), @@ -592,7 +592,7 @@ public class Arrrghs extends TestHelper { if (!isEnglishLocale()) { // only english version return; } - TestResult tr = null; + TestResult tr; // a missing class createJar("MIA", new File("some.jar"), new File("Foo"), (String[])null); diff --git a/jdk/test/tools/launcher/DefaultLocaleTestRun.java b/jdk/test/tools/launcher/DefaultLocaleTestRun.java index c1183e78814..2d4091912e2 100644 --- a/jdk/test/tools/launcher/DefaultLocaleTestRun.java +++ b/jdk/test/tools/launcher/DefaultLocaleTestRun.java @@ -41,7 +41,7 @@ public class DefaultLocaleTestRun extends TestHelper { System.out.println("Test passes vacuously on non-windows"); return; } - TestResult tr = null; + TestResult tr; tr = doExec(javaCmd, "-cp", TEST_CLASSES_DIR.getAbsolutePath(), "DefaultLocaleTest", "-w", "x.out"); diff --git a/jdk/test/tools/launcher/ExecutionEnvironment.java b/jdk/test/tools/launcher/ExecutionEnvironment.java index 58acf380b0e..62903b33ecb 100644 --- a/jdk/test/tools/launcher/ExecutionEnvironment.java +++ b/jdk/test/tools/launcher/ExecutionEnvironment.java @@ -120,15 +120,14 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testEcoFriendly() { - TestResult tr = null; - Map env = new HashMap<>(); for (String x : LD_PATH_STRINGS) { String pairs[] = x.split("="); env.put(pairs[0], pairs[1]); } - tr = doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath()); + TestResult tr = + doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath()); if (!tr.isNotZeroOutput()) { flagError(tr, "Error: No output at all. Did the test execute ?"); @@ -180,7 +179,7 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testJavaLibraryPath() { - TestResult tr = null; + TestResult tr; Map env = new HashMap<>(); @@ -240,17 +239,14 @@ public class ExecutionEnvironment extends TestHelper { */ @Test void testVmSelection() { - - TestResult tr = null; - if (haveClientVM) { - tr = doExec(javaCmd, "-client", "-version"); + TestResult tr = doExec(javaCmd, "-client", "-version"); if (!tr.matches(".*Client VM.*")) { flagError(tr, "the expected vm -client did not launch"); } } if (haveServerVM) { - tr = doExec(javaCmd, "-server", "-version"); + TestResult tr = doExec(javaCmd, "-server", "-version"); if (!tr.matches(".*Server VM.*")) { flagError(tr, "the expected vm -server did not launch"); } diff --git a/jdk/test/tools/launcher/FXLauncherTest.java b/jdk/test/tools/launcher/FXLauncherTest.java index a885cb8dbf6..0ee9d981cda 100644 --- a/jdk/test/tools/launcher/FXLauncherTest.java +++ b/jdk/test/tools/launcher/FXLauncherTest.java @@ -239,7 +239,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(StdMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]); } else { @@ -290,7 +290,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]); } else { @@ -359,7 +359,7 @@ public class FXLauncherTest extends TestHelper { createFile(ManifestFile, createManifestContents(NonFXMainClass, null)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); - TestResult tr; + final TestResult tr; if (useCP) { tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]); diff --git a/jdk/test/tools/launcher/I18NTest.java b/jdk/test/tools/launcher/I18NTest.java index 3af5d593afc..aa1ce24e798 100644 --- a/jdk/test/tools/launcher/I18NTest.java +++ b/jdk/test/tools/launcher/I18NTest.java @@ -60,7 +60,7 @@ public class I18NTest extends TestHelper { // compile the generate code using the javac compiler vs. the api, to // as a bonus point to see if the argument is passed correctly - TestResult tr = null; + TestResult tr; tr = doExec(javacCmd, fileName + JAVA_FILE_EXT); if (!tr.isOK()) { System.out.println(tr); diff --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java index 3769d117894..7b82abc4f48 100644 --- a/jdk/test/tools/launcher/MiscTests.java +++ b/jdk/test/tools/launcher/MiscTests.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6856415 8154212 + * @bug 6856415 8154212 8154470 * @summary Miscellaneous tests, Exceptions * @compile -XDignore.symbol.file MiscTests.java * @run main MiscTests @@ -95,30 +95,34 @@ public class MiscTests extends TestHelper { TestResult tr = doExec(javaCmd, "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak"); - for (String s : tr.testOutput) { - System.out.println(s); - } if (!tr.contains("java.security.AccessControlException:" + " access denied (\"java.lang.RuntimePermission\"" + " \"accessClassInPackage.sun.security.pkcs11\")")) { - System.out.println(tr.status); + System.out.println(tr); } } - static void testJLDEnvWithTool() { - final Map envMap = new HashMap<>(); - envMap.put("_JAVA_LAUNCHER_DEBUG", "true"); - TestResult tr = doExec(envMap, javacCmd, "-version"); - tr.checkPositive(); - if (!tr.isOK()) { - System.out.println(tr); + static void testJLDEnv() { + final Map envToSet = new HashMap<>(); + envToSet.put("_JAVA_LAUNCHER_DEBUG", "true"); + for (String cmd : new String[] { javaCmd, javacCmd }) { + TestResult tr = doExec(envToSet, cmd, "-version"); + tr.checkPositive(); + String javargs = cmd.equals(javacCmd) ? "on" : "off"; + String progname = cmd.equals(javacCmd) ? "javac" : "java"; + if (!tr.isOK() + || !tr.matches("\\s*debug:on$") + || !tr.matches("\\s*javargs:" + javargs + "$") + || !tr.matches("\\s*program name:" + progname + "$")) { + System.out.println(tr); + } } } public static void main(String... args) throws IOException { testWithClassPathSetViaProperty(); test6856415(); - testJLDEnvWithTool(); + testJLDEnv(); if (testExitValue != 0) { throw new Error(testExitValue + " tests failed"); } diff --git a/jdk/test/tools/launcher/Settings.java b/jdk/test/tools/launcher/Settings.java index 8d45c8288b6..bd8f238108a 100644 --- a/jdk/test/tools/launcher/Settings.java +++ b/jdk/test/tools/launcher/Settings.java @@ -55,9 +55,9 @@ public class Settings extends TestHelper { } } - static void checkNoContains(TestResult tr, String str) { - if (tr.contains(str)) { - System.out.println(tr.status); + static void checkNotContains(TestResult tr, String str) { + if (!tr.notContains(str)) { + System.out.println(tr); throw new RuntimeException(str + " found"); } } @@ -77,84 +77,77 @@ public class Settings extends TestHelper { if (getArch().equals("ppc64") || getArch().equals("ppc64le")) { stackSize = "800"; } - TestResult tr = null; + TestResult tr; tr = doExec(javaCmd, "-Xms64m", "-Xmx512m", "-Xss" + stackSize + "k", "-XshowSettings", "-jar", testJar.getAbsolutePath()); containsAllOptions(tr); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } tr = doExec(javaCmd, "-Xms65536k", "-Xmx712m", "-Xss" + stackSize + "000", "-XshowSettings", "-jar", testJar.getAbsolutePath()); containsAllOptions(tr); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } } static void runTestOptionAll() throws IOException { init(); - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:all"); + TestResult tr = doExec(javaCmd, "-XshowSettings:all"); containsAllOptions(tr); } static void runTestOptionVM() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:vm"); + TestResult tr = doExec(javaCmd, "-XshowSettings:vm"); checkContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); } static void runTestOptionProperty() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:properties"); - checkNoContains(tr, VM_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettings:properties"); + checkNotContains(tr, VM_SETTINGS); checkContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); } static void runTestOptionLocale() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings:locale"); - checkNoContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettings:locale"); + checkNotContains(tr, VM_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); checkContains(tr, LOCALE_SETTINGS); } static void runTestBadOptions() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettingsBadOption"); - checkNoContains(tr, VM_SETTINGS); - checkNoContains(tr, PROP_SETTINGS); - checkNoContains(tr, LOCALE_SETTINGS); + TestResult tr = doExec(javaCmd, "-XshowSettingsBadOption"); + checkNotContains(tr, VM_SETTINGS); + checkNotContains(tr, PROP_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); checkContains(tr, "Unrecognized option: -XshowSettingsBadOption"); } static void runTest7123582() throws IOException { - TestResult tr = null; - tr = doExec(javaCmd, "-XshowSettings", "-version"); + TestResult tr = doExec(javaCmd, "-XshowSettings", "-version"); if (!tr.isOK()) { - System.out.println(tr.status); + System.out.println(tr); throw new RuntimeException("test fails"); } containsAllOptions(tr); } - public static void main(String... args) { - try { - runTestOptionAll(); - runTestOptionDefault(); - runTestOptionVM(); - runTestOptionProperty(); - runTestOptionLocale(); - runTestBadOptions(); - runTest7123582(); - } catch (IOException ioe) { - throw new RuntimeException(ioe); + public static void main(String... args) throws IOException { + runTestOptionAll(); + runTestOptionDefault(); + runTestOptionVM(); + runTestOptionProperty(); + runTestOptionLocale(); + runTestBadOptions(); + runTest7123582(); + if (testExitValue != 0) { + throw new Error(testExitValue + " tests failed"); } } } diff --git a/jdk/test/tools/launcher/TestHelper.java b/jdk/test/tools/launcher/TestHelper.java index 402102b2cd5..6724daf2396 100644 --- a/jdk/test/tools/launcher/TestHelper.java +++ b/jdk/test/tools/launcher/TestHelper.java @@ -603,23 +603,23 @@ public class TestHelper { return true; } - boolean matches(String stringToMatch) { + boolean matches(String regexToMatch) { for (String x : testOutput) { - if (x.matches(stringToMatch)) { + if (x.matches(regexToMatch)) { return true; } } - appendError("string <" + stringToMatch + "> not found"); + appendError("regex <" + regexToMatch + "> not matched"); return false; } - boolean notMatches(String stringToMatch) { + boolean notMatches(String regexToMatch) { for (String x : testOutput) { - if (!x.matches(stringToMatch)) { + if (!x.matches(regexToMatch)) { return true; } } - appendError("string <" + stringToMatch + "> found"); + appendError("regex <" + regexToMatch + "> matched"); return false; } } diff --git a/jdk/test/tools/launcher/TestSpecialArgs.java b/jdk/test/tools/launcher/TestSpecialArgs.java index 307a4e06fb4..0cb75908b8f 100644 --- a/jdk/test/tools/launcher/TestSpecialArgs.java +++ b/jdk/test/tools/launcher/TestSpecialArgs.java @@ -241,7 +241,7 @@ public class TestSpecialArgs extends TestHelper { @Test void testNMArgumentProcessing() throws FileNotFoundException { - TestResult tr = null; + TestResult tr; // the direct invokers of the VM String options[] = { "-version", "-fullversion", "-help", "-?", "-X" diff --git a/jdk/test/tools/launcher/TooSmallStackSize.java b/jdk/test/tools/launcher/TooSmallStackSize.java index dac1c7f0325..7cc02ab56df 100644 --- a/jdk/test/tools/launcher/TooSmallStackSize.java +++ b/jdk/test/tools/launcher/TooSmallStackSize.java @@ -85,11 +85,10 @@ public class TooSmallStackSize extends TestHelper { */ static String checkStack(String stackSize) { String min_stack_allowed; - TestResult tr; if (verbose) System.out.println("*** Testing " + stackSize); - tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); + TestResult tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); if (verbose) printTestOutput(tr); @@ -114,11 +113,9 @@ public class TooSmallStackSize extends TestHelper { * Run the JVM with the minimum allowed stack size. This should always succeed. */ static void checkMinStackAllowed(String stackSize) { - TestResult tr = null; - if (verbose) System.out.println("*** Testing " + stackSize); - tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); + TestResult tr = doExec(javaCmd, "-Xss" + stackSize, "-version"); if (verbose) printTestOutput(tr); diff --git a/jdk/test/tools/launcher/ToolsOpts.java b/jdk/test/tools/launcher/ToolsOpts.java index bff769a54ff..a0f67d24203 100644 --- a/jdk/test/tools/launcher/ToolsOpts.java +++ b/jdk/test/tools/launcher/ToolsOpts.java @@ -149,7 +149,7 @@ public class ToolsOpts extends TestHelper { */ static void runTestOptions() throws IOException { init(); - TestResult tr = null; + TestResult tr; int jpos = -1; for (String arg[] : optionPatterns) { jpos = indexOfJoption(arg); diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java index 08a18bd2a28..13dac4f01be 100644 --- a/jdk/test/tools/launcher/VersionCheck.java +++ b/jdk/test/tools/launcher/VersionCheck.java @@ -151,12 +151,11 @@ public class VersionCheck extends TestHelper { * of the -version output as they are inconsistent. */ static boolean testToolVersion() { - TestResult tr = null; TestHelper.testExitValue = 0; for (File f : new File(JAVA_BIN).listFiles(new ToolFilter(BLACKLIST_VERSION))) { String x = f.getAbsolutePath(); System.out.println("Testing (-version): " + x); - tr = doExec(x, "-version"); + TestResult tr = doExec(x, "-version"); tr.checkPositive(); } return TestHelper.testExitValue == 0; diff --git a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java index fcb693c6285..414e0d99f1e 100644 --- a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java +++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java @@ -107,7 +107,7 @@ public class AddExportsTest { public void testSanity() throws Exception { int exitValue - = executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED", + = executeTestJava("-XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED", "-version") .outputTo(System.out) .errorTo(System.out) @@ -207,8 +207,8 @@ public class AddExportsTest { public void testWithDuplicateOption() throws Exception { int exitValue - = executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED", - "-XaddExports:java.base/sun.reflect=ALL-UNNAMED", + = executeTestJava("-XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED", + "-XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED", "-version") .outputTo(System.out) .errorTo(System.out) diff --git a/langtools/.hgtags b/langtools/.hgtags index 85118b214e5..8032358a539 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -356,3 +356,4 @@ f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 9adfb22ff08f2e82c7801b272607cd685976dbb1 jdk-9+111 3d4117c36559b344a73f786d39cc7626b4d8e2c0 jdk-9+112 4e87682893e662421af10a62d29ae822ce0fea04 jdk-9+113 +cba09a2e6ae969b029783eb59bb01017b78f8eef jdk-9+114 diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java index bc750f2b9c4..ed412ece259 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java @@ -45,10 +45,13 @@ import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.Arguments; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.file.BaseFileManager; +import com.sun.tools.javac.file.CacheFSInfo; +import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.util.ClientCodeException; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.PropagatedException; @@ -95,6 +98,7 @@ public final class JavacTool implements JavaCompiler { ? new PrintWriter(System.err, true) : new PrintWriter(new OutputStreamWriter(System.err, charset), true); context.put(Log.outKey, pw); + CacheFSInfo.preRegister(context); return new JavacFileManager(context, true, charset); } @@ -173,6 +177,14 @@ public final class JavacTool implements JavaCompiler { Arguments args = Arguments.instance(context); args.init("javac", options, classes, compilationUnits); + + // init multi-release jar handling + if (fileManager.isSupportedOption(Option.MULTIRELEASE.text) == 1) { + Target target = Target.instance(context); + List list = List.of(target.multiReleaseValue()); + fileManager.handleOption(Option.MULTIRELEASE.text, list.iterator()); + } + return new JavacTaskImpl(context); } catch (PropagatedException ex) { throw ex.getCause(); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java index 874f78cdbd6..1c84b51a0db 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java @@ -286,6 +286,8 @@ public abstract class BaseFileManager implements JavaFileManager { return -1; } + protected String multiReleaseValue; + /** * Common back end for OptionHelper handleFileManagerOption. * @param option the option whose value to be set @@ -298,6 +300,10 @@ public abstract class BaseFileManager implements JavaFileManager { encodingName = value; return true; + case MULTIRELEASE: + multiReleaseValue = value; + return true; + default: return locations.handleOption(option, value); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java index 496c0397fb7..fa1a3a5c608 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java @@ -42,8 +42,10 @@ import java.nio.file.InvalidPathException; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -266,30 +268,137 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil System.out.println(message); } - /** - * Insert all files in a subdirectory of the platform image - * which match fileKinds into resultList. - */ - private void listJRTImage(RelativeDirectory subdirectory, - Set fileKinds, - boolean recurse, - ListBuffer resultList) throws IOException { - JRTIndex.Entry e = getJRTIndex().getEntry(subdirectory); - if (symbolFileEnabled && e.ctSym.hidden) - return; - for (Path file: e.files.values()) { - if (fileKinds.contains(getKind(file))) { - JavaFileObject fe - = PathFileObject.forJRTPath(JavacFileManager.this, file); - resultList.append(fe); + private final Map containers = new HashMap<>(); + + synchronized Container getContainer(Path path) throws IOException { + Container fs = containers.get(path); + + if (fs != null) { + return fs; + } + + if (fsInfo.isFile(path) && path.equals(Locations.thisSystemModules)) { + containers.put(path, fs = new JRTImageContainer()); + return fs; + } + + Path realPath = fsInfo.getCanonicalFile(path); + + fs = containers.get(realPath); + + if (fs != null) { + containers.put(path, fs); + return fs; + } + + BasicFileAttributes attr = null; + + try { + attr = Files.readAttributes(realPath, BasicFileAttributes.class); + } catch (IOException ex) { + //non-existing + fs = MISSING_CONTAINER; + } + + if (attr != null) { + if (attr.isDirectory()) { + fs = new DirectoryContainer(realPath); + } else { + try { + fs = new ArchiveContainer(realPath); + } catch (ProviderNotFoundException | SecurityException ex) { + throw new IOException(ex); + } } } - if (recurse) { - for (RelativeDirectory rd: e.subdirs) { - listJRTImage(rd, fileKinds, recurse, resultList); + containers.put(realPath, fs); + containers.put(path, fs); + + return fs; + } + + private interface Container { + /** + * Insert all files in subdirectory subdirectory of container which + * match fileKinds into resultList + */ + public abstract void list(Path userPath, + RelativeDirectory subdirectory, + Set fileKinds, + boolean recurse, + ListBuffer resultList) throws IOException; + public abstract JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException; + public abstract void close() throws IOException; + } + + private static final Container MISSING_CONTAINER = new Container() { + @Override + public void list(Path userPath, + RelativeDirectory subdirectory, + Set fileKinds, + boolean recurse, + ListBuffer resultList) throws IOException { + } + @Override + public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException { + return null; + } + @Override + public void close() throws IOException {} + }; + + private final class JRTImageContainer implements Container { + + /** + * Insert all files in a subdirectory of the platform image + * which match fileKinds into resultList. + */ + @Override + public void list(Path userPath, + RelativeDirectory subdirectory, + Set fileKinds, + boolean recurse, + ListBuffer resultList) throws IOException { + try { + JRTIndex.Entry e = getJRTIndex().getEntry(subdirectory); + if (symbolFileEnabled && e.ctSym.hidden) + return; + for (Path file: e.files.values()) { + if (fileKinds.contains(getKind(file))) { + JavaFileObject fe + = PathFileObject.forJRTPath(JavacFileManager.this, file); + resultList.append(fe); + } + } + + if (recurse) { + for (RelativeDirectory rd: e.subdirs) { + list(userPath, rd, fileKinds, recurse, resultList); + } + } + } catch (IOException ex) { + ex.printStackTrace(System.err); + log.error("error.reading.file", userPath, getMessage(ex)); } } + + @Override + public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException { + JRTIndex.Entry e = getJRTIndex().getEntry(name.dirname()); + if (symbolFileEnabled && e.ctSym.hidden) + return null; + Path p = e.files.get(name.basename()); + if (p != null) { + return PathFileObject.forJRTPath(JavacFileManager.this, p); + } else { + return null; + } + } + + @Override + public void close() throws IOException { + } } private synchronized JRTIndex getJRTIndex() { @@ -300,164 +409,199 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil private JRTIndex jrtIndex; + private final class DirectoryContainer implements Container { + private final Path directory; - /** - * Insert all files in subdirectory subdirectory of directory directory - * which match fileKinds into resultList - */ - private void listDirectory(Path directory, Path realDirectory, - RelativeDirectory subdirectory, - Set fileKinds, - boolean recurse, - ListBuffer resultList) { - Path d; - try { - d = subdirectory.resolveAgainst(directory); - } catch (InvalidPathException ignore) { - return; + public DirectoryContainer(Path directory) { + this.directory = directory; } - if (!Files.exists(d)) { - return; - } - - if (!caseMapCheck(d, subdirectory)) { - return; - } - - java.util.List files; - try (Stream s = Files.list(d)) { - files = (sortFiles == null ? s : s.sorted(sortFiles)).collect(Collectors.toList()); - } catch (IOException ignore) { - return; - } - - if (realDirectory == null) - realDirectory = fsInfo.getCanonicalFile(directory); - - for (Path f: files) { - String fname = f.getFileName().toString(); - if (fname.endsWith("/")) - fname = fname.substring(0, fname.length() - 1); - if (Files.isDirectory(f)) { - if (recurse && SourceVersion.isIdentifier(fname)) { - listDirectory(directory, realDirectory, - new RelativeDirectory(subdirectory, fname), - fileKinds, - recurse, - resultList); - } - } else { - if (isValidFile(fname, fileKinds)) { - RelativeFile file = new RelativeFile(subdirectory, fname); - JavaFileObject fe = PathFileObject.forDirectoryPath(this, - file.resolveAgainst(realDirectory), directory, file); - resultList.append(fe); - } - } - } - } - - /** - * Insert all files in subdirectory subdirectory of archive archivePath - * which match fileKinds into resultList - */ - private void listArchive(Path archivePath, - RelativeDirectory subdirectory, - Set fileKinds, - boolean recurse, - ListBuffer resultList) - throws IOException { - FileSystem fs = getFileSystem(archivePath); - if (fs == null) { - return; - } - - Path containerSubdir = subdirectory.resolveAgainst(fs); - if (!Files.exists(containerSubdir)) { - return; - } - - int maxDepth = (recurse ? Integer.MAX_VALUE : 1); - Set opts = EnumSet.of(FOLLOW_LINKS); - Files.walkFileTree(containerSubdir, opts, maxDepth, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - if (isValid(dir.getFileName())) { - return FileVisitResult.CONTINUE; - } else { - return FileVisitResult.SKIP_SUBTREE; - } - } - - boolean isValid(Path fileName) { - if (fileName == null) { - return true; - } else { - String name = fileName.toString(); - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - return SourceVersion.isIdentifier(name); - } - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (attrs.isRegularFile() && fileKinds.contains(getKind(file.getFileName().toString()))) { - JavaFileObject fe = PathFileObject.forJarPath( - JavacFileManager.this, file, archivePath); - resultList.append(fe); - } - return FileVisitResult.CONTINUE; - } - }); - - } - - /** - * container is a directory, a zip file, or a non-existant path. - * Insert all files in subdirectory subdirectory of container which - * match fileKinds into resultList - */ - private void listContainer(Path container, - RelativeDirectory subdirectory, - Set fileKinds, - boolean recurse, - ListBuffer resultList) - throws IOException { - if (Files.isRegularFile(container) && container.equals(Locations.thisSystemModules)) { + /** + * Insert all files in subdirectory subdirectory of directory userPath + * which match fileKinds into resultList + */ + @Override + public void list(Path userPath, + RelativeDirectory subdirectory, + Set fileKinds, + boolean recurse, + ListBuffer resultList) throws IOException { + Path d; try { - listJRTImage(subdirectory, - fileKinds, - recurse, - resultList); - } catch (IOException ex) { - ex.printStackTrace(System.err); - log.error("error.reading.file", container, getMessage(ex)); + d = subdirectory.resolveAgainst(userPath); + } catch (InvalidPathException ignore) { + return ; + } + + if (!Files.exists(d)) { + return; + } + + if (!caseMapCheck(d, subdirectory)) { + return; + } + + java.util.List files; + try (Stream s = Files.list(d)) { + files = (sortFiles == null ? s : s.sorted(sortFiles)).collect(Collectors.toList()); + } catch (IOException ignore) { + return; + } + + for (Path f: files) { + String fname = f.getFileName().toString(); + if (fname.endsWith("/")) + fname = fname.substring(0, fname.length() - 1); + if (Files.isDirectory(f)) { + if (recurse && SourceVersion.isIdentifier(fname)) { + list(userPath, + new RelativeDirectory(subdirectory, fname), + fileKinds, + recurse, + resultList); + } + } else { + if (isValidFile(fname, fileKinds)) { + RelativeFile file = new RelativeFile(subdirectory, fname); + JavaFileObject fe = PathFileObject.forDirectoryPath(JavacFileManager.this, + file.resolveAgainst(directory), userPath, file); + resultList.append(fe); + } + } } - return; } - if (Files.isDirectory(container)) { - listDirectory(container, null, - subdirectory, - fileKinds, - recurse, - resultList); - return; + @Override + public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException { + try { + Path f = name.resolveAgainst(userPath); + if (Files.exists(f)) + return PathFileObject.forSimplePath(JavacFileManager.this, + fsInfo.getCanonicalFile(f), f); + } catch (InvalidPathException ignore) { + } + return null; } - if (Files.isRegularFile(container)) { - listArchive(container, - subdirectory, - fileKinds, - recurse, - resultList); + @Override + public void close() throws IOException { } } + private final class ArchiveContainer implements Container { + private final Path archivePath; + private final FileSystem fileSystem; + private final Map pathCache = new HashMap<>(); + + public ArchiveContainer(Path archivePath) throws IOException, ProviderNotFoundException, SecurityException { + this.archivePath = archivePath; + if (multiReleaseValue != null && archivePath.toString().endsWith(".jar")) { + Map env = Collections.singletonMap("multi-release", multiReleaseValue); + this.fileSystem = getJarFSProvider().newFileSystem(archivePath, env); + } else { + this.fileSystem = FileSystems.newFileSystem(archivePath, null); + } + } + + /** + * Insert all files in subdirectory subdirectory of this archive + * which match fileKinds into resultList + */ + @Override + public void list(Path userPath, + RelativeDirectory subdirectory, + Set fileKinds, + boolean recurse, + ListBuffer resultList) throws IOException { + Path resolvedSubdirectory = resolvePath(subdirectory); + + if (resolvedSubdirectory == null) + return ; + + int maxDepth = (recurse ? Integer.MAX_VALUE : 1); + Set opts = EnumSet.of(FOLLOW_LINKS); + Files.walkFileTree(resolvedSubdirectory, opts, maxDepth, + new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + if (isValid(dir.getFileName())) { + return FileVisitResult.CONTINUE; + } else { + return FileVisitResult.SKIP_SUBTREE; + } + } + + boolean isValid(Path fileName) { + if (fileName == null) { + return true; + } else { + String name = fileName.toString(); + if (name.endsWith("/")) { + name = name.substring(0, name.length() - 1); + } + return SourceVersion.isIdentifier(name); + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (attrs.isRegularFile() && fileKinds.contains(getKind(file.getFileName().toString()))) { + JavaFileObject fe = PathFileObject.forJarPath( + JavacFileManager.this, file, archivePath); + resultList.append(fe); + } + return FileVisitResult.CONTINUE; + } + }); + + } + + @Override + public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException { + Path p = resolvePath(name); + if (p != null) + return PathFileObject.forJarPath(JavacFileManager.this, p, userPath); + + return null; + } + + private synchronized Path resolvePath(RelativePath path) { + if (!pathCache.containsKey(path)) { + Path relativePath = path.resolveAgainst(fileSystem); + + if (!Files.exists(relativePath)) { + relativePath = null; + } + + pathCache.put(path, relativePath); + return relativePath; + } + return pathCache.get(path); + } + + @Override + public void close() throws IOException { + fileSystem.close(); + } + } + + private FileSystemProvider jarFSProvider; + + private FileSystemProvider getJarFSProvider() throws IOException { + if (jarFSProvider != null) { + return jarFSProvider; + } + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + if (provider.getScheme().equals("jar")) { + return (jarFSProvider = provider); + } + } + throw new ProviderNotFoundException("no provider found for .jar files"); + } + + /** + * container is a directory, a zip file, or a non-existent path. + */ private boolean isValidFile(String s, Set fileKinds) { JavaFileObject.Kind kind = getKind(s); return fileKinds.contains(kind); @@ -498,18 +642,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil return j < 0; } - private FileSystem getFileSystem(Path path) throws IOException { - Path realPath = fsInfo.getCanonicalFile(path); - FileSystem fs = fileSystems.get(realPath); - if (fs == null) { - fileSystems.put(realPath, fs = FileSystems.newFileSystem(realPath, null)); - } - return fs; - } - - private final Map fileSystems = new HashMap<>(); - - /** Flush any output resources. */ @Override @DefinedBy(Api.COMPILER) @@ -528,10 +660,10 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil } locations.close(); - for (FileSystem fs: fileSystems.values()) { - fs.close(); + for (Container container: containers.values()) { + container.close(); } - fileSystems.clear(); + containers.clear(); contentCache.clear(); } @@ -570,8 +702,12 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName); ListBuffer results = new ListBuffer<>(); - for (Path directory : path) - listContainer(directory, subdirectory, kinds, recurse, results); + for (Path directory : path) { + Container container = getContainer(directory); + + container.list(directory, subdirectory, kinds, recurse, results); + } + return results.toList(); } @@ -644,29 +780,10 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil return null; for (Path file: path) { - if (file.equals(Locations.thisSystemModules)) { - JRTIndex.Entry e = getJRTIndex().getEntry(name.dirname()); - if (symbolFileEnabled && e.ctSym.hidden) - continue; - Path p = e.files.get(name.basename()); - if (p != null) - return PathFileObject.forJRTPath(this, p); - } else if (Files.isDirectory(file)) { - try { - Path f = name.resolveAgainst(file); - if (Files.exists(f)) - return PathFileObject.forSimplePath(this, - fsInfo.getCanonicalFile(f), f); - } catch (InvalidPathException ignore) { - } - } else if (Files.isRegularFile(file)) { - FileSystem fs = getFileSystem(file); - if (fs != null) { - Path fsRoot = fs.getRootDirectories().iterator().next(); - Path f = name.resolveAgainst(fsRoot); - if (Files.exists(f)) - return PathFileObject.forJarPath(this, f, file); - } + JavaFileObject fo = getContainer(file).getFileObject(file, name); + + if (fo != null) { + return fo; } } return null; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index df70c50b8ec..75f314b1912 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,4 +141,10 @@ public enum Target { return compareTo(JDK1_9) >= 0; } + /** Value of platform release used to access multi-release jar files + */ + public String multiReleaseValue() { + return Integer.toString(this.ordinal() - Target.JDK1_1.ordinal() + 1); + } + } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java index 187f6f76352..a37991e2dd2 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import com.sun.tools.javac.api.BasicJavacTask; import com.sun.tools.javac.file.CacheFSInfo; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.platform.PlatformDescription; import com.sun.tools.javac.processing.AnnotationProcessingError; import com.sun.tools.javac.util.*; @@ -230,7 +231,7 @@ public class Main { if (args.isEmpty()) return Result.OK; - // init Depeendencies + // init Dependencies if (options.isSet("completionDeps")) { Dependencies.GraphDependencies.preRegister(context); } @@ -242,6 +243,13 @@ public class Main { t.initPlugins(pluginOpts); } + // init multi-release jar handling + if (fileManager.isSupportedOption(Option.MULTIRELEASE.text) == 1) { + Target target = Target.instance(context); + List list = List.of(target.multiReleaseValue()); + fileManager.handleOption(Option.MULTIRELEASE.text, list.iterator()); + } + // init JavaCompiler JavaCompiler comp = JavaCompiler.instance(context); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index cddbda43f2b..5f07f84e47e 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -667,7 +667,9 @@ public enum Option { } return false; } - }; + }, + + MULTIRELEASE("-multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER); /** The kind of an Option. This is used by the -help and -X options. */ public enum OptionKind { diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index 3df72adfa3b..611ab01a6cf 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -99,6 +99,8 @@ javac.opt.implicit=\ Specify whether or not to generate class files for implicitly referenced files javac.opt.pkginfo=\ Specify handling of package-info files +javac.opt.multi-release=\ + Specify which release to use in multi-release jars javac.opt.arg.class=\ javac.opt.arg.class.list=\ @@ -133,6 +135,8 @@ javac.opt.plugin=\ Name and optional arguments for a plug-in to be run javac.opt.arg.plugin=\ "name args" +javac.opt.arg.multi-release=\ + ## extended options diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index 0de7455a4a5..824ffc81348 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -52,6 +52,8 @@ import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.CommandLine; +import com.sun.tools.javac.main.OptionHelper; +import com.sun.tools.javac.main.OptionHelper.GrumpyHelper; import com.sun.tools.javac.platform.PlatformDescription; import com.sun.tools.javac.platform.PlatformUtils; import com.sun.tools.javac.util.ClientCodeException; @@ -342,7 +344,7 @@ public class Start extends ToolOption.Helper { compOpts = Options.instance(context); // Make sure no obsolete source/target messages are reported - compOpts.put("-Xlint:-options", "-Xlint:-options"); + com.sun.tools.javac.main.Option.XLINT.process(getOptionHelper(), "-Xlint:-options"); doclet.init(locale, messager); parseArgs(argList, javaNames); @@ -550,6 +552,8 @@ public class Start extends ToolOption.Helper { if (o.hasArg) { oneArg(args, i++); o.process(this, args.get(i)); + } else if (o.hasSuffix) { + o.process(this, arg); } else { setOption(arg); o.process(this); @@ -690,4 +694,19 @@ public class Start extends ToolOption.Helper { } return null; } + + @Override + OptionHelper getOptionHelper() { + return new GrumpyHelper(null) { + @Override + public String get(com.sun.tools.javac.main.Option option) { + return compOpts.get(option); + } + + @Override + public void put(String name, String value) { + compOpts.put(name, value); + } + }; + } } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java index 7f8d2f0e828..9eaa29213d6 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.StringTokenizer; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.main.OptionHelper; import com.sun.tools.javac.util.Options; /** @@ -118,14 +119,14 @@ public enum ToolOption { ADDMODS("-addmods", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.ADDMODS.process(helper.getOptionHelper(), opt, arg); } }, LIMITMODS("-limitmods", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.LIMITMODS.process(helper.getOptionHelper(), opt, arg); } }, @@ -133,35 +134,63 @@ public enum ToolOption { @Override public void process(Helper helper, String arg) { helper.encoding = arg; - helper.setCompilerOpt(opt, arg); + helper.setFileManagerOpt(Option.ENCODING, arg); } }, RELEASE("-release", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.RELEASE.process(helper.getOptionHelper(), opt, arg); } }, SOURCE("-source", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.SOURCE.process(helper.getOptionHelper(), opt, arg); } }, XMAXERRS("-Xmaxerrs", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.XMAXERRS.process(helper.getOptionHelper(), opt, arg); } }, XMAXWARNS("-Xmaxwarns", true) { @Override public void process(Helper helper, String arg) { - helper.setCompilerOpt(opt, arg); + Option.XMAXWARNS.process(helper.getOptionHelper(), opt, arg); + } + }, + + XADDREADS("-XaddReads:", false) { + @Override + public void process(Helper helper, String arg) { + Option.XADDREADS.process(helper.getOptionHelper(), arg); + } + }, + + XADDEXPORTS("-XaddExports:", false) { + @Override + public void process(Helper helper, String arg) { + Option.XADDEXPORTS.process(helper.getOptionHelper(), arg); + } + }, + + XMODULE("-Xmodule:", false) { + @Override + public void process(Helper helper, String arg) { + Option.XMODULE.process(helper.getOptionHelper(), arg); + } + }, + + XPATCH("-Xpatch:", false) { + @Override + public void process(Helper helper, String arg) { + Option.XMODULE.process(helper.getOptionHelper(), arg); } }, @@ -299,6 +328,7 @@ public enum ToolOption { public final String opt; public final boolean hasArg; + public final boolean hasSuffix; // ex: foo:bar or -foo=bar ToolOption(String opt) { this(opt, false); @@ -307,6 +337,8 @@ public enum ToolOption { ToolOption(String opt, boolean hasArg) { this.opt = opt; this.hasArg = hasArg; + char lastChar = opt.charAt(opt.length() - 1); + this.hasSuffix = lastChar == ':' || lastChar == '='; } void process(Helper helper, String arg) { } @@ -314,9 +346,16 @@ public enum ToolOption { void process(Helper helper) { } static ToolOption get(String name) { - for (ToolOption o: values()) { - if (name.equals(o.opt)) + String oname = name; + if (name.contains(":")) { + oname = name.substring(0, name.indexOf(':') + 1); + } else if (name.contains("=")) { + oname = name.substring(0, name.indexOf('=') + 1); + } + for (ToolOption o : values()) { + if (oname.equals(o.opt)) { return o; + } } return null; } @@ -366,6 +405,7 @@ public enum ToolOption { abstract void Xusage(); abstract void usageError(String msg, Object... args); + abstract OptionHelper getOptionHelper(); void addToList(List list, String str){ StringTokenizer st = new StringTokenizer(str, ":"); @@ -388,13 +428,6 @@ public enum ToolOption { } } - void setCompilerOpt(String opt, String arg) { - if (compOpts.get(opt) != null) { - usageError("main.option.already.seen", opt); - } - compOpts.put(opt, arg); - } - void setFileManagerOpt(Option opt, String arg) { fileManagerOpts.put(opt, arg); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties index 1bebe48ddae..f9cab63f716 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties @@ -37,6 +37,13 @@ main.usage=Usage: javadoc [options] [packagenames] [sourcefiles] [@files]\n\ \ -help Display command line options and exit\n\ \ -doclet Generate output via alternate doclet\n\ \ -docletpath Specify where to find doclet class files\n\ +\ -modulesourcepath Specify where to find input source files for multiple modules\n\ +\ -upgrademodulepath Override location of upgradeable modules\n\ +\ -modulepath Specify where to find application modules\n\ +\ -mp Specify where to find application modules\n\ +\ -addmods (,)* Root modules to resolve in addition to the initial modules,\n\ +\ or all modules on the module path if is ALL-MODULE-PATH.\n\ +\ -limitmods (,)* Limit the universe of observable modules\n\ \ -sourcepath Specify where to find source files\n\ \ -classpath Specify where to find user class files\n\ \ -cp Specify where to find user class files\n\ @@ -56,14 +63,23 @@ main.usage=Usage: javadoc [options] [packagenames] [sourcefiles] [@files]\n\ main.Xusage=\ \ -Xmaxerrs Set the maximum number of errors to print\n\ -\ -Xmaxwarns Set the maximum number of warnings to print\n +\ -Xmaxwarns Set the maximum number of warnings to print\n\ +\ -XaddExports:/=(,)*\n\ +\ Specify a package to be considered as exported from its \n\ +\ defining module to additional modules, or to all unnamed \n\ +\ modules if is ALL-UNNAMED.\n\ +\ -XaddReads:=(,)*\n\ +\ Specify additional modules to be considered as required by a\n\ +\ given module. may be ALL-UNNAMED to require\n\ +\ the unnamed module.\n\ +\ -Xmodule: Specify a module to which the classes being compiled belong.\n\ +\ -Xpatch: Specify location of module class files to patch\n main.Xusage.foot=\ These options are non-standard and subject to change without notice. main.doclet.usage.header=Provided by the {0} doclet: -main.option.already.seen=The {0} option may be specified no more than once. main.requires_argument=option {0} requires an argument. main.invalid_flag=invalid flag: {0} main.No_packages_or_classes_specified=No packages or classes specified. diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 7db92c5fae4..144de11c114 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -1077,12 +1077,12 @@ public class JShellTool { ed.add(n); } editor = ed.toArray(new String[ed.size()]); - fluffmsg("jshell.msg.set.editor.set", arg); + fluffmsg("jshell.msg.set.editor.set", prog); return true; } } case "start": { - String init = readFile(at.next(), "'/set start'"); + String init = readFile(at.next(), "/set start"); if (init == null) { return false; } else { @@ -1351,7 +1351,7 @@ public class JShellTool { .filter(sn -> state.status(sn).isActive && sn instanceof PersistentSnippet) .collect(toList()); if (snippets.isEmpty()) { - errormsg("jshell.err.drop.active"); + errormsg("jshell.err.drop.not.active"); return false; } if (snippets.size() > 1) { @@ -1499,7 +1499,7 @@ public class JShellTool { } private boolean cmdOpen(String filename) { - return runFile(filename, "'/open'"); + return runFile(filename, "/open"); } private boolean runFile(String filename, String context) { @@ -1533,7 +1533,7 @@ public class JShellTool { } catch (AccessDeniedException e) { errormsg("jshell.err.file.not.accessible", context, filename, e.getMessage()); } catch (NoSuchFileException e) { - errormsg("jshell.err.file.not.found", context, filename, e.getMessage()); + errormsg("jshell.err.file.not.found", context, filename); } catch (Exception e) { errormsg("jshell.err.file.exception", context, filename, e); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index dcdb5a3e01a..34ef112a527 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -42,7 +42,7 @@ jshell.err.arg = Invalid ''{0}'' argument: {1} jshell.msg.see = See {0} for help. jshell.err.file.not.accessible = File ''{1}'' for ''{0}'' is not accessible: {2} -jshell.err.file.not.found = File ''{1}'' for ''{0}'' is not found: {2} +jshell.err.file.not.found = File ''{1}'' for ''{0}'' is not found. jshell.err.file.exception = File ''{1}'' for ''{0}'' threw exception: {2} jshell.err.file.filename = ''{0}'' requires a filename argument. @@ -90,7 +90,7 @@ For example ''/help /list'' or ''/help intro''. Subjects:\n jshell.err.drop.arg =\ In the /drop argument, please specify an import, variable, method, or class to drop.\n\ Specify by id or name. Use /list to see ids. Use /reset to reset all state. -jshell.msg.drop.not.active = The argument did not specify an active import, variable, method, or class to drop. +jshell.err.drop.not.active = The argument did not specify an active import, variable, method, or class to drop. jshell.err.drop.ambiguous = The argument references more than one import, variable, method, or class. jshell.err.failed = Failed. jshell.msg.native.method = Native Method @@ -503,74 +503,86 @@ The contents of the specified become the default start-up snippets and co which are run when the jshell tool is started or reset. startup.feedback = \ -/set newmode normal command \n\ -/set prompt normal '\\n-> ' '>> ' \n\ -/set format normal pre '| ' \n\ -/set format normal post '%n' \n\ -/set format normal errorpre '| ' \n\ -/set format normal errorpost '%n' \n\ - \n\ -/set format normal errorline '{post}{pre} {err}' \n\ - \n\ -/set format normal action 'Added' added-primary \n\ -/set format normal action 'Modified' modified-primary \n\ -/set format normal action 'Replaced' replaced-primary \n\ -/set format normal action 'Overwrote' overwrote-primary \n\ -/set format normal action 'Dropped' dropped-primary \n\ -/set format normal action ' Update added' added-update \n\ -/set format normal action ' Update modified' modified-update \n\ -/set format normal action ' Update replaced' replaced-update \n\ -/set format normal action ' Update overwrote' overwrote-update \n\ -/set format normal action ' Update dropped' dropped-update \n\ - \n\ -/set format normal until ', however, it cannot be instanciated or its methods invoked until' defined-class-primary \n\ -/set format normal until ', however, its methods cannot be invoked until' defined-interface-primary \n\ -/set format normal until ', however, it cannot be used until' defined-enum,annotation-primary \n\ -/set format normal until ', however, it cannot be invoked until' defined-method-primary \n\ -/set format normal until ', however, it cannot be referenced until' notdefined-primary \n\ -/set format normal until ' which cannot be instanciated or its methods invoked until' defined-class-update \n\ -/set format normal until ' whose methods cannot be invoked until' defined-interface-update \n\ -/set format normal until ' which cannot be invoked until' defined-method-update \n\ -/set format normal until ' which cannot be referenced until' notdefined-update \n\ - \n\ -/set format normal unrerr '{unresolved} is declared' unresolved1-error0 \n\ -/set format normal unrerr '{unresolved} are declared' unresolved2-error0 \n\ -/set format normal unrerr ' this error is corrected: {errors}' unresolved0-error1 \n\ -/set format normal unrerr '{unresolved} is declared and this error is corrected: {errors}' unresolved1-error1 \n\ -/set format normal unrerr '{unresolved} are declared and this error is corrected: {errors}' unresolved2-error1 \n\ -/set format normal unrerr ' these errors are corrected: {errors}' unresolved0-error2 \n\ -/set format normal unrerr '{unresolved} is declared and these errors are corrected: {errors}' unresolved1-error2 \n\ -/set format normal unrerr '{unresolved} are declared and these errors are corrected: {errors}' unresolved2-error2 \n\ - \n\ -/set format normal resolve '{until}{unrerr}' added,modified,replaced,used \n\ - \n\ -/set format normal typeKind 'class' class \n\ -/set format normal typeKind 'interface' interface \n\ -/set format normal typeKind 'enum' enum \n\ -/set format normal typeKind 'annotation interface' annotation \n\ - \n\ -/set format normal display '{pre}{action} {typeKind} {name}{resolve}{post}' class,interface,enum,annotation \n\ -/set format normal display '{pre}{action} method {name}({type}){resolve}{post}' method \n\ - \n\ -/set format normal display '{pre}{action} variable {name} of type {type}{resolve}{post}' vardecl \n\ -/set format normal display '{pre}{action} variable {name} of type {type} with initial value {value}{resolve}{post}' varinit \n\ +/set newmode verbose command \n\ +\n\ +/set prompt verbose '\\njshell> ' ' ...> ' \n\ +\n\ +/set format verbose pre '| ' \n\ +/set format verbose post '%n' \n\ +/set format verbose errorpre '| ' \n\ +/set format verbose errorpost '%n' \n\ +\n\ +/set format verbose errorline '{pre} {err}' \n\ +\n\ +/set format verbose action 'created' added-primary \n\ +/set format verbose action 'modified' modified-primary \n\ +/set format verbose action 'replaced' replaced-primary \n\ +/set format verbose action 'overwrote' overwrote-primary \n\ +/set format verbose action 'dropped' dropped-primary \n\ +/set format verbose action ' update created' added-update \n\ +/set format verbose action ' update modified' modified-update \n\ +/set format verbose action ' update replaced' replaced-update \n\ +/set format verbose action ' update overwrote' overwrote-update \n\ +/set format verbose action ' update dropped' dropped-update \n\ +\n\ +/set format verbose until ', however, it cannot be instanciated or its methods invoked until' defined-class-primary \n\ +/set format verbose until ', however, its methods cannot be invoked until' defined-interface-primary \n\ +/set format verbose until ', however, it cannot be used until' defined-enum,annotation-primary \n\ +/set format verbose until ', however, it cannot be invoked until' defined-method-primary \n\ +/set format verbose until ', however, it cannot be referenced until' notdefined-primary \n\ +/set format verbose until ' which cannot be instanciated or its methods invoked until' defined-class-update \n\ +/set format verbose until ' whose methods cannot be invoked until' defined-interface-update \n\ +/set format verbose until ' which cannot be invoked until' defined-method-update \n\ +/set format verbose until ' which cannot be referenced until' notdefined-update \n\ +\n\ +/set format verbose unrerr '{unresolved} is declared' unresolved1-error0 \n\ +/set format verbose unrerr '{unresolved} are declared' unresolved2-error0 \n\ +/set format verbose unrerr ' this error is corrected: {errors}' unresolved0-error1 \n\ +/set format verbose unrerr '{unresolved} is declared and this error is corrected: {errors}' unresolved1-error1 \n\ +/set format verbose unrerr '{unresolved} are declared and this error is corrected: {errors}' unresolved2-error1 \n\ +/set format verbose unrerr ' these errors are corrected: {errors}' unresolved0-error2 \n\ +/set format verbose unrerr '{unresolved} is declared and these errors are corrected: {errors}' unresolved1-error2 \n\ +/set format verbose unrerr '{unresolved} are declared and these errors are corrected: {errors}' unresolved2-error2 \n\ +\n\ +/set format verbose resolve '{until}{unrerr}' added,modified,replaced,used \n\ +\n\ +/set format verbose typeKind 'class' class \n\ +/set format verbose typeKind 'interface' interface \n\ +/set format verbose typeKind 'enum' enum \n\ +/set format verbose typeKind 'annotation interface' annotation \n\ +\n\ +/set format verbose result '{name} ==> {value}{post}' added,modified,replaced-ok-primary \n\ +\n\ +/set format verbose display '{result}{pre}created scratch variable {name} : {type}{post}' expression-primary \n\ +/set format verbose display '{result}{pre}value of {name} : {type}{post}' varvalue-primary \n\ +/set format verbose display '{result}{pre}assigned to {name} : {type}{post}' assignment-primary \n\ +/set format verbose display '{result}{pre}{action} variable {name} : {type}{resolve}{post}' varinit,vardecl \n\ +/set format verbose display '{pre}{action} variable {name}{resolve}{post}' vardecl,varinit-notdefined \n\ +/set format verbose display '{pre}{action} variable {name}{post}' dropped-vardecl,varinit \n\ +/set format verbose display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update \n\ +\n\ +/set format verbose display '{pre}{action} {typeKind} {name}{resolve}{post}' class,interface,enum,annotation \n\ +/set format verbose display '{pre}{action} method {name}({type}){resolve}{post}' method \n\ +\n\ +/set format verbose display '{pre}attempted to use {typeKind} {name}{resolve}{post}' used-class,interface,enum,annotation \n\ +/set format verbose display '{pre}attempted to call method {name}({type}){resolve}{post}' used-method \n\ +\n\ +/set newmode normal command verbose \n\ +/set format normal display '' added,modified,replaced,overwrote,dropped-update \n\ /set format normal display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update \n\ -/set format normal display '{pre}{action} variable {name}{resolve}{post}' vardecl,varinit-notdefined \n\ -/set format normal display '{pre}{action} variable {name}{post}' overwrote,dropped-vardecl,varinit \n\ - \n\ -/set format normal display '{pre}Expression value is: {value}{post}{pre} assigned to temporary variable {name} of type {type}{post}' expression \n\ -/set format normal display '{pre}Variable {name} of type {type} has value {value}{post}' varvalue \n\ -/set format normal display '{pre}Variable {name} has been assigned the value {value}{post}' assignment \n\ - \n\ -/set format normal display '{pre}Attempted to use {typeKind} {name}{resolve}{post}' used-class,interface,enum,annotation \n\ -/set format normal display '{pre}Attempted to call method {name}({type}){resolve}{post}' used-method \n\ - \n\ +/set format normal display '{result}' added,modified,replaced-expression,varvalue,assignment,varinit,vardecl-ok-primary \n\ +/set newmode concise quiet normal \n\ +\n\ +/set prompt concise 'jshell> ' ' ...> ' \n\ +\n\ +/set format concise display '' class,interface,enum,annotation,method,assignment,varinit,vardecl-ok \n\ +\n\ /set feedback normal \n\ - \n\ -/set newmode off quiet \n\ -/set prompt off '-> ' '>> ' \n\ -/set format off pre '| ' \n\ -/set format off post '%n' \n\ -/set format off errorpre '| ' \n\ -/set format off errorpost '%n' \n\ -/set format off display '' \n +\n\ +/set newmode silent quiet \n\ +/set prompt silent '-> ' '>> ' \n\ +/set format silent pre '| ' \n\ +/set format silent post '%n' \n\ +/set format silent errorpre '| ' \n\ +/set format silent errorpost '%n' \n\ +/set format silent display '' \n diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 94b2dca46ee..7e0e4b35392 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -465,16 +465,40 @@ class Eval { // If appropriate, execute the snippet String value = null; Exception exception = null; - if (si.isExecutable() && si.status().isDefined) { - try { - value = state.executionControl().commandInvoke(state.maps.classFullName(si)); - value = si.subKind().hasValue() - ? expunge(value) - : ""; - } catch (EvalException ex) { - exception = translateExecutionException(ex); - } catch (UnresolvedReferenceException ex) { - exception = ex; + if (si.status().isDefined) { + if (si.isExecutable()) { + try { + value = state.executionControl().commandInvoke(state.maps.classFullName(si)); + value = si.subKind().hasValue() + ? expunge(value) + : ""; + } catch (EvalException ex) { + exception = translateExecutionException(ex); + } catch (UnresolvedReferenceException ex) { + exception = ex; + } + } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) { + switch (((VarSnippet) si).typeName()) { + case "byte": + case "short": + case "int": + case "long": + value = "0"; + break; + case "float": + case "double": + value = "0.0"; + break; + case "boolean": + value = "false"; + break; + case "char": + value = "''"; + break; + default: + value = "null"; + break; + } } } return events(c, outs, value, exception); diff --git a/langtools/test/jdk/jshell/EditorPadTest.java b/langtools/test/jdk/jshell/EditorPadTest.java index fd3b8e110d8..30eed668255 100644 --- a/langtools/test/jdk/jshell/EditorPadTest.java +++ b/langtools/test/jdk/jshell/EditorPadTest.java @@ -25,6 +25,7 @@ * @test * @summary Testing built-in editor. * @ignore 8139872 + * @modules jdk.jshell/jdk.internal.jshell.tool * @build ReplToolTesting EditorTestBase * @run testng EditorPadTest */ @@ -67,7 +68,7 @@ public class EditorPadTest extends EditorTestBase { private static JButton exit = null; @BeforeClass - public static void setUp() { + public static void setUpEditorPadTest() { try { robot = new Robot(); robot.setAutoWaitForIdle(true); diff --git a/langtools/test/jdk/jshell/EditorTestBase.java b/langtools/test/jdk/jshell/EditorTestBase.java index f6f7bef8a8e..c2bd55a921c 100644 --- a/langtools/test/jdk/jshell/EditorTestBase.java +++ b/langtools/test/jdk/jshell/EditorTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,19 +65,19 @@ public abstract class EditorTestBase extends ReplToolTesting { } public void assertEditOutput(boolean after, String cmd, String output, Action action) { - assertEditOutput(after, cmd, s -> assertEquals(s, output, "command"), action); + assertEditOutput(after, cmd, s -> assertEquals(s.trim(), output.trim(), "command"), action); } @Test public void testEditNegative() { - for (String edit : new String[] {"/e", "/edit"}) { + for (String edit : new String[] {"/ed", "/edit"}) { test(new String[]{"-nostartup"}, - a -> assertCommand(a, edit + " 1", - "| No definition or id named 1 found. See /classes, /methods, /vars, or /list\n"), - a -> assertCommand(a, edit + " -1", - "| No definition or id named -1 found. See /classes, /methods, /vars, or /list\n"), - a -> assertCommand(a, edit + " unknown", - "| No definition or id named unknown found. See /classes, /methods, /vars, or /list\n") + a -> assertCommandOutputStartsWith(a, edit + " 1", + "| No definition or id found named: 1"), + a -> assertCommandOutputStartsWith(a, edit + " -1", + "| No definition or id found named: -1"), + a -> assertCommandOutputStartsWith(a, edit + " unknown", + "| No definition or id found named: unknown") ); } } @@ -86,7 +86,7 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testDoNothing() { testEditor( a -> assertVariable(a, "int", "a", "0", "0"), - a -> assertEditOutput(a, "/e 1", "", this::exit), + a -> assertEditOutput(a, "/ed 1", "", this::exit), a -> assertCommandCheckOutput(a, "/v", assertVariables()) ); } @@ -95,12 +95,12 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditVariable1() { testEditor( a -> assertVariable(a, "int", "a", "0", "0"), - a -> assertEditOutput(a, "/e 1", "| Modified variable a of type int with initial value 10\n", () -> { + a -> assertEditOutput(a, "/ed 1", "a ==> 10", () -> { writeSource("\n\n\nint a = 10;\n\n\n"); exit(); loadVariable(true, "int", "a", "10", "10"); }), - a -> assertEditOutput(a, "/e 1", "| Modified variable a of type int with initial value 15\n", () -> { + a -> assertEditOutput(a, "/ed 1", "a ==> 15", () -> { writeSource("int a = 15;"); exit(); loadVariable(true, "int", "a", "15", "15"); @@ -113,12 +113,12 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditVariable2() { testEditor( a -> assertVariable(a, "int", "a", "0", "0"), - a -> assertEditOutput(a, "/e 1", "| Added variable b of type int with initial value 10\n", () -> { + a -> assertEditOutput(a, "/ed 1", "b ==> 10", () -> { writeSource("int b = 10;"); exit(); loadVariable(true, "int", "b", "10", "10"); }), - a -> assertEditOutput(a, "/e 1", "| Modified variable a of type int with initial value 15\n", () -> { + a -> assertEditOutput(a, "/ed 1", "a ==> 15", () -> { writeSource("int a = 15;"); exit(); loadVariable(true, "int", "a", "15", "15"); @@ -131,19 +131,18 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditClass1() { testEditor( a -> assertClass(a, "class A {}", "class", "A"), - a -> assertEditOutput(a, "/e 1", "", () -> { + a -> assertEditOutput(a, "/ed 1", "", () -> { writeSource("\n\n\nclass A {}\n\n\n"); exit(); loadClass(true, "class A {}", "class", "A"); }), - a -> assertEditOutput(a, "/e 1", - "| Replaced enum A\n" + - "| Update overwrote class A\n", () -> { + a -> assertEditOutput(a, "/ed 1", + "| replaced enum A", () -> { writeSource("enum A {}"); exit(); loadClass(true, "enum A {}", "enum", "A"); }), - a -> assertCommandCheckOutput(a, "/c", assertClasses()) + a -> assertCommandCheckOutput(a, "/classes", assertClasses()) ); } @@ -151,19 +150,18 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditClass2() { testEditor( a -> assertClass(a, "class A {}", "class", "A"), - a -> assertEditOutput(a, "/e 1", "| Added class B\n", () -> { + a -> assertEditOutput(a, "/ed 1", "| created class B", () -> { writeSource("class B { }"); exit(); loadClass(true, "class B {}", "class", "B"); }), - a -> assertEditOutput(a, "/e 1", - "| Replaced enum A\n" + - "| Update overwrote class A\n", () -> { + a -> assertEditOutput(a, "/ed 1", + "| replaced enum A", () -> { writeSource("enum A {}"); exit(); loadClass(true, "enum A {}", "enum", "A"); }), - a -> assertCommandCheckOutput(a, "/c", assertClasses()) + a -> assertCommandCheckOutput(a, "/classes", assertClasses()) ); } @@ -171,14 +169,13 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditMethod1() { testEditor( a -> assertMethod(a, "void f() {}", "()void", "f"), - a -> assertEditOutput(a, "/e 1", "", () -> { + a -> assertEditOutput(a, "/ed 1", "", () -> { writeSource("\n\n\nvoid f() {}\n\n\n"); exit(); loadMethod(true, "void f() {}", "()void", "f"); }), - a -> assertEditOutput(a, "/e 1", - "| Replaced method f()\n" + - "| Update overwrote method f()\n", () -> { + a -> assertEditOutput(a, "/ed 1", + "| replaced method f()", () -> { writeSource("double f() { return 0; }"); exit(); loadMethod(true, "double f() { return 0; }", "()double", "f"); @@ -191,14 +188,13 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testEditMethod2() { testEditor( a -> assertMethod(a, "void f() {}", "()void", "f"), - a -> assertEditOutput(a, "/e 1", "| Added method g()\n", () -> { + a -> assertEditOutput(a, "/ed 1", "| created method g()", () -> { writeSource("void g() {}"); exit(); loadMethod(true, "void g() {}", "()void", "g"); }), - a -> assertEditOutput(a, "/e 1", - "| Replaced method f()\n" + - "| Update overwrote method f()\n", () -> { + a -> assertEditOutput(a, "/ed 1", + "| replaced method f()", () -> { writeSource("double f() { return 0; }"); exit(); loadMethod(true, "double f() { return 0; }", "()double", "f"); @@ -213,7 +209,7 @@ public abstract class EditorTestBase extends ReplToolTesting { a -> assertVariable(a, "int", "a"), a -> assertMethod(a, "void f() {}", "()void", "f"), a -> assertClass(a, "class A {}", "class", "A"), - a -> assertEditInput(a, "/e", s -> { + a -> assertEditInput(a, "/ed", s -> { String[] ss = s.split("\n"); assertEquals(ss.length, 3, "Expected 3 lines: " + s); assertEquals(ss[0], "int a;"); @@ -226,15 +222,15 @@ public abstract class EditorTestBase extends ReplToolTesting { @Test public void testStartup() { testEditor(true, new String[0], - a -> assertEditInput(a, "/e", s -> assertTrue(s.isEmpty(), "Checking of startup: " + s), this::cancel), - a -> assertEditInput(a, "/e printf", assertStartsWith("void printf"), this::cancel)); + a -> assertEditInput(a, "/ed", s -> assertTrue(s.isEmpty(), "Checking of startup: " + s), this::cancel), + a -> assertEditInput(a, "/ed printf", assertStartsWith("void printf"), this::cancel)); } @Test public void testCancel() { testEditor( a -> assertVariable(a, "int", "a"), - a -> assertEditOutput(a, "/e a", "", () -> { + a -> assertEditOutput(a, "/ed a", "", () -> { writeSource("int b = 10"); cancel(); }) @@ -245,7 +241,7 @@ public abstract class EditorTestBase extends ReplToolTesting { public void testAccept() { testEditor( a -> assertVariable(a, "int", "a"), - a -> assertEditOutput(a, "/e a", "| Added variable b of type int with initial value 10\n", () -> { + a -> assertEditOutput(a, "/ed a", "b ==> 10", () -> { writeSource("int b = 10"); accept(); exit(); diff --git a/langtools/test/jdk/jshell/ExternalEditorTest.java b/langtools/test/jdk/jshell/ExternalEditorTest.java index a794c7e57af..5d1d63979b8 100644 --- a/langtools/test/jdk/jshell/ExternalEditorTest.java +++ b/langtools/test/jdk/jshell/ExternalEditorTest.java @@ -24,8 +24,9 @@ /* * @test * @summary Testing external editor. - * @bug 8080843 + * @bug 8080843 8143955 * @ignore 8080843 + * @modules jdk.jshell/jdk.internal.jshell.tool * @build ReplToolTesting CustomEditor EditorTestBase * @run testng ExternalEditorTest */ @@ -124,7 +125,7 @@ public class ExternalEditorTest extends EditorTestBase { } @BeforeClass - public static void setUp() throws IOException { + public static void setUpExternalEditorTest() throws IOException { listener = new ServerSocket(0); listener.setSoTimeout(30000); int localPort = listener.getLocalPort(); @@ -193,11 +194,11 @@ public class ExternalEditorTest extends EditorTestBase { @Test public void setUnknownEditor() { test( - a -> assertCommand(a, "/set editor", "| /set editor requires a path argument\n"), - a -> assertCommand(a, "/set editor UNKNOWN", "| Editor set to: UNKNOWN\n"), + a -> assertCommand(a, "/set editor", "| The '/set editor' command requires a path argument"), + a -> assertCommand(a, "/set editor UNKNOWN", "| Editor set to: UNKNOWN"), a -> assertCommand(a, "int a;", null), - a -> assertCommand(a, "/e 1", - "| Edit Error: process IO failure: Cannot run program \"UNKNOWN\": error=2, No such file or directory\n") + a -> assertCommand(a, "/ed 1", + "| Edit Error: process IO failure: Cannot run program \"UNKNOWN\": error=2, No such file or directory") ); } diff --git a/langtools/test/jdk/jshell/ReplToolTesting.java b/langtools/test/jdk/jshell/ReplToolTesting.java index 1448fc4a5be..a2be490511c 100644 --- a/langtools/test/jdk/jshell/ReplToolTesting.java +++ b/langtools/test/jdk/jshell/ReplToolTesting.java @@ -273,8 +273,7 @@ public class ReplToolTesting { } public void evaluateExpression(boolean after, String type, String expr, String value) { - String output = String.format("\\| *Expression values is: %s\n|" + - " *.*temporary variable (\\$\\d+) of type %s", value, type); + String output = String.format("(\\$\\d+) ==> %s", value); Pattern outputPattern = Pattern.compile(output); assertCommandCheckOutput(after, expr, s -> { Matcher matcher = outputPattern.matcher(s); @@ -558,14 +557,19 @@ public class ReplToolTesting { @Override public Consumer checkOutput() { - String pattern = String.format("\\| *\\w+ variable %s of type %s", name, type); - if (initialValue != null) { - pattern += " with initial value " + initialValue; - } - Predicate checkOutput = Pattern.compile(pattern).asPredicate(); - final String finalPattern = pattern; - return output -> assertTrue(checkOutput.test(output), - "Output: " + output + " does not fit pattern: " + finalPattern); + String arrowPattern = String.format("%s ==> %s", name, value); + Predicate arrowCheckOutput = Pattern.compile(arrowPattern).asPredicate(); + String howeverPattern = String.format("\\| *\\w+ variable %s, however*.", name); + Predicate howeverCheckOutput = Pattern.compile(howeverPattern).asPredicate(); + return output -> { + if (output.startsWith("| ")) { + assertTrue(howeverCheckOutput.test(output), + "Output: " + output + " does not fit pattern: " + howeverPattern); + } else { + assertTrue(arrowCheckOutput.test(output), + "Output: " + output + " does not fit pattern: " + arrowPattern); + } + }; } @Override diff --git a/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java b/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java index c04598b8627..101083c0e27 100644 --- a/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java +++ b/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java @@ -37,8 +37,8 @@ import org.testng.annotations.Test; public class JShellToolTest8146368 extends ReplToolTesting { public void test() { test( - a -> assertCommand(a, "class A extends B {}", "| Added class A, however, it cannot be referenced until class B is declared\n"), - a -> assertCommand(a, "und m() { return new und(); }", "| Added method m(), however, it cannot be referenced until class und is declared\n") + a -> assertCommand(a, "class A extends B {}", "| created class A, however, it cannot be referenced until class B is declared\n"), + a -> assertCommand(a, "und m() { return new und(); }", "| created method m(), however, it cannot be referenced until class und is declared\n") ); } } diff --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index 538b3030177..9d162d39c31 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -23,9 +23,13 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 + * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 * @summary Tests for Basic tests for REPL tool * @requires os.family != "solaris" + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @ignore 8139873 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask @@ -176,23 +180,23 @@ public class ToolBasicTest extends ReplToolTesting { } assertOutput(getCommandOutput(), "", "command"); assertOutput(getCommandErrorOutput(), "", "command error"); - assertOutput(getUserOutput(), output, "user"); + assertOutput(getUserOutput().trim(), output, "user"); assertOutput(getUserErrorOutput(), "", "user error"); } } public void testStop() { test( - (a) -> assertStop(a, "while (true) {}", "Killed.\n"), - (a) -> assertStop(a, "while (true) { try { Thread.sleep(100); } catch (InterruptedException ex) { } }", "Killed.\n") + (a) -> assertStop(a, "while (true) {}", "Killed."), + (a) -> assertStop(a, "while (true) { try { Thread.sleep(100); } catch (InterruptedException ex) { } }", "Killed.") ); } @Test(enabled = false) // TODO 8130450 public void testRerun() { test(false, new String[] {"-nostartup"}, - (a) -> assertCommand(a, "/0", "| No such command or snippet id: /0\n| Type /help for help.\n"), - (a) -> assertCommand(a, "/5", "| No such command or snippet id: /5\n| Type /help for help.\n") + (a) -> assertCommand(a, "/0", "| No such command or snippet id: /0\n| Type /help for help."), + (a) -> assertCommand(a, "/5", "| No such command or snippet id: /5\n| Type /help for help.") ); String[] codes = new String[] { "int a = 0;", // var @@ -251,99 +255,9 @@ public class ToolBasicTest extends ReplToolTesting { ); test(false, new String[] {"-nostartup"}, - (a) -> assertCommand(a, "/s1", "| No such command or snippet id: /s1\n| Type /help for help.\n"), - (a) -> assertCommand(a, "/1", "| No such command or snippet id: /1\n| Type /help for help.\n"), - (a) -> assertCommand(a, "/e1", "| No such command or snippet id: /e1\n| Type /help for help.\n") - ); - } - - public void testRemaining() { - test( - (a) -> assertCommand(a, "int z; z =", "| Added variable z of type int\n"), - (a) -> assertCommand(a, "5", "| Variable z has been assigned the value 5\n"), - (a) -> assertCommand(a, "/*nada*/; int q =", ""), - (a) -> assertCommand(a, "77", "| Added variable q of type int with initial value 77\n"), - (a) -> assertCommand(a, "//comment;", ""), - (a) -> assertCommand(a, "int v;", "| Added variable v of type int\n"), - (a) -> assertCommand(a, "int v; int c", "| Added variable c of type int\n") - ); - } - - public void oneLineOfError() { - test( - (a) -> assertCommand(a, "12+", null), - (a) -> assertCommandCheckOutput(a, " true", (s) -> - assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'")) - ); - } - - public void defineVariables() { - test( - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), - (a) -> assertVariable(a, "int", "a"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), - (a) -> assertVariable(a, "double", "a", "1", "1.0"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), - (a) -> evaluateExpression(a, "double", "2 * a", "2.0"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()) - ); - } - - public void defineMethods() { - test( - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), - (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), - (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), - (a) -> assertMethod(a, "void g() {}", "()void", "g"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) - ); - } - - public void defineClasses() { - test( - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), - (a) -> assertClass(a, "class A { }", "class", "A"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), - (a) -> assertClass(a, "interface A { }", "interface", "A"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), - (a) -> assertClass(a, "enum A { }", "enum", "A"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), - (a) -> assertClass(a, "@interface A { }", "@interface", "A"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()) - ); - } - - public void defineImports() { - test( - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), - (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), - (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), - (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), - (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"), - (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) + (a) -> assertCommand(a, "/s1", "| No such command or snippet id: /s1\n| Type /help for help."), + (a) -> assertCommand(a, "/1", "| No such command or snippet id: /1\n| Type /help for help."), + (a) -> assertCommand(a, "/e1", "| No such command or snippet id: /e1\n| Type /help for help.") ); } @@ -353,14 +267,14 @@ public class ToolBasicTest extends ReplToolTesting { compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }"); Path classpath = compiler.getPath(outDir); test( - (a) -> assertCommand(a, "/classpath " + classpath, String.format("| Path %s added to classpath\n", classpath)), - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> assertCommand(a, "/classpath " + classpath, String.format("| Path '%s' added to classpath", classpath)), + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); test(new String[] { "-cp", classpath.toString() }, - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); test(new String[] { "-classpath", classpath.toString() }, - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); } @@ -372,14 +286,14 @@ public class ToolBasicTest extends ReplToolTesting { compiler.jar(outDir, jarName, "pkg/A.class"); Path jarPath = compiler.getPath(outDir).resolve(jarName); test( - (a) -> assertCommand(a, "/classpath " + jarPath, String.format("| Path %s added to classpath\n", jarPath)), - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> assertCommand(a, "/classpath " + jarPath, String.format("| Path '%s' added to classpath", jarPath)), + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); test(new String[] { "-cp", jarPath.toString() }, - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); test(new String[] { "-classpath", jarPath.toString() }, - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") ); } @@ -389,7 +303,7 @@ public class ToolBasicTest extends ReplToolTesting { Path startup = compiler.getPath("StartupFileOption/startup.txt"); compiler.writeToFile(startup, "class A { public String toString() { return \"A\"; } }"); test(new String[]{"-startup", startup.toString()}, - (a) -> evaluateExpression(a, "A", "new A()", "\"A\"\n") + (a) -> evaluateExpression(a, "A", "new A()", "A") ); test(new String[]{"-nostartup"}, (a) -> assertCommandCheckOutput(a, "printf(\"\")", assertStartsWith("| Error:\n| cannot find symbol")) @@ -406,18 +320,18 @@ public class ToolBasicTest extends ReplToolTesting { Path path = compiler.getPath("loading.repl"); compiler.writeToFile(path, "int a = 10; double x = 20; double a = 10;"); test(new String[] { path.toString() }, - (a) -> assertCommand(a, "x", "| Variable x of type double has value 20.0\n"), - (a) -> assertCommand(a, "a", "| Variable a of type double has value 10.0\n") + (a) -> assertCommand(a, "x", "x ==> 20.0"), + (a) -> assertCommand(a, "a", "a ==> 10.0") ); Path unknown = compiler.getPath("UNKNOWN.jar"); test(Locale.ROOT, true, new String[]{unknown.toString()}, "| File " + unknown - + " is not found: " + unresolvableMessage(unknown) + "\n"); + + " is not found: " + unresolvableMessage(unknown)); } public void testReset() { test( - (a) -> assertReset(a, "/r"), + (a) -> assertReset(a, "/res"), (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertVariable(a, "int", "x"), (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), @@ -444,8 +358,8 @@ public class ToolBasicTest extends ReplToolTesting { for (String s : new String[]{"/o", "/open"}) { test( (a) -> assertCommand(a, s + " " + path.toString(), ""), - (a) -> assertCommand(a, "a", "| Variable a of type double has value 10.0\n"), - (a) -> evaluateExpression(a, "A", "new A();", "\"A\""), + (a) -> assertCommand(a, "a", "a ==> 10.0"), + (a) -> evaluateExpression(a, "A", "new A();", "A"), (a) -> evaluateExpression(a, "long", "Stream.of(\"A\").count();", "1"), (a) -> { loadVariable(a, "double", "x", "20.0", "20.0"); @@ -464,8 +378,7 @@ public class ToolBasicTest extends ReplToolTesting { Path unknown = compiler.getPath("UNKNOWN.repl"); test( (a) -> assertCommand(a, s + " " + unknown, - "| File '" + unknown - + "' is not found: " + unresolvableMessage(unknown) + "\n") + "| File '" + unknown + "' for '/open' is not found.") ); } } @@ -529,8 +442,8 @@ public class ToolBasicTest extends ReplToolTesting { ); Path unknown = compiler.getPath("UNKNOWN"); test( - (a) -> assertCommand(a, "/set start " + unknown.toString(), - "| File '" + unknown + "' for /set start is not found.\n") + (a) -> assertCommandOutputStartsWith(a, "/set start " + unknown.toString(), + "| File '" + unknown + "' for '/set start' is not found.") ); test(false, new String[0], (a) -> { @@ -556,28 +469,6 @@ public class ToolBasicTest extends ReplToolTesting { } } - public void testUnknownCommand() { - test((a) -> assertCommand(a, "/unknown", - "| No such command or snippet id: /unknown\n" + - "| Type /help for help.\n")); - } - - public void testEmptyClassPath() { - test(after -> assertCommand(after, "/classpath", "| /classpath requires a path argument\n")); - } - - public void testNoArgument() { - String[] commands = {"/save", "/open", "/set start"}; - test(Stream.of(commands) - .map(cmd -> { - String c = cmd; - final String finalC = c; - return (ReplTest) after -> assertCommand(after, cmd, - "| The " + finalC + " command requires a filename argument.\n"); - }) - .toArray(ReplTest[]::new)); - } - public void testStartSave() throws IOException { Compiler compiler = new Compiler(); Path startSave = compiler.getPath("startSave.txt"); @@ -614,8 +505,8 @@ public class ToolBasicTest extends ReplToolTesting { assertStartsWith("| Does not match any current feedback mode"))); } - public void testFeedbackOff() { - for (String off : new String[]{"o", "off"}) { + public void testFeedbackSilent() { + for (String off : new String[]{"s", "silent"}) { test( a -> assertCommand(a, "/set feedback " + off, ""), a -> assertCommand(a, "int a", ""), @@ -632,16 +523,16 @@ public class ToolBasicTest extends ReplToolTesting { String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; String[] sources2 = new String[] {"int a //again", "void f() {int y = 4;}", "class A {} //again", "a = 10"}; String[] output = new String[] { - "| Added variable a of type int\n", - "| Added method f()\n", - "| Added class A\n", - "| Variable a has been assigned the value 10\n" + "a ==> 0", + "| created method f()", + "| created class A", + "a ==> 10" }; compiler.writeToFile(testNormalFile, sources2); - for (String feedback : new String[]{"/set f", "/set feedback"}) { - for (String feedbackState : new String[]{"n", "normal", "o", "off"}) { + for (String feedback : new String[]{"/set fe", "/set feedback"}) { + for (String feedbackState : new String[]{"n", "normal"}) { test( - a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: normal\n"), + a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: normal"), a -> assertCommand(a, sources[0], output[0]), a -> assertCommand(a, sources[1], output[1]), a -> assertCommand(a, sources[2], output[2]), @@ -652,87 +543,21 @@ public class ToolBasicTest extends ReplToolTesting { } } - public void testDrop() { - test(false, new String[]{"-nostartup"}, - a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/drop 1", "int a = 0", "| Dropped variable a\n"), - a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop 2", "b ()I", "| Dropped method b()\n"), - a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/drop 3", "class A", "| Dropped class A\n"), - a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""), - a -> assertCommandCheckOutput(a, "/vars", assertVariables()), - a -> assertCommandCheckOutput(a, "/methods", assertMethods()), - a -> assertCommandCheckOutput(a, "/classes", assertClasses()), - a -> assertCommandCheckOutput(a, "/imports", assertImports()) - ); - test(false, new String[]{"-nostartup"}, - a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/drop a", "int a = 0", "| Dropped variable a\n"), - a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), - a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/drop A", "class A", "| Dropped class A\n"), - a -> assertCommandCheckOutput(a, "/vars", assertVariables()), - a -> assertCommandCheckOutput(a, "/methods", assertMethods()), - a -> assertCommandCheckOutput(a, "/classes", assertClasses()), - a -> assertCommandCheckOutput(a, "/imports", assertImports()) - ); - } - - public void testDropNegative() { - test(false, new String[]{"-nostartup"}, - a -> assertCommand(a, "/drop 0", "| No definition or id named 0 found. See /classes, /methods, /vars, or /list\n"), - a -> assertCommand(a, "/drop a", "| No definition or id named a found. See /classes, /methods, /vars, or /list\n"), - a -> assertCommandCheckOutput(a, "/drop", - assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), - a -> assertVariable(a, "int", "a"), - a -> assertCommand(a, "a", "| Variable a of type int has value 0\n"), - a -> assertCommand(a, "/drop 2", "| The argument did not specify an active import, variable, method, or class to drop.\n") - ); - } - - public void testAmbiguousDrop() { - Consumer check = s -> { - assertTrue(s.startsWith("| The argument references more than one import, variable, method, or class"), s); - int lines = s.split("\n").length; - assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s); - }; - test( - a -> assertVariable(a, "int", "a"), - a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), - a -> assertClass(a, "class a {}", "class", "a"), - a -> assertCommandCheckOutput(a, "/drop a", check), - a -> assertCommandCheckOutput(a, "/vars", assertVariables()), - a -> assertCommandCheckOutput(a, "/methods", assertMethods()), - a -> assertCommandCheckOutput(a, "/classes", assertClasses()), - a -> assertCommandCheckOutput(a, "/imports", assertImports()) - ); - test( - a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), - a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), - a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), - a -> assertCommandCheckOutput(a, "/drop a", check), - a -> assertCommandCheckOutput(a, "/methods", assertMethods()) - ); - } - public void testHistoryReference() { test(false, new String[]{"-nostartup"}, a -> assertCommand(a, "System.err.println(1)", "", "", null, "", "1\n"), a -> assertCommand(a, "System.err.println(2)", "", "", null, "", "2\n"), - a -> assertCommand(a, "/-2", "System.err.println(1)\n", "", null, "", "1\n"), - a -> assertCommand(a, "/history", "\n" + + a -> assertCommand(a, "/-2", "System.err.println(1)", "", null, "", "1\n"), + a -> assertCommand(a, "/history", "/debug 0\n" + "System.err.println(1)\n" + "System.err.println(2)\n" + "System.err.println(1)\n" + "/history\n"), - a -> assertCommand(a, "/-2", "System.err.println(2)\n", "", null, "", "2\n"), - a -> assertCommand(a, "/!", "System.err.println(2)\n", "", null, "", "2\n"), - a -> assertCommand(a, "/2", "System.err.println(2)\n", "", null, "", "2\n"), - a -> assertCommand(a, "/1", "System.err.println(1)\n", "", null, "", "1\n") + a -> assertCommand(a, "/-2", "System.err.println(2)", "", null, "", "2\n"), + a -> assertCommand(a, "/!", "System.err.println(2)", "", null, "", "2\n"), + a -> assertCommand(a, "/2", "System.err.println(2)", "", null, "", "2\n"), + a -> assertCommand(a, "/1", "System.err.println(1)", "", null, "", "1\n") ); } @@ -744,14 +569,4 @@ public class ToolBasicTest extends ReplToolTesting { return ex.getMessage(); } } - - public void testCommandPrefix() { - test(a -> assertCommandCheckOutput(a, "/s", - assertStartsWith("| Command: /s is ambiguous: /save, /set")), - a -> assertCommand(a, "int var", "| Added variable var of type int\n"), - a -> assertCommandCheckOutput(a, "/va", - assertStartsWith("| int var = 0")), - a -> assertCommandCheckOutput(a, "/save", - assertStartsWith("| The /save command requires a filename argument."))); - } } diff --git a/langtools/test/jdk/jshell/ToolReloadTest.java b/langtools/test/jdk/jshell/ToolReloadTest.java index 1dfb8b775b1..6779fc1eafb 100644 --- a/langtools/test/jdk/jshell/ToolReloadTest.java +++ b/langtools/test/jdk/jshell/ToolReloadTest.java @@ -24,7 +24,7 @@ /* * @test * @key intermittent - * @bug 8081845 8147898 + * @bug 8081845 8147898 8143955 * @summary Tests for /reload in JShell tool * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -71,7 +71,7 @@ public class ToolReloadTest extends ReplToolTesting { Path classpath = compiler.getPath(outDir); test( (a) -> assertCommand(a, "/classpath " + classpath, - String.format("| Path '%s' added to classpath\n", classpath)), + String.format("| Path '%s' added to classpath", classpath)), (a) -> assertMethod(a, "String foo() { return (new pkg.A()).toString(); }", "()String", "foo"), (a) -> assertVariable(a, "String", "v", "foo()", "\"A\""), @@ -83,20 +83,20 @@ public class ToolReloadTest extends ReplToolTesting { "-: String foo() { return (new pkg.A()).toString(); }\n" + "-: String v = foo();\n"); }, - (a) -> assertCommand(a, "v", "| Variable v of type String has value \"Aprime\"\n"), + (a) -> assertCommand(a, "v", "v ==> \"Aprime\""), (a) -> evaluateExpression(a, "String", "foo()", "\"Aprime\""), - (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"Aprime\"") + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "Aprime") ); } public void testReloadDrop() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/dr 1", "int a = 0", "| Dropped variable a\n"), + a -> dropVariable(a, "/dr 1", "int a = 0", "| dropped variable a"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), + a -> dropMethod(a, "/drop b", "b ()I", "| dropped method b()"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/dr A", "class A", "| Dropped class A\n"), + a -> dropClass(a, "/dr A", "class A", "| dropped class A"), a -> assertCommand(a, "/reload", "| Restarting and restoring state.\n" + "-: int a;\n" + @@ -115,13 +115,13 @@ public class ToolReloadTest extends ReplToolTesting { public void testReloadQuiet() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/dr 1", "int a = 0", "| Dropped variable a\n"), + a -> dropVariable(a, "/dr 1", "int a = 0", "| dropped variable a"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), + a -> dropMethod(a, "/drop b", "b ()I", "| dropped method b()"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/dr A", "class A", "| Dropped class A\n"), + a -> dropClass(a, "/dr A", "class A", "| dropped class A"), a -> assertCommand(a, "/reload quiet", - "| Restarting and restoring state.\n"), + "| Restarting and restoring state."), a -> assertCommandCheckOutput(a, "/vars", assertVariables()), a -> assertCommandCheckOutput(a, "/methods", assertMethods()), a -> assertCommandCheckOutput(a, "/classes", assertClasses()), @@ -144,8 +144,8 @@ public class ToolReloadTest extends ReplToolTesting { "-: ++c\n" + "-: ++c\n" ), - (a) -> assertCommand(a, "c", "| Variable c of type int has value 11\n"), - (a) -> assertCommand(a, "$4", "| Variable $4 of type int has value 10\n") + (a) -> assertCommand(a, "c", "c ==> 11"), + (a) -> assertCommand(a, "$4", "$4 ==> 10") ); } @@ -158,7 +158,7 @@ public class ToolReloadTest extends ReplToolTesting { (a) -> assertCommand(a, "/vars", null), (a) -> assertCommand(a, "/save abcd", null), (a) -> assertCommand(a, "/reload", - "| Restarting and restoring state.\n") + "| Restarting and restoring state.") ); } @@ -168,7 +168,7 @@ public class ToolReloadTest extends ReplToolTesting { (a) -> assertMethod(a, "int m(int z) { return z * z; }", "(int)int", "m"), (a) -> evaluateExpression(a, "int", "m(x)", "25"), - (a) -> assertCommand(a, "/reset", "| Resetting state.\n"), + (a) -> assertCommand(a, "/reset", "| Resetting state."), (a) -> assertCommand(a, "/reload restore", "| Restarting and restoring from previous state.\n" + "-: int x = 5;\n" + @@ -188,7 +188,7 @@ public class ToolReloadTest extends ReplToolTesting { (a) -> evaluateExpression(a, "int", "m(x)", "25"), (a) -> assertCommand(a, "System.exit(1);", "| State engine terminated.\n" + - "| Restore definitions with: /reload restore\n"), + "| Restore definitions with: /reload restore"), (a) -> assertCommand(a, "/reload restore", "| Restarting and restoring from previous state.\n" + "-: int x = 5;\n" + diff --git a/langtools/test/jdk/jshell/ToolSimpleTest.java b/langtools/test/jdk/jshell/ToolSimpleTest.java index 15a56093873..069e571fa41 100644 --- a/langtools/test/jdk/jshell/ToolSimpleTest.java +++ b/langtools/test/jdk/jshell/ToolSimpleTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8153716 + * @bug 8153716 8143955 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -47,10 +47,102 @@ import static org.testng.Assert.assertTrue; @Test public class ToolSimpleTest extends ReplToolTesting { + public void testRemaining() { + test( + (a) -> assertCommand(a, "int z; z =", "z ==> 0"), + (a) -> assertCommand(a, "5", "z ==> 5"), + (a) -> assertCommand(a, "/*nada*/; int q =", ""), + (a) -> assertCommand(a, "77", "q ==> 77"), + (a) -> assertCommand(a, "//comment;", ""), + (a) -> assertCommand(a, "int v;", "v ==> 0"), + (a) -> assertCommand(a, "int v; int c", + "v ==> 0\n" + + "c ==> 0") + ); + } + + public void oneLineOfError() { + test( + (a) -> assertCommand(a, "12+", null), + (a) -> assertCommandCheckOutput(a, " true", (s) -> + assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'")) + ); + } + + public void defineVariables() { + test( + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertVariable(a, "int", "a"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertVariable(a, "double", "a", "1", "1.0"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> evaluateExpression(a, "double", "2 * a", "2.0"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()) + ); + } + + public void defineMethods() { + test( + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertMethod(a, "void g() {}", "()void", "g"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); + } + + public void defineClasses() { + test( + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), + (a) -> assertClass(a, "class A { }", "class", "A"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), + (a) -> assertClass(a, "interface A { }", "interface", "A"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), + (a) -> assertClass(a, "enum A { }", "enum", "A"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), + (a) -> assertClass(a, "@interface A { }", "@interface", "A"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()) + ); + } + + public void defineImports() { + test( + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), + (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), + (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), + (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), + (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"), + (a) -> assertCommandCheckOutput(a, "/list", assertList()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + } + public void defineVar() { test( - (a) -> assertCommand(a, "int x = 72", "| Added variable x of type int with initial value 72"), - (a) -> assertCommand(a, "x", "| Variable x of type int has value 72"), + (a) -> assertCommand(a, "int x = 72", "x ==> 72"), + (a) -> assertCommand(a, "x", "x ==> 72"), (a) -> assertCommand(a, "/vars", "| int x = 72") ); } @@ -59,7 +151,7 @@ public class ToolSimpleTest extends ReplToolTesting { public void defineUnresolvedVar() { test( (a) -> assertCommand(a, "undefined x", - "| Added variable x, however, it cannot be referenced until class undefined is declared"), + "| created variable x, however, it cannot be referenced until class undefined is declared"), (a) -> assertCommand(a, "/vars", "| undefined x = (not-active)") ); } @@ -67,15 +159,37 @@ public class ToolSimpleTest extends ReplToolTesting { public void testUnresolved() { test( (a) -> assertCommand(a, "int f() { return g() + x + new A().a; }", - "| Added method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"), + "| created method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"), (a) -> assertCommand(a, "f()", - "| Attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"), + "| attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"), (a) -> assertCommandOutputStartsWith(a, "int g() { return x; }", - "| Added method g(), however, it cannot be invoked until variable x is declared"), - (a) -> assertCommand(a, "g()", "| Attempted to call method g() which cannot be invoked until variable x is declared") + "| created method g(), however, it cannot be invoked until variable x is declared"), + (a) -> assertCommand(a, "g()", "| attempted to call method g() which cannot be invoked until variable x is declared") ); } + public void testUnknownCommand() { + test((a) -> assertCommand(a, "/unknown", + "| No such command or snippet id: /unknown\n" + + "| Type /help for help.")); + } + + public void testEmptyClassPath() { + test(after -> assertCommand(after, "/classpath", "| The /classpath command requires a path argument.")); + } + + public void testNoArgument() { + String[] commands = {"/save", "/open", "/set start"}; + test(Stream.of(commands) + .map(cmd -> { + String c = cmd; + final String finalC = c; + return (ReplTest) after -> assertCommand(after, cmd, + "| '" + finalC + "' requires a filename argument."); + }) + .toArray(ReplTest[]::new)); + } + public void testDebug() { test( (a) -> assertCommand(a, "/deb", "| Debugging on"), @@ -85,6 +199,72 @@ public class ToolSimpleTest extends ReplToolTesting { ); } + public void testDrop() { + test(false, new String[]{"-nostartup"}, + a -> assertVariable(a, "int", "a"), + a -> dropVariable(a, "/drop 1", "int a = 0", "| dropped variable a"), + a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), + a -> dropMethod(a, "/drop 2", "b ()I", "| dropped method b()"), + a -> assertClass(a, "class A {}", "class", "A"), + a -> dropClass(a, "/drop 3", "class A", "| dropped class A"), + a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), + a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + test(false, new String[]{"-nostartup"}, + a -> assertVariable(a, "int", "a"), + a -> dropVariable(a, "/drop a", "int a = 0", "| dropped variable a"), + a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), + a -> dropMethod(a, "/drop b", "b ()I", "| dropped method b()"), + a -> assertClass(a, "class A {}", "class", "A"), + a -> dropClass(a, "/drop A", "class A", "| dropped class A"), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + } + + public void testDropNegative() { + test(false, new String[]{"-nostartup"}, + a -> assertCommandOutputStartsWith(a, "/drop 0", "| No definition or id found named: 0"), + a -> assertCommandOutputStartsWith(a, "/drop a", "| No definition or id found named: a"), + a -> assertCommandCheckOutput(a, "/drop", + assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), + a -> assertVariable(a, "int", "a"), + a -> assertCommand(a, "a", "a ==> 0"), + a -> assertCommand(a, "/drop 2", "| The argument did not specify an active import, variable, method, or class to drop.") + ); + } + + public void testAmbiguousDrop() { + Consumer check = s -> { + assertTrue(s.startsWith("| The argument references more than one import, variable, method, or class"), s); + int lines = s.split("\n").length; + assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s); + }; + test( + a -> assertVariable(a, "int", "a"), + a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), + a -> assertClass(a, "class a {}", "class", "a"), + a -> assertCommandCheckOutput(a, "/drop a", check), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + test( + a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), + a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), + a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), + a -> assertCommandCheckOutput(a, "/drop a", check), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); + } + public void testHelpLength() { Consumer testOutput = (s) -> { List ss = Stream.of(s.split("\n")) @@ -148,6 +328,16 @@ public class ToolSimpleTest extends ReplToolTesting { ); } + public void testCommandPrefix() { + test(a -> assertCommandCheckOutput(a, "/s", + assertStartsWith("| Command: '/s' is ambiguous: /save, /set")), + a -> assertCommand(a, "int var", "var ==> 0"), + a -> assertCommandCheckOutput(a, "/va", + assertStartsWith("| int var = 0")), + a -> assertCommandCheckOutput(a, "/save", + assertStartsWith("| '/save' requires a filename argument."))); + } + public void testHeadlessEditPad() { String prevHeadless = System.getProperty("java.awt.headless"); try { diff --git a/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarAwareSJFM.java b/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarAwareSJFM.java new file mode 100644 index 00000000000..b4475468846 --- /dev/null +++ b/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarAwareSJFM.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8149757 + * @summary Test that StandardJavaFileManager uses the correct version of a + * class from a multi-release jar on classpath + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox + * @run testng MultiReleaseJarAwareSJFM + */ + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; + +import toolbox.JarTask; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class MultiReleaseJarAwareSJFM { + + private final String version8 = + "package version;\n" + + "\n" + + "public class Version {\n" + + " public int getVersion() {\n" + + " return 8;\n" + + " }\n" + + "}\n"; + + private final String version9 = + "package version;\n" + + "\n" + + "public class Version {\n" + + " public int getVersion() {\n" + + " int version = (new PackagePrivate()).getVersion();\n" + + " if (version == 9) return 9;\n" + + " return version;\n" + + " }\n" + + "}\n"; + + private final String packagePrivate = + "package version;\n" + + "\n" + + "class PackagePrivate {\n" + + " int getVersion() {\n" + + " return 9;\n" + + " }\n" + + "}\n"; + + private final String version10 = + "package version;\n" + + "\n" + + "public class Version {\n" + + " public int getVersion() {\n" + + " return 10;\n" + + " }\n" + + "}\n"; + + private final String manifest = + "Manifest-Version: 1.0\n" + + "Multi-Release: true\n"; + + private final ToolBox tb = new ToolBox(); + + private final JavaFileManager.Location jloc = new JavaFileManager.Location() { + @Override + public String getName() { + return "Multi-Release Jar"; + } + @Override + public boolean isOutputLocation() { + return false; + } + }; + + @BeforeClass + public void setup() throws Exception { + tb.createDirectories("classes", + "classes/META-INF/versions/9", + "classes/META-INF/versions/10"); + new JavacTask(tb) + .outdir("classes") + .sources(version8) + .run(); + new JavacTask(tb) + .outdir("classes/META-INF/versions/9") + .sources(version9, packagePrivate) + .run(); + new JavacTask(tb) + .outdir("classes/META-INF/versions/10") + .sources(version10) + .run(); + new JarTask(tb, "multi-release.jar") + .manifest(manifest) + .baseDir("classes") + .files("version/Version.class", + "META-INF/versions/9/version/Version.class", + "META-INF/versions/9/version/PackagePrivate.class", + "META-INF/versions/10/version/Version.class") + .run(); + } + + @AfterClass + public void teardown() throws Exception { + tb.deleteFiles( + "classes/META-INF/versions/10/version/Version.class", + "classes/META-INF/versions/10/version", + "classes/META-INF/versions/10/", + "classes/META-INF/versions/9/version/Version.class", + "classes/META-INF/versions/9/version/PackagePrivate.class", + "classes/META-INF/versions/9/version", + "classes/META-INF/versions/9", + "classes/META-INF/versions", + "classes/META-INF", + "classes/version/Version.class", + "classes/version", + "classes", + "multi-release.jar" + ); + } + + @DataProvider(name = "versions") + public Object[][] data() { + return new Object[][] { + {"", 8}, + {"8", 8}, + {"9", 9}, + {"runtime", jdk.Version.current().major()} + }; + } + + @Test(dataProvider = "versions") + public void test(String version, int expected) throws Throwable { + StandardJavaFileManager jfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null); + jfm.setLocation(jloc, List.of(new File("multi-release.jar"))); + + if (version.length() > 0) { + jfm.handleOption("-multi-release", List.of(version).iterator()); + } + + CustomClassLoader cldr = new CustomClassLoader(jfm); + Class versionClass = cldr.loadClass("version.Version"); + MethodType mt = MethodType.methodType(int.class); + MethodHandle mh = MethodHandles.lookup().findVirtual(versionClass, "getVersion", mt); + int v = (int)mh.invoke(versionClass.newInstance()); + Assert.assertEquals(v, expected); + + jfm.close(); + } + + private class CustomClassLoader extends ClassLoader { + private final JavaFileManager jfm; + + public CustomClassLoader(JavaFileManager jfm) { + super(null); + this.jfm = jfm; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + int n = name.lastIndexOf('.'); + String pkg = n == -1 ? "" : name.substring(0, n); + String cls = name.substring(n + 1) + ".class"; + byte[] b; + try { + FileObject obj = jfm.getFileForInput(jloc, pkg, cls); + try (InputStream is = obj.openInputStream()) { + b = is.readAllBytes(); + } + } catch (IOException x) { + throw new ClassNotFoundException(x.getMessage(), x); + } + return defineClass(name, b, 0, b.length); + } + } +} + diff --git a/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java b/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java new file mode 100644 index 00000000000..39e14ab1057 --- /dev/null +++ b/langtools/test/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8149757 + * @summary Test that javac uses the correct version of a class from a + * multi-release jar on classpath + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @run testng MultiReleaseJarTest + */ + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import toolbox.JarTask; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + + +public class MultiReleaseJarTest { + + private final String main1 = + "class Main {\n" + + " Info info = new Info();\n" + + " \n" + + " void run() {\n" + + " System.out.println(info.get());\n" + + " }\n" + + "}\n"; + + private final String main2 = + "class Main {\n" + + " Info info = new Info();\n" + + " \n" + + " void run() {\n" + + " System.out.println(info.getInfo());\n" + + " }\n" + + "}\n"; + + private final String info1 = + "class Info {\n" + + " String get() {\n" + + " return \"some info\";\n" + + " }\n" + + "}\n"; + + private final String info2 = + "class Info {\n" + + " String getInfo() {\n" + + " return \"some info\";\n" + + " }\n" + + "}\n"; + + private final String manifest = + "Manifest-Version: 1.0\n" + + "Multi-Release: true\n"; + + private final ToolBox tb = new ToolBox(); + + @BeforeClass + public void setup() throws Exception { + tb.createDirectories("classes", "classes/META-INF/versions/9"); + new JavacTask(tb) + .outdir("classes") + .sources(info1) + .run(); + new JavacTask(tb) + .outdir("classes/META-INF/versions/9") + .sources(info2) + .run(); + // This is a bogus multi-release jar file since the two Info classes + // do not have the same public interface + new JarTask(tb, "multi-release.jar") + .manifest(manifest) + .baseDir("classes") + .files("Info.class", "META-INF/versions/9/Info.class") + .run(); + tb.deleteFiles( + "classes/META-INF/versions/9/Info.class", + "classes/META-INF/versions/9", + "classes/META-INF/versions", + "classes/META-INF", + "classes/Info.class" + ); + } + + @AfterClass + public void teardown() throws Exception { + tb.deleteFiles( + "multi-release.jar", + "classes/Main.class", + "classes" + ); + } + + @Test(dataProvider="modes") + // javac -d classes -cp multi-release.jar Main.java -> fails + public void main1Runtime(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main1); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .classpath("multi-release.jar") + .files("Main.java") + .run(Task.Expect.FAIL, 1); + result.writeAll(); + tb.deleteFiles("Main.java"); + + } + + @Test(dataProvider="modes") + // javac -d classes -release 8 -cp multi-release.jar Main.java -> succeeds + public void main1Release8(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main1); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .options("-release", "8") + .classpath("multi-release.jar") + .files("Main.java") + .run(); + result.writeAll(); + tb.deleteFiles("Main.java"); + } + + @Test(dataProvider="modes") + // javac -d classes -release 9 -cp multi-release.jar Main.java -> fails + public void main1Release9(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main1); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .options("-release", "9") + .classpath("multi-release.jar") + .files("Main.java") + .run(Task.Expect.FAIL, 1); + result.writeAll(); + tb.deleteFiles("Main.java"); + } + + @Test(dataProvider="modes") + // javac -d classes -cp multi-release.jar Main.java -> succeeds + public void main2Runtime(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main2); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .classpath("multi-release.jar") + .files("Main.java") + .run(); + result.writeAll(); + tb.deleteFiles("Main.java"); + + } + + @Test(dataProvider="modes") + // javac -d classes -release 8 -cp multi-release.jar Main.java -> fails + public void main2Release8(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main2); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .options("-release", "8") + .classpath("multi-release.jar") + .files("Main.java") + .run(Task.Expect.FAIL, 1); + result.writeAll(); + tb.deleteFiles("Main.java"); + } + + @Test(dataProvider="modes") + // javac -d classes -release 9 -cp multi-release.jar Main.java -> succeeds + public void main2Release9(Task.Mode mode) throws Exception { + tb.writeFile("Main.java", main2); + Task.Result result = new JavacTask(tb, mode) + .outdir("classes") + .options("-release", "9") + .classpath("multi-release.jar") + .files("Main.java") + .run(); + result.writeAll(); + tb.deleteFiles("Main.java"); + } + + @DataProvider(name="modes") + public Object[][] createModes() { + return new Object[][] { + new Object[] {Task.Mode.API}, + new Object[] {Task.Mode.CMDLINE}, + new Object[] {Task.Mode.EXEC}, + }; + } +} + diff --git a/langtools/test/tools/javac/unit/T6198196.java b/langtools/test/tools/javac/unit/T6198196.java index deef60b02fd..6c67c513584 100644 --- a/langtools/test/tools/javac/unit/T6198196.java +++ b/langtools/test/tools/javac/unit/T6198196.java @@ -36,34 +36,31 @@ import javax.tools.*; public class T6198196 { static String pkginf = "package-info"; - static StandardJavaFileManager fm; - static void test(String pathname, String filename, boolean result) { - JavaFileObject fo; - fo = fm.getJavaFileObjectsFromStrings(Arrays.asList(pathname)).iterator().next(); - if (result != fo.isNameCompatible(filename, JavaFileObject.Kind.SOURCE)) - throw new AssertionError("endsWith(" + pathname + ", " - + filename + ") != " + result); - System.out.format("OK: endsWith(%s, %s) = %s%n", pathname, filename, result); - } - public static void main(String[] args) throws IOException { - fm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null); - try { - boolean windows = System.getProperty("os.name").startsWith("Windows"); - test("/x/y/z/package-info.java", pkginf, true); - if (windows) { - test("\\x\\y\\z\\package-info.java", pkginf, true); - test("..\\x\\y\\z\\package-info.java", pkginf, true); - } else { - test("\\x\\y\\z\\package-info.java", pkginf, false); - test("..\\x\\y\\z\\package-info.java", pkginf, false); - } - test("Package-info.java", pkginf, false); - test("../x/y/z/package-info.java", pkginf, true); - test("/x/y/z/package-info.java", pkginf, true); - test("x/y/z/package-info.java", pkginf, true); - test("package-info.java", pkginf, true); - } finally { - fm.close(); + static void test(String pathname, String filename, boolean result) throws IOException { + try (StandardJavaFileManager fm = + ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)) { + JavaFileObject fo = + fm.getJavaFileObjectsFromStrings(Arrays.asList(pathname)).iterator().next(); + if (result != fo.isNameCompatible(filename, JavaFileObject.Kind.SOURCE)) + throw new AssertionError("endsWith(" + pathname + ", " + + filename + ") != " + result); + System.out.format("OK: endsWith(%s, %s) = %s%n", pathname, filename, result); } } + public static void main(String[] args) throws IOException { + boolean windows = System.getProperty("os.name").startsWith("Windows"); + test("/x/y/z/package-info.java", pkginf, true); + if (windows) { + test("\\x\\y\\z\\package-info.java", pkginf, true); + test("..\\x\\y\\z\\package-info.java", pkginf, true); + } else { + test("\\x\\y\\z\\package-info.java", pkginf, false); + test("..\\x\\y\\z\\package-info.java", pkginf, false); + } + test("Package-info.java", pkginf, false); + test("../x/y/z/package-info.java", pkginf, true); + test("/x/y/z/package-info.java", pkginf, true); + test("x/y/z/package-info.java", pkginf, true); + test("package-info.java", pkginf, true); + } } diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 306b7c88bc6..c4275f863e3 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -469,32 +469,7 @@ jdk.localedata_EXCLUDE_FILES += sun/text/resources/th/BreakIteratorRules_th.java ################################################################################ # Setup the compilation for the module # -# Order src dirs in order of override with the most important first. Generated -# source before static source and platform specific source before shared. -# -GENERATED_SRC_DIRS += \ - $(SUPPORT_OUTPUTDIR)/gensrc \ - # - -TOP_SRC_DIRS += \ - $(HOTSPOT_TOPDIR)/src \ - $(CORBA_TOPDIR)/src \ - $(JDK_TOPDIR)/src \ - $(LANGTOOLS_TOPDIR)/src \ - $(JAXP_TOPDIR)/src \ - $(JAXWS_TOPDIR)/src \ - $(NASHORN_TOPDIR)/src \ - # - -SRC_SUBDIRS += $(OPENJDK_TARGET_OS)/classes -ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE)) - SRC_SUBDIRS += $(OPENJDK_TARGET_OS_TYPE)/classes -endif -SRC_SUBDIRS += share/classes - -MODULE_SRC_DIRS := $(strip \ - $(addsuffix /$(MODULE), $(GENERATED_SRC_DIRS) $(IMPORT_MODULES_SRC)) \ - $(foreach sub, $(SRC_SUBDIRS), $(addsuffix /$(MODULE)/$(sub), $(TOP_SRC_DIRS)))) +MODULE_SRC_DIRS := $(call FindModuleSrcDirs, $(MODULE)) # The JDK_USER_DEFINED_FILTER is a poor man's incremental build: by specifying # JDK_FILTER at the make command line, only a subset of the JDK java files will @@ -502,27 +477,20 @@ MODULE_SRC_DIRS := $(strip \ # space separated list. JDK_USER_DEFINED_FILTER := $(strip $(subst $(COMMA),$(SPACE), $(JDK_FILTER))) -# Rewrite the MODULE_SRC_DIRS with a wildcard for the module so that all module -# source dirs are available on the path. -MODULESOURCEPATH := $(subst $(SPACE),$(PATH_SEP),$(subst $(MODULE),*,$(MODULE_SRC_DIRS))) +# Get the complete module source path. +MODULESOURCEPATH := $(call GetModuleSrcPath) -# Add imported modules to the moduleclasspath -MODULECLASSPATH := $(subst $(SPACE),$(PATH_SEP), $(IMPORT_MODULES_CLASSES)) +# Add imported modules to the modulepath +MODULEPATH := $(call PathList, $(IMPORT_MODULES_CLASSES)) ifeq ($(MODULE), jdk.vm.ci) ## WORKAROUND jdk.vm.ci source structure issue JVMCI_MODULESOURCEPATH := $(MODULESOURCEPATH) \ $(subst /$(MODULE)/,/*/, $(filter-out %processor/src, \ $(wildcard $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes/*/src))) - MODULESOURCEPATH := $(subst $(SPACE),$(PATH_SEP), $(JVMCI_MODULESOURCEPATH)) + MODULESOURCEPATH := $(call PathList, $(JVMCI_MODULESOURCEPATH)) endif -# Make sure the generated source base dirs exist. Not all modules have generated -# source in all of these directories and because of timing, all of them might not -# exist at the time this makefile gets called. Javac will complain if there are -# missing directories in the moduleclasspath. -$(call MakeDir, $(GENERATED_SRC_DIRS)) - $(eval $(call SetupJavaCompilation, $(MODULE), \ SETUP := $(if $($(MODULE)_SETUP), $($(MODULE)_SETUP), GENERATE_JDKBYTECODE), \ MODULE := $(MODULE), \ @@ -532,8 +500,8 @@ $(eval $(call SetupJavaCompilation, $(MODULE), \ HEADERS := $(SUPPORT_OUTPUTDIR)/headers, \ ADD_JAVAC_FLAGS := \ $($(MODULE)_ADD_JAVAC_FLAGS) \ - -modulesourcepath "$(MODULESOURCEPATH)" \ - $(if $(MODULECLASSPATH), -modulepath "$(MODULECLASSPATH)") \ + -modulesourcepath $(MODULESOURCEPATH) \ + -modulepath $(MODULEPATH) \ -system none, \ )) @@ -574,8 +542,9 @@ endif ifneq ($(wildcard $(IMPORT_MODULES_CLASSES)/$(MODULE)), ) $(JDK_OUTPUTDIR)/modules/$(MODULE)/_imported.marker: \ $(call CacheFind, $(IMPORT_MODULES_CLASSES)/$(MODULE)) - $(RM) -r $(@D) - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) + # Do not delete marker and build meta data files + $(RM) -r $(filter-out $(@D)/_%, $(wildcard $(@D)/*)) $(CP) -R $(IMPORT_MODULES_CLASSES)/$(MODULE)/* $(@D)/ $(TOUCH) $@ diff --git a/make/GensrcModuleInfo.gmk b/make/GensrcModuleInfo.gmk index b53fc5a1256..84bed9e8985 100644 --- a/make/GensrcModuleInfo.gmk +++ b/make/GensrcModuleInfo.gmk @@ -49,7 +49,6 @@ default: all include $(SPEC) include MakeBase.gmk include Modules.gmk -#include TextFileProcessing.gmk ################################################################################ # Define this here since jdk/make/Tools.gmk cannot be included from the top @@ -64,25 +63,8 @@ TOOL_GENMODULEINFOSOURCE = $(JAVA_SMALL) \ # Name of data file. Keep module-info.java.ext until javafx has changed. MOD_FILENAME := module-info.java.extra module-info.java.ext -# List all the possible sub directories inside a module source directory where -# data might be stored. -CLASSES_SUBDIRS += $(OPENJDK_TARGET_OS)/classes -ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE)) - CLASSES_SUBDIRS += $(OPENJDK_TARGET_OS_TYPE)/classes -endif -CLASSES_SUBDIRS += share/classes - -# TODO: When the deploy build is better integrated, this will get added globally -# but for now need to add it here. -ifeq ($(BUILD_DEPLOY), true) - ALL_TOP_SRC_DIRS += $(DEPLOY_TOPDIR)/src -endif - # Construct all possible src directories for the module. -MODULE_CLASSES_DIRS := $(strip \ - $(foreach sub, $(CLASSES_SUBDIRS), \ - $(addsuffix /$(MODULE)/$(sub), $(ALL_TOP_SRC_DIRS))) \ - $(addsuffix /$(MODULE), $(IMPORT_MODULES_SRC))) +MODULE_CLASSES_DIRS := $(call FindModuleSrcDirs, $(MODULE)) # Find all the .extra files in the src dirs. MOD_FILES := $(wildcard $(foreach f, $(MOD_FILENAME), $(addsuffix /$(f), \ @@ -125,20 +107,6 @@ ifneq ($(MOD_FILES), ) TARGETS += $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java endif -# This doesn't work because javac only accepts one single exports line per -# exported package. - # Restore the modifications to separate lines with spaces -# MODIFICATIONS := $(subst /,$(SPACE),$(MODIFICATIONS)) - -# ifneq ($(MODIFICATIONS), ) -# $(eval $(call SetupTextFileProcessing, PROCESS_MODULE_INFO, \ -# SOURCE_FILES := $(firstword $(call FindAllModuleInfos, $(MODULE))), \ -# OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java, \ -# REPLACEMENTS := } => $(MODIFICATIONS) }, \ -# )) - -# TARGETS += $(PROCESS_MODULE_INFO) -# endif endif # If no modifications are found for this module, remove any module-info.java diff --git a/make/Javadoc.gmk b/make/Javadoc.gmk index 4ab8d5a0b21..2998dbf5242 100644 --- a/make/Javadoc.gmk +++ b/make/Javadoc.gmk @@ -235,6 +235,11 @@ JDK_API_DOCSDIR = $(DOCSDIR)/jdk/api JRE_API_DOCSDIR = $(DOCSDIR)/jre/api PLATFORM_DOCSDIR = $(DOCSDIR)/platform +JAVADOC_ARCHIVE_NAME := jdk-$(VERSION_STRING)-docs.zip +JAVADOC_ARCHIVE_ASSEMBLY_DIR := $(DOCSTMPDIR)/zip-docs +JAVADOC_ARCHIVE_DIR := $(OUTPUT_ROOT)/bundles +JAVADOC_ARCHIVE := $(JAVADOC_ARCHIVE_DIR)/$(JAVADOC_ARCHIVE_NAME) + # The core api index file is the target for the core api javadocs rule # and needs to be defined early so that all other javadoc rules may # depend on it. @@ -378,6 +383,13 @@ $(eval $(call IncludeCustomExtension, , Javadoc.gmk)) all: docs docs: coredocs otherdocs +# +# Optional target which bundles all generated javadocs into a zip archive. +# The dependency on docs is handled in Main.gmk. +# + +zip-docs: $(JAVADOC_ARCHIVE) + ############################################################# # # coredocs @@ -1671,6 +1683,28 @@ $(JLINK_PLUGIN_PACKAGES_FILE): $(call PackageDependencies,$(JLINK_PLUGIN_PKGS)) otherdocs: $(ALL_OTHER_TARGETS) +# +# Add the core docs as prerequisite to the archive to trigger a rebuild +# if the core docs were rebuilt. Ideally any doc rebuild should trigger +# this, but the way prerequisites are currently setup in this file, that +# is hard to achieve. +# + +$(JAVADOC_ARCHIVE): $(COREAPI_INDEX_FILE) + $(call LogInfo, Compressing javadoc to single $(JAVADOC_ARCHIVE_NAME)) + $(MKDIR) -p $(JAVADOC_ARCHIVE_DIR) + $(RM) -r $(JAVADOC_ARCHIVE_ASSEMBLY_DIR) + $(MKDIR) -p $(JAVADOC_ARCHIVE_ASSEMBLY_DIR) + all_roots=`$(FIND) $(DOCSDIR) | $(GREP) index.html | grep -v old/doclet`; \ + pushd $(JAVADOC_ARCHIVE_ASSEMBLY_DIR); \ + for index_file in $${all_roots} ; do \ + target_dir=`dirname $${index_file}`; \ + name=`$(ECHO) $${target_dir} | $(SED) "s;/spec;;" | $(SED) "s;.*/;;"`; \ + $(LN) -s $${target_dir} $${name}; \ + done; \ + $(ZIP) -q -r $(JAVADOC_ARCHIVE) * ; \ + popd ; + ############################################################# .PHONY: all docs coredocs otherdocs \ - $(ALL_OTHER_TARGETS) + $(ALL_OTHER_TARGETS) zip-docs diff --git a/make/Main.gmk b/make/Main.gmk index 045a1da46c7..2bb6bab68bf 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -333,6 +333,9 @@ docs-javadoc: docs-jvmtidoc: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk jvmtidocs) +zip-docs: docs-javadoc docs-jvmtidoc + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk zip-docs) + ALL_TARGETS += docs-javadoc docs-jvmtidoc ################################################################################ @@ -385,9 +388,27 @@ test-image-jdk-jtreg-native: build-test-lib: +($(CD) $(TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) -f BuildTestLib.gmk) +ifeq ($(BUILD_FAILURE_HANDLER), true) + # Builds the failure handler jtreg extension + build-test-failure-handler: + +($(CD) $(TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) \ + -f BuildFailureHandler.gmk build) + + # Runs the tests for the failure handler jtreg extension + test-failure-handler: + +($(CD) $(TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) \ + -f BuildFailureHandler.gmk test) + + # Copies the failure handler jtreg extension into the test image + test-image-failure-handler: + +($(CD) $(TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) \ + -f BuildFailureHandler.gmk images) +endif + ALL_TARGETS += prepare-test-image build-test-hotspot-jtreg-native \ test-image-hotspot-jtreg-native build-test-jdk-jtreg-native \ - test-image-jdk-jtreg-native build-test-lib + test-image-jdk-jtreg-native build-test-lib build-test-failure-handler \ + test-failure-handler test-image-failure-handler ################################################################################ # Run tests @@ -582,6 +603,12 @@ else build-test-lib: java + build-test-failure-handler: interim-langtools + + test-failure-handler: build-test-failure-handler + + test-image-failure-handler: build-test-failure-handler + build-test-hotspot-jtreg-native: buildtools-jdk build-test-jdk-jtreg-native: buildtools-jdk @@ -667,11 +694,11 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) endif # This target builds the documentation image -docs-image: docs-javadoc docs-jvmtidoc +docs-image: zip-docs # This target builds the test image test-image: prepare-test-image test-image-hotspot-jtreg-native \ - test-image-jdk-jtreg-native + test-image-jdk-jtreg-native test-image-failure-handler # all-images is the top-most target, it builds all our deliverables ("images"). all-images: product-images test-image docs-image @@ -691,7 +718,7 @@ images: product-images docs: docs-image all: all-images -ALL_TARGETS += default jdk images docs all +ALL_TARGETS += default jdk images docs all zip-docs ################################################################################ ################################################################################ diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk index 9d5865d2b2c..d09331a0962 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -104,6 +104,7 @@ define Clean-docs @$(PRINTF) "\n" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/docs $(RM) -r $(IMAGES_OUTPUTDIR)/docs + $(RM) $(OUTPUT_ROOT)/bundles/jdk-*-docs.zip @$(PRINTF) " done\n" endef diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 7ed52135f28..d97169007e2 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -723,12 +723,13 @@ else endif ################################################################################ -# Return a string suitable for use after a -classpath option. It will correct and safe to use -# on all platforms. Arguments are given as space separate classpath entries. +# Return a string suitable for use after a -classpath or -modulepath option. It +# will be correct and safe to use on all platforms. Arguments are given as space +# separate classpath entries. Safe for multiple nested calls. # param 1 : A space separated list of classpath entries # The surrounding strip is needed to keep additional whitespace out PathList = \ - "$(subst $(SPACE),$(PATH_SEP),$(strip $1))" + "$(subst $(SPACE),$(PATH_SEP),$(strip $(subst $(DQUOTE),,$1)))" ################################################################################ diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 5930e2627a3..cba267b0075 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -138,26 +138,35 @@ endif ################################################################################ # Module list macros -# Use append so that the custom extension may add to this variable +# Use append so that the custom extension may add to these variables -ALL_TOP_SRC_DIRS += \ +GENERATED_SRC_DIRS += \ + $(SUPPORT_OUTPUTDIR)/gensrc \ + # + +TOP_SRC_DIRS += \ + $(CORBA_TOPDIR)/src \ $(HOTSPOT_TOPDIR)/src \ $(JDK_TOPDIR)/src \ $(LANGTOOLS_TOPDIR)/src \ - $(CORBA_TOPDIR)/src \ $(JAXP_TOPDIR)/src \ $(JAXWS_TOPDIR)/src \ $(NASHORN_TOPDIR)/src \ # +SRC_SUBDIRS += $(OPENJDK_TARGET_OS)/classes +ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE)) + SRC_SUBDIRS += $(OPENJDK_TARGET_OS_TYPE)/classes +endif +SRC_SUBDIRS += share/classes + # Find all module-info.java files for the current build target platform and # configuration. # Param 1 - Module to find for, set to * for finding all FindAllModuleInfos = \ $(wildcard \ - $(patsubst %,%/$(strip $1)/$(OPENJDK_TARGET_OS)/classes/module-info.java, $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %,%/$(strip $1)/$(OPENJDK_TARGET_OS_TYPE)/classes/module-info.java, $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %,%/$(strip $1)/share/classes/module-info.java, $(ALL_TOP_SRC_DIRS)) \ + $(foreach sub, $(SRC_SUBDIRS), \ + $(patsubst %,%/$(strip $1)/$(sub)/module-info.java, $(TOP_SRC_DIRS))) \ $(patsubst %,%/$(strip $1)/module-info.java, $(IMPORT_MODULES_SRC))) # Extract the module names from the paths of module-info.java files. The @@ -178,6 +187,19 @@ FindAllModules = \ FindImportedModules = \ $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*))) +# Find all source dirs for a particular module +# $1 - Module to find source dirs for +FindModuleSrcDirs = \ + $(strip $(wildcard \ + $(addsuffix /$(strip $1), $(GENERATED_SRC_DIRS) $(IMPORT_MODULES_SRC)) \ + $(foreach sub, $(SRC_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS))))) + +# Construct the complete module source path +GetModuleSrcPath = \ + $(call PathList, \ + $(addsuffix /*, $(GENERATED_SRC_DIRS) $(IMPORT_MODULES_SRC)) \ + $(foreach sub, $(SRC_SUBDIRS), $(addsuffix /*/$(sub), $(TOP_SRC_DIRS)))) + ################################################################################ # Extract module dependencies from module-info.java files. diff --git a/make/jprt.properties b/make/jprt.properties index c00d85159eb..943f15b5be5 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -311,13 +311,13 @@ my.build.flavors.hotspot= \ # Platforms built for hotspot push jobs my.build.targets.hotspot= \ - solaris_sparcv9_5.11-{product|fastdebug}, \ + solaris_sparcv9_5.11-{product|fastdebug}, \ solaris_x64_5.11-{product|fastdebug}, \ linux_i586_3.8-{product|fastdebug}, \ - linux_x64_3.8-{product|fastdebug}, \ + linux_x64_3.8-{product|fastdebug}, \ macosx_x64_10.9-{product|fastdebug}, \ windows_i586_6.3-{product|fastdebug}, \ - windows_x64_6.3-{product|fastdebug}, \ + windows_x64_6.3-{product|fastdebug}, \ solaris_x64_5.11-{fastdebugOpen}, \ linux_x64_3.8-{productOpen}, \ ${my.additional.build.targets.hotspot} @@ -346,18 +346,15 @@ my.test.targets.hotspot.solaris.x64= \ solaris_x64_5.11-{product|fastdebug}-c2-GCBasher_G1 my.test.targets.hotspot.linux.i586= \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-jvm98, \ + linux_i586_3.8-{product|fastdebug}-c2-jvm98, \ linux_i586_3.8-{product|fastdebug}-c2-jvm98_nontiered, \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-scimark, \ - linux_i586_3.8-product-c1-runThese8_Xcomp_lang, \ - linux_i586_3.8-product-c1-runThese8_Xcomp_vm, \ - linux_i586_3.8-fastdebug-c1-runThese8_Xshare, \ + linux_i586_3.8-{product|fastdebug}-c2-scimark, \ linux_i586_3.8-fastdebug-c2-runThese8_Xcomp_lang, \ linux_i586_3.8-fastdebug-c2-runThese8_Xcomp_vm, \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - linux_i586_3.8-{product|fastdebug}-{c1|c2}-GCBasher_G1 + linux_i586_3.8-{product|fastdebug}-c2-GCBasher_SerialGC, \ + linux_i586_3.8-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + linux_i586_3.8-{product|fastdebug}-c2-GCBasher_CMS, \ + linux_i586_3.8-{product|fastdebug}-c2-GCBasher_G1 my.test.targets.hotspot.linux.x64= \ linux_x64_3.8-{product|fastdebug}-c2-jvm98, \ @@ -378,17 +375,16 @@ my.test.targets.hotspot.macosx.x64= \ macosx_x64_10.9-{product|fastdebug}-c2-GCBasher_G1 my.test.targets.hotspot.windows.i586= \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-jvm98, \ + windows_i586_6.3-{product|fastdebug}-c2-jvm98, \ windows_i586_6.3-{product|fastdebug}-c2-jvm98_nontiered, \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-scimark, \ - windows_i586_6.3-product-{c1|c2}-runThese8, \ - windows_i586_6.3-product-{c1|c2}-runThese8_Xcomp_lang, \ - windows_i586_6.3-product-{c1|c2}-runThese8_Xcomp_vm, \ - windows_i586_6.3-fastdebug-c1-runThese8_Xshare, \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - windows_i586_6.3-{product|fastdebug}-{c1|c2}-GCBasher_G1 + windows_i586_6.3-{product|fastdebug}-c2-scimark, \ + windows_i586_6.3-product-c2-runThese8, \ + windows_i586_6.3-product-c2-runThese8_Xcomp_lang, \ + windows_i586_6.3-product-c2-runThese8_Xcomp_vm, \ + windows_i586_6.3-{product|fastdebug}-c2-GCBasher_SerialGC, \ + windows_i586_6.3-{product|fastdebug}-c2-GCBasher_ParallelGC, \ + windows_i586_6.3-{product|fastdebug}-c2-GCBasher_CMS, \ + windows_i586_6.3-{product|fastdebug}-c2-GCBasher_G1 my.test.targets.hotspot.windows.x64= \ windows_x64_6.3-{product|fastdebug}-c2-jvm98, \ @@ -443,22 +439,21 @@ my.make.rule.test.targets.hotspot.reg.group= \ linux_x64_3.8-fastdebug-c2-GROUP, \ macosx_x64_10.9-fastdebug-c2-GROUP, \ windows_i586_6.3-fastdebug-c2-GROUP, \ - windows_x64_6.3-fastdebug-c2-GROUP, \ - linux_i586_3.8-fastdebug-c1-GROUP, \ - windows_i586_6.3-fastdebug-c1-GROUP + windows_x64_6.3-fastdebug-c2-GROUP # Hotspot jtreg tests -my.make.rule.test.targets.hotspot.reg= \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_1}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_2}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_3}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_closed}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_gc}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_gc_closed}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_gc_gcold}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_runtime}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_serviceability}, \ - ${my.make.rule.test.targets.hotspot.reg.group:GROUP=jdk_svc_sanity}, \ +my.make.rule.test.targets.hotspot.reg= \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_compiler_1}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_compiler_2}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_compiler_3}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_compiler_closed}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_gc_1}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_gc_2}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_gc_closed}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_gc_gcold}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_runtime}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_fast_serviceability}, \ + ${my.make.rule.test.targets.hotspot.reg.group:GROUP=jdk_svc_sanity}, \ ${my.additional.make.rule.test.targets.hotspot.reg} # Other Makefile based Hotspot tests diff --git a/make/test/BuildFailureHandler.gmk b/make/test/BuildFailureHandler.gmk new file mode 100644 index 00000000000..e64541fb6e2 --- /dev/null +++ b/make/test/BuildFailureHandler.gmk @@ -0,0 +1,128 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +default: build + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk +include NativeCompilation.gmk + +TARGETS := + +################################################################################ + +FH_BASEDIR := $(SRC_ROOT)/test/failure_handler +FH_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/failure_handler +FH_JAR := $(FH_SUPPORT)/jtregFailureHandler.jar + +JTREG_JAR := $(JT_HOME)/lib/jtreg.jar +ifeq ($(wildcard $(JTREG_JAR)), ) + $(error Cannot build failure handler without jtreg) +endif +# tools.jar is only needed if it exists in the boot jdk +TOOLS_JAR := $(wildcard $(BOOT_JDK)/lib/tools.jar) + +FH_CLASSPATH := $(call PathList, $(JTREG_JAR) $(TOOLS_JAR)) + +$(eval $(call SetupJavaCompilation, BUILD_FAILURE_HANDLER, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(FH_BASEDIR)/src/share/classes $(FH_BASEDIR)/src/share/conf, \ + BIN := $(FH_SUPPORT)/classes, \ + COPY := .properties, \ + CLASSPATH := $(JTREG_JAR) $(TOOLS_JAR), \ + JAR := $(FH_JAR), \ +)) + +TARGETS += $(BUILD_FAILURE_HANDLER) + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), windows) + + $(eval $(call SetupNativeCompilation, BUILD_LIBTIMEOUT_HANDLER, \ + LIBRARY := timeoutHandler, \ + SRC := $(FH_BASEDIR)/src/windows/native/libtimeoutHandler, \ + OBJECT_DIR := $(FH_SUPPORT)/libtimeoutHandler, \ + OUTPUT_DIR := $(FH_SUPPORT), \ + CFLAGS := $(CFLAGS_JDKLIB), \ + LDFLAGS := $(LDFLAGS_JDKLIB), \ + OPTIMIZATION := LOW, \ + )) + + TARGETS += $(BUILD_LIBTIMEOUT_HANDLER) + +endif + +################################################################################ +# Targets for building test-image. +################################################################################ + +# Copy to hotspot jtreg test image +$(eval $(call SetupCopyFiles, COPY_FH, \ + SRC := $(FH_SUPPORT), \ + DEST := $(TEST_IMAGE_DIR)/failure_handler, \ + FILES := $(FH_JAR) $(BUILD_LIBTIMEOUT_HANDLER), \ +)) + +IMAGES_TARGETS += $(COPY_FH) + +################################################################################ +# Test the failure handler itself +################################################################################ +# +# Use JTREG_TEST_OPTS for test VM options +# Use JTREG_TESTS for jtreg tests parameter +# +RUN_DIR := $(FH_SUPPORT)/test +# Add the dir of the dll to the path on windows +ifeq ($(OPENJDK_TARGET_OS), windows) + export PATH := $(PATH);$(FH_SUPPORT) +endif + +test: + $(RM) -r $(RUN_DIR) + $(MKDIR) -p $(RUN_DIR) + $(CD) $(FH_BASEDIR)/test && JT_JAVA=$(BOOT_JDK) $(JTREGEXE) \ + -jdk:$(BOOT_JDK) \ + $(JTREG_TEST_OPTS) \ + -timeout:0.1 -va -retain:all \ + -noreport \ + -agentvm \ + -thd:$(FH_JAR) \ + -th:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \ + -od:$(FH_JAR) \ + -o:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ + -w:$(RUN_DIR)/JTwork -r:$(RUN_DIR)/JTreport \ + $(if $(JTREG_TESTS), $(JTREG_TESTS), .) \ + || true + +################################################################################ + +build: $(TARGETS) +images: $(IMAGES_TARGETS) + +.PHONY: all images test diff --git a/nashorn/.hgtags b/nashorn/.hgtags index d023255c9e0..5d1fa7fb250 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -347,3 +347,4 @@ cfb3167456932b14c16a6d4cffd5fe295fbe01ff jdk-9+106 133ea8746b37739a0510c80b42888bd85ace9477 jdk-9+111 c261f8440c5578b34596e6b0419a81aec431a884 jdk-9+112 a5d1990fd32d908da8154d79116fce8013ba4d40 jdk-9+113 +ba21793a0e4816283cc0ecdab5142a4959363529 jdk-9+114 diff --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java index 035b492d751..75c5065d525 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java @@ -111,7 +111,7 @@ import jdk.dynalink.linker.LinkRequest; import jdk.dynalink.linker.LinkerServices; import jdk.dynalink.linker.support.Guards; import jdk.dynalink.linker.support.Lookup; -import sun.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitive; /** * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java index 54d2e12620f..59389e99d83 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java @@ -72,7 +72,7 @@ import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome; -import sun.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitive; /** * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}. diff --git a/test/failure_handler/Makefile b/test/failure_handler/Makefile index 00f34c26511..49352cbc762 100644 --- a/test/failure_handler/Makefile +++ b/test/failure_handler/Makefile @@ -29,7 +29,7 @@ BUILD_DIR := $(shell pwd)/build CLASSES_DIR := ${BUILD_DIR}/classes IMAGE_DIR := ${BUILD_DIR}/image RUN_DIR := $(shell pwd)/run - +CLASSPATH := ${JTREG_HOME}/lib/jtreg.jar:${JAVA_HOME}/lib/tools.jar SRC_DIR := src/share/classes/ SOURCES := ${SRC_DIR}/jdk/test/failurehandler/*.java \ ${SRC_DIR}/jdk/test/failurehandler/action/*.java \ @@ -47,9 +47,12 @@ OS_NAME := $(shell uname -o 2>&1) ifeq ("${OS_NAME}", "Cygwin") BUILD_DIR := $(shell cygpath -m "${BUILD_DIR}") CLASSES_DIR := $(shell cygpath -m "${CLASSES_DIR}") -IMAGE_DIR := $(shell cygpath -m "${IMAGE_DIR}") RUN_DIR := $(shell cygpath -m "${RUN_DIR}") +IMAGE_DIR := $(shell cygpath -m "${IMAGE_DIR}") +RUN_DIR := $(shell cygpath -m "${RUN_DIR}") SRC_DIR := $(shell cygpath -m "${SRC_DIR}") +JAVA_HOME := $(shell cygpath -m "${JAVA_HOME}") JTREG_HOME := $(shell cygpath -m "${JTREG_HOME}") +CLASSPATH := $(shell cygpath -pm "${CLASSPATH}") CC := "cl.exe" endif @@ -57,33 +60,33 @@ all: clean test native: require_env ifeq ("${OS_NAME}", "Cygwin") - "${CC}" src/windows/native/jdk/test/failurehandler/jtreg/*.c \ - -I"$(shell cygpath -w ${JAVA_HOME}/include)" \ - -I"$(shell cygpath -w ${JAVA_HOME}/include/win32)" \ - /link /MACHINE:X64 /DLL /OUT:timeoutHandler.dll + "${CC}" src/windows/native/jdk/test/failurehandler/jtreg/*.c \ + -I"$(shell cygpath -w "${JAVA_HOME}/include")" \ + -I"$(shell cygpath -w "${JAVA_HOME}/include/win32")" \ + /link /DLL /OUT:timeoutHandler.dll endif check_defined = $(foreach 1,$1,$(__check_defined)) __check_defined = $(if $(value $1),, $(error $1 is not set)) classes: require_env - mkdir -p ${IMAGE_DIR}/bin ${IMAGE_DIR}/lib ${CLASSES_DIR} - "${JAVA_HOME}"/bin/javac -target ${JAVA_RELEASE} -source ${JAVA_RELEASE} \ - -sourcepath $(shell pwd) \ - -classpath ${JTREG_HOME}/lib/jtreg.jar:${JAVA_HOME}/lib/tools.jar \ - -d ${CLASSES_DIR} \ + mkdir -p ${IMAGE_DIR}/bin ${IMAGE_DIR}/lib ${CLASSES_DIR} + "${JAVA_HOME}"/bin/javac -target ${JAVA_RELEASE} -source ${JAVA_RELEASE} \ + -sourcepath "$(shell pwd)" \ + -cp "${CLASSPATH}" \ + -d ${CLASSES_DIR} \ ${SOURCES} - "${JAVA_HOME}"/bin/jar cf ${TARGET_JAR} -C ${CLASSES_DIR} . - "${JAVA_HOME}"/bin/jar uf ${TARGET_JAR} -C ${CONF_DIR} . + "${JAVA_HOME}"/bin/jar cf "${TARGET_JAR}" -C "${CLASSES_DIR}" . + "${JAVA_HOME}"/bin/jar uf "${TARGET_JAR}" -C "${CONF_DIR}" . # # Use JTREG_TEST_OPTS for test VM options # Use JTREG_TESTS for jtreg tests parameter # test: require_env build - rm -rf ${RUN_DIR} - mkdir -p ${RUN_DIR} - "${JTREG_HOME}"/bin/jtreg \ + rm -rf "${RUN_DIR}" + mkdir -p "${RUN_DIR}" + "${JTREG_HOME}"/bin/jtreg \ -jdk:"${JAVA_HOME}" \ ${JTREG_TEST_OPTS} \ -timeout:0.1 -va -retain:all \ @@ -93,7 +96,8 @@ test: require_env build -th:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \ -od:"${TARGET_JAR}" \ -o:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ - -w:${RUN_DIR}/JTwork -r:${RUN_DIR}/JTreport \ + -w:"${RUN_DIR}/JTwork" \ + -r:"${RUN_DIR}/JTreport" \ $(if ${JTREG_TESTS}, ${JTREG_TESTS}, test) \ && false || true @@ -101,11 +105,11 @@ debug: JTREG_TEST_OPTS += "-J-agentlib:jdwp=transport=dt_socket,server=y,suspend debug: test require_env: - $(call check_defined, JAVA_HOME) - $(call check_defined, JTREG_HOME) + $(call check_defined, JAVA_HOME) + $(call check_defined, JTREG_HOME) clean: - rm -rf "${BUILD_DIR}" "${RUN_DIR}" + rm -rf "${BUILD_DIR}" "${RUN_DIR}" build: classes native diff --git a/test/failure_handler/README b/test/failure_handler/README index ca3e72705d2..8929cc21667 100644 --- a/test/failure_handler/README +++ b/test/failure_handler/README @@ -36,11 +36,9 @@ The library requires jtreg 4b13+ and JDK 7+. BUILDING -To build a library, one should simply run make with 'JTREG_HOME' and -'JAVA_HOME' environment variables set. 'JAVA_HOME' should contain path to JDK, -'JTREG_HOME' -- path to jtreg. - -'image/lib/jtregFailureHandler.jar' is created on successful build. +The library is built using the top level build-test-failure-handler target and +is automatically included in the test image and picked up by hotspot and jdk +test makefiles. CONFIGURATION diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java index a16b4e734d7..c08418073fe 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java @@ -39,12 +39,16 @@ import java.nio.file.Path; * process and its children. */ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler { + private static final boolean HAS_NATIVE_LIBRARY; static { + boolean value = true; try { System.loadLibrary("timeoutHandler"); } catch (UnsatisfiedLinkError ignore) { // not all os need timeoutHandler native-library + value = false; } + HAS_NATIVE_LIBRARY = value; } private static final String LOG_FILENAME = "processes.log"; private static final String OUTPUT_FILENAME = "processes.html"; @@ -105,7 +109,7 @@ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler { if (result == 0L) { /* jtreg didn't find pid, most probably we are on JDK < 9 there is no Process::getPid */ - if ("windows".equals(OS.current().family)) { + if (HAS_NATIVE_LIBRARY && "windows".equals(OS.current().family)) { try { Field field = process.getClass().getDeclaredField("handle"); boolean old = field.isAccessible(); diff --git a/test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c b/test/failure_handler/src/windows/native/libtimeoutHandler/GatherProcessInfoTimeoutHandler.c similarity index 96% rename from test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c rename to test/failure_handler/src/windows/native/libtimeoutHandler/GatherProcessInfoTimeoutHandler.c index f2155129316..827fc5be4f5 100644 --- a/test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c +++ b/test/failure_handler/src/windows/native/libtimeoutHandler/GatherProcessInfoTimeoutHandler.c @@ -30,7 +30,7 @@ extern "C" { JNIEXPORT jlong JNICALL Java_jdk_test_failurehandler_jtreg_GatherProcessInfoTimeoutHandler_getWin32Pid (JNIEnv* env, jobject o, jlong handle) { - return GetProcessId(handle); + return GetProcessId((HANDLE) handle); } #ifdef __cplusplus } diff --git a/test/failure_handler/test/sanity/Suicide.java b/test/failure_handler/test/sanity/Suicide.java index 0cc1c4a3fe0..7f978e04517 100644 --- a/test/failure_handler/test/sanity/Suicide.java +++ b/test/failure_handler/test/sanity/Suicide.java @@ -28,7 +28,7 @@ import java.lang.management.ManagementFactory; /* * @test * @summary Suicide test - * @run main/othervm Crash + * @run main/othervm Suicide */ public class Suicide { public static void main(String[] args) { diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 29f201de8ef..f2c85fb95a1 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -344,7 +344,13 @@ public class WhiteBox { } public native Object[] getCodeBlob(long addr); - public native void clearInlineCaches(); + private native void clearInlineCaches0(boolean preserve_static_stubs); + public void clearInlineCaches() { + clearInlineCaches0(false); + } + public void clearInlineCaches(boolean preserve_static_stubs) { + clearInlineCaches0(preserve_static_stubs); + } // Intered strings public native boolean isInStringTable(String str); diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 6b3d1a22f71..7f5f2f4af7e 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -254,4 +254,14 @@ ifneq ($(call sequence, 5, 15), 5 6 7 8 9 10 11 12 13 14 15) but was $(call sequence, 5, 15)) endif +################################################################################ +# Test that PathList is safe when called multiple nested times. + +PATHLIST_INPUT := foo bar baz + +$(eval $(call assert-equals, \ + $(call PathList, $(call PathList, $(PATHLIST_INPUT))), \ + $(call PathList, $(PATHLIST_INPUT)), \ + PathList call not safe for calling twice)) + all: $(TEST_TARGETS)