diff --git a/.hgignore b/.hgignore index aec0e31d131..9aab81ce35d 100644 --- a/.hgignore +++ b/.hgignore @@ -1,5 +1,6 @@ ^build/ ^dist/ +^.idea/ nbproject/private/ ^webrev ^.hgtip diff --git a/.hgtags b/.hgtags index 7f711e51df0..5618d206183 100644 --- a/.hgtags +++ b/.hgtags @@ -360,3 +360,4 @@ c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114 8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115 84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116 82b8d12a553f5617737c238cec060281d52e351c jdk-9+117 +7c04fcb12bd4a31570a238e663fa846dfa5ec3b8 jdk-9+118 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index bd47c1a0596..08fd371176c 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -360,3 +360,4 @@ f900d5afd9c83a0df8f36161c27c5e4c86a66f4c jdk-9+111 09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115 6743a8e0cab7b5f6f4a0575f6664892f0ab740af jdk-9+116 e882bcdbdac436523f3d5681611d3118a3804ea7 jdk-9+117 +047f95de8f918d8ff5e8cd2636a2abb5c3c8adb8 jdk-9+118 diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 7789f01450e..bdcec6208f3 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -768,7 +768,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" ;; esac - TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: 6, IF_AT_LEAST: FLAGS_SETUP_GCC6_COMPILER_FLAGS) + TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: 6, PREFIX: $2, IF_AT_LEAST: FLAGS_SETUP_GCC6_COMPILER_FLAGS) elif test "x$TOOLCHAIN_TYPE" = xclang; then $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_GNU_SOURCE" @@ -964,7 +964,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], -Wunused-value -Woverloaded-virtual" if test "x$TOOLCHAIN_TYPE" = xgcc; then - TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: [4.8], + TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: [4.8], PREFIX: $2, IF_AT_LEAST: [ # These flags either do not work or give spurious warnings prior to gcc 4.8. $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wno-format-zero-length -Wtype-limits -Wuninitialized" @@ -1411,9 +1411,15 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], DISABLE_WARNING_PREFIX= fi CFLAGS_WARNINGS_ARE_ERRORS="-Werror" - # Repeate the check for the BUILD_CC + # Repeate the check for the BUILD_CC and BUILD_CXX. Need to also reset + # CFLAGS since any target specific flags will likely not work with the + # build compiler CC_OLD="$CC" + CXX_OLD="$CXX" CC="$BUILD_CC" + CXX="$BUILD_CXX" + CFLAGS_OLD="$CFLAGS" + CFLAGS="" FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [-Wno-this-is-a-warning-that-do-not-exist], IF_TRUE: [BUILD_CC_CAN_DISABLE_WARNINGS=true], IF_FALSE: [BUILD_CC_CAN_DISABLE_WARNINGS=false] @@ -1424,6 +1430,8 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], BUILD_CC_DISABLE_WARNING_PREFIX= fi CC="$CC_OLD" + CXX="$CXX_OLD" + CFLAGS="$CFLAGS_OLD" ;; clang) DISABLE_WARNING_PREFIX="-Wno-" diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 548ab680d2a..f40198f8da3 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4900,6 +4900,8 @@ TOOLCHAIN_MINIMUM_VERSION_xlc="" # Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called. # Must have CC_VERSION_NUMBER and CXX_VERSION_NUMBER. +# $1 - optional variable prefix for compiler and version variables (BUILD_) +# $2 - optional variable prefix for comparable variable (OPENJDK_BUILD_) # Check if the configured compiler (C and C++) is of a specific version or @@ -4909,6 +4911,7 @@ TOOLCHAIN_MINIMUM_VERSION_xlc="" # VERSION: The version string to check against the found version # IF_AT_LEAST: block to run if the compiler is at least this version (>=) # IF_OLDER_THAN: block to run if the compiler is older than this version (<) +# PREFIX: Optional variable prefix for compiler to compare version for (OPENJDK_BUILD_) @@ -5073,7 +5076,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=1462806878 +DATE_WHEN_GENERATED=1462970869 ############################################################################### # @@ -34795,19 +34798,19 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test "x$CC_VERSION_NUMBER" != "x$CXX_VERSION_NUMBER"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C and C++ compiler has different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER." >&5 -$as_echo "$as_me: WARNING: C and C++ compiler has different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C and C++ compiler have different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER." >&5 +$as_echo "$as_me: WARNING: C and C++ compiler have different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER." >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: This typically indicates a broken setup, and is not supported" >&5 $as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not supported" >&2;} fi # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. - if [[ "$CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then + if [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 $as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi - if [[ "$CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then + if [[ "[$]CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi @@ -34850,6 +34853,13 @@ $as_echo "$as_me: WARNING: C compiler version number has a part larger than 9999 + + + + + + + @@ -34897,6 +34907,8 @@ $as_echo "$as_me: WARNING: You are using $TOOLCHAIN_TYPE older than $TOOLCHAIN_M + + fi # @@ -46475,6 +46487,268 @@ $as_echo "$as_me: Rewriting BUILD_STRIP to \"$new_complete\"" >&6;} BUILD_LDCXX="$BUILD_CXX" PATH="$OLDPATH" + + + COMPILER=$BUILD_CC + COMPILER_NAME=BuildC + + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + # cc -V output typically looks like + # cc: Sun C 5.12 Linux_i386 2011/11/16 + COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1` + # Check that this is likely to be the Solaris Studio cc. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null + if test $? -ne 0; then + ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1` + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with -V was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with -V was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Remove usage instructions (if present), and + # collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/ *[Uu]sage:.*//'` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e "s/^.*[ ,\t]$COMPILER_NAME[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/"` + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + # xlc -qversion output typically looks like + # IBM XL C/C++ for AIX, V11.1 (5724-X13) + # Version: 11.01.0000.0015 + COMPILER_VERSION_OUTPUT=`$COMPILER -qversion 2>&1` + # Check that this is likely to be the IBM XL C compiler. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "IBM XL C" > /dev/null + if test $? -ne 0; then + ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1` + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with -qversion was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with -qversion was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.*, V\([1-9][0-9.]*\).*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + # There is no specific version flag, but all output starts with a version string. + # First line typically looks something like: + # Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 + COMPILER_VERSION_OUTPUT=`$COMPILER 2>&1 | $HEAD -n 1 | $TR -d '\r'` + # Check that this is likely to be Microsoft CL.EXE. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Microsoft.*Compiler" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running it was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running it was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.*ersion.\([1-9][0-9.]*\) .*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + # gcc --version output typically looks like + # gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 + # Copyright (C) 2013 Free Software Foundation, Inc. + # This is free software; see the source for copying conditions. There is NO + # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` + # Check that this is likely to be GCC. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Remove Copyright and legalese from version string, and + # collapse into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/ *Copyright .*//'` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.* \([1-9]\.[0-9.]*\)[^0-9.].*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xclang; then + # clang --version output typically looks like + # Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) + # clang version 3.3 (tags/RELEASE_33/final) + # or + # Debian clang version 3.2-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2) + # Target: x86_64-pc-linux-gnu + # Thread model: posix + COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` + # Check that this is likely to be clang + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "clang" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.* version \([1-9][0-9.]*\).*$/\1/'` + else + as_fn_error $? "Unknown toolchain type $TOOLCHAIN_TYPE." "$LINENO" 5 + fi + # This sets CC_VERSION_NUMBER or CXX_VERSION_NUMBER. (This comment is a grep marker) + BUILD_CC_VERSION_NUMBER="$COMPILER_VERSION_NUMBER" + # This sets CC_VERSION_STRING or CXX_VERSION_STRING. (This comment is a grep marker) + BUILD_CC_VERSION_STRING="$COMPILER_VERSION_STRING" + + { $as_echo "$as_me:${as_lineno-$LINENO}: Using $TOOLCHAIN_TYPE $COMPILER_NAME compiler version $COMPILER_VERSION_NUMBER [$COMPILER_VERSION_STRING]" >&5 +$as_echo "$as_me: Using $TOOLCHAIN_TYPE $COMPILER_NAME compiler version $COMPILER_VERSION_NUMBER [$COMPILER_VERSION_STRING]" >&6;} + + + COMPILER=$BUILD_CXX + COMPILER_NAME=BuildC++ + + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + # cc -V output typically looks like + # cc: Sun C 5.12 Linux_i386 2011/11/16 + COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1` + # Check that this is likely to be the Solaris Studio cc. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null + if test $? -ne 0; then + ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1` + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with -V was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with -V was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Remove usage instructions (if present), and + # collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/ *[Uu]sage:.*//'` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e "s/^.*[ ,\t]$COMPILER_NAME[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/"` + elif test "x$TOOLCHAIN_TYPE" = xxlc; then + # xlc -qversion output typically looks like + # IBM XL C/C++ for AIX, V11.1 (5724-X13) + # Version: 11.01.0000.0015 + COMPILER_VERSION_OUTPUT=`$COMPILER -qversion 2>&1` + # Check that this is likely to be the IBM XL C compiler. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "IBM XL C" > /dev/null + if test $? -ne 0; then + ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1` + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with -qversion was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with -qversion was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$ALT_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.*, V\([1-9][0-9.]*\).*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + # There is no specific version flag, but all output starts with a version string. + # First line typically looks something like: + # Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 + COMPILER_VERSION_OUTPUT=`$COMPILER 2>&1 | $HEAD -n 1 | $TR -d '\r'` + # Check that this is likely to be Microsoft CL.EXE. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Microsoft.*Compiler" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running it was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running it was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.*ersion.\([1-9][0-9.]*\) .*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + # gcc --version output typically looks like + # gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 + # Copyright (C) 2013 Free Software Foundation, Inc. + # This is free software; see the source for copying conditions. There is NO + # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` + # Check that this is likely to be GCC. + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Remove Copyright and legalese from version string, and + # collapse into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/ *Copyright .*//'` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.* \([1-9]\.[0-9.]*\)[^0-9.].*$/\1/'` + elif test "x$TOOLCHAIN_TYPE" = xclang; then + # clang --version output typically looks like + # Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) + # clang version 3.3 (tags/RELEASE_33/final) + # or + # Debian clang version 3.2-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2) + # Target: x86_64-pc-linux-gnu + # Thread model: posix + COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1` + # Check that this is likely to be clang + $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "clang" > /dev/null + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 +$as_echo "$as_me: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: The result from running with --version was: \"$COMPILER_VERSION_OUTPUT\"" >&5 +$as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSION_OUTPUT\"" >&6;} + as_fn_error $? "A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir." "$LINENO" 5 + fi + # Collapse compiler output into a single line + COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT` + COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \ + $SED -e 's/^.* version \([1-9][0-9.]*\).*$/\1/'` + else + as_fn_error $? "Unknown toolchain type $TOOLCHAIN_TYPE." "$LINENO" 5 + fi + # This sets CC_VERSION_NUMBER or CXX_VERSION_NUMBER. (This comment is a grep marker) + BUILD_CXX_VERSION_NUMBER="$COMPILER_VERSION_NUMBER" + # This sets CC_VERSION_STRING or CXX_VERSION_STRING. (This comment is a grep marker) + BUILD_CXX_VERSION_STRING="$COMPILER_VERSION_STRING" + + { $as_echo "$as_me:${as_lineno-$LINENO}: Using $TOOLCHAIN_TYPE $COMPILER_NAME compiler version $COMPILER_VERSION_NUMBER [$COMPILER_VERSION_STRING]" >&5 +$as_echo "$as_me: Using $TOOLCHAIN_TYPE $COMPILER_NAME compiler version $COMPILER_VERSION_NUMBER [$COMPILER_VERSION_STRING]" >&6;} + + + if test "x$BUILD_CC_VERSION_NUMBER" != "x$BUILD_CXX_VERSION_NUMBER"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C and C++ compiler have different version numbers, $BUILD_CC_VERSION_NUMBER vs $BUILD_CXX_VERSION_NUMBER." >&5 +$as_echo "$as_me: WARNING: C and C++ compiler have different version numbers, $BUILD_CC_VERSION_NUMBER vs $BUILD_CXX_VERSION_NUMBER." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: This typically indicates a broken setup, and is not supported" >&5 +$as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not supported" >&2;} + fi + + # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. + if [[ "[$]BUILD_CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5 +$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} + fi + + if [[ "[$]BUILD_CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has a part larger than 99999: $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5 +$as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} + fi + + OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$BUILD_CC_VERSION_NUMBER"` + else # If we are not cross compiling, use the normal target compilers for # building the build platform executables. @@ -49122,6 +49396,18 @@ $as_echo "$supports" >&6; } + + + + + + + + + + + + @@ -49711,6 +49997,8 @@ $as_echo "$supports" >&6; } + + elif test "x$TOOLCHAIN_TYPE" = xclang; then JVM_CFLAGS="$JVM_CFLAGS -D_GNU_SOURCE" @@ -49935,6 +50223,18 @@ $as_echo "$supports" >&6; } + + + + + + + + + + + + @@ -49987,6 +50287,8 @@ $as_echo "$supports" >&6; } + + fi if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then # Non-zero builds have stricter warnings @@ -50440,6 +50742,18 @@ $as_echo "$supports" >&6; } + + + + + + + + + + + + @@ -50469,7 +50783,7 @@ $as_echo "$supports" >&6; } # Version comparison method inspired by http://stackoverflow.com/a/24067243 COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"` - if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + if test $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : else @@ -50488,6 +50802,8 @@ $as_echo "$supports" >&6; } + + elif test "x$TOOLCHAIN_TYPE" = xclang; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_GNU_SOURCE" @@ -50712,6 +51028,18 @@ $as_echo "$supports" >&6; } + + + + + + + + + + + + @@ -50741,7 +51069,7 @@ $as_echo "$supports" >&6; } # Version comparison method inspired by http://stackoverflow.com/a/24067243 COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"` - if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + if test $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : # These flags either do not work or give spurious warnings prior to gcc 4.8. @@ -50764,6 +51092,8 @@ $as_echo "$supports" >&6; } + + fi if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then # Non-zero builds have stricter warnings @@ -51918,9 +52248,15 @@ $as_echo "$supports" >&6; } DISABLE_WARNING_PREFIX= fi CFLAGS_WARNINGS_ARE_ERRORS="-Werror" - # Repeate the check for the BUILD_CC + # Repeate the check for the BUILD_CC and BUILD_CXX. Need to also reset + # CFLAGS since any target specific flags will likely not work with the + # build compiler CC_OLD="$CC" + CXX_OLD="$CXX" CC="$BUILD_CC" + CXX="$BUILD_CXX" + CFLAGS_OLD="$CFLAGS" + CFLAGS="" @@ -52198,6 +52534,8 @@ $as_echo "$supports" >&6; } BUILD_CC_DISABLE_WARNING_PREFIX= fi CC="$CC_OLD" + CXX="$CXX_OLD" + CFLAGS="$CFLAGS_OLD" ;; clang) DISABLE_WARNING_PREFIX="-Wno-" diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 7e7a07c5d8b..c93d487a870 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -59,23 +59,25 @@ TOOLCHAIN_MINIMUM_VERSION_xlc="" # Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called. # Must have CC_VERSION_NUMBER and CXX_VERSION_NUMBER. +# $1 - optional variable prefix for compiler and version variables (BUILD_) +# $2 - optional variable prefix for comparable variable (OPENJDK_BUILD_) AC_DEFUN([TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS], [ - if test "x$CC_VERSION_NUMBER" != "x$CXX_VERSION_NUMBER"; then - AC_MSG_WARN([C and C++ compiler has different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER.]) + if test "x[$]$1CC_VERSION_NUMBER" != "x[$]$1CXX_VERSION_NUMBER"; then + AC_MSG_WARN([C and C++ compiler have different version numbers, [$]$1CC_VERSION_NUMBER vs [$]$1CXX_VERSION_NUMBER.]) AC_MSG_WARN([This typically indicates a broken setup, and is not supported]) fi # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. - if [ [[ "$CC_VERSION_NUMBER" =~ (.*\.){3} ]] ]; then - AC_MSG_WARN([C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong.]) + if [ [[ "[$]$1CC_VERSION_NUMBER" =~ (.*\.){3} ]] ]; then + AC_MSG_WARN([C compiler version number has more than three parts (X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.]) fi - if [ [[ "$CC_VERSION_NUMBER" =~ [0-9]{6} ]] ]; then - AC_MSG_WARN([C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong.]) + if [ [[ "[$]$1CC_VERSION_NUMBER" =~ [0-9]{6} ]] ]; then + AC_MSG_WARN([C compiler version number has a part larger than 99999: [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.]) fi - COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "$CC_VERSION_NUMBER"` + $2COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "[$]$1CC_VERSION_NUMBER"` ]) # Check if the configured compiler (C and C++) is of a specific version or @@ -85,8 +87,9 @@ AC_DEFUN([TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS], # VERSION: The version string to check against the found version # IF_AT_LEAST: block to run if the compiler is at least this version (>=) # IF_OLDER_THAN: block to run if the compiler is older than this version (<) +# PREFIX: Optional variable prefix for compiler to compare version for (OPENJDK_BUILD_) BASIC_DEFUN_NAMED([TOOLCHAIN_CHECK_COMPILER_VERSION], - [*VERSION IF_AT_LEAST IF_OLDER_THAN], [$@], + [*VERSION PREFIX IF_AT_LEAST IF_OLDER_THAN], [$@], [ # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=ARG_VERSION @@ -102,7 +105,7 @@ BASIC_DEFUN_NAMED([TOOLCHAIN_CHECK_COMPILER_VERSION], # Version comparison method inspired by http://stackoverflow.com/a/24067243 COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "$REFERENCE_VERSION"` - if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then + if test [$]ARG_PREFIX[COMPARABLE_ACTUAL_VERSION] -ge $COMPARABLE_REFERENCE_VERSION ; then : ARG_IF_AT_LEAST else @@ -808,6 +811,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS], BUILD_LDCXX="$BUILD_CXX" PATH="$OLDPATH" + + TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CC, [BuildC]) + TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CXX, [BuildC++]) + TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS([BUILD_], [OPENJDK_BUILD_]) else # If we are not cross compiling, use the normal target compilers for # building the build platform executables. diff --git a/common/bin/idea.sh b/common/bin/idea.sh new file mode 100644 index 00000000000..911d309c070 --- /dev/null +++ b/common/bin/idea.sh @@ -0,0 +1,199 @@ +#!/bin/sh +# +# Copyright (c) 2009, 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. +# + +# Shell script for generating an IDEA project from a given list of modules + +usage() { + echo "usage: $0 [-h|--help] [-v|--verbose] [-o|--output ] [modules]+" + exit 1 +} + +SCRIPT_DIR=`dirname $0` +PWD=`pwd` +cd $SCRIPT_DIR; SCRIPT_DIR=`pwd` +cd ../../; TOP=`pwd`; cd $PWD + +IDEA_OUTPUT=$TOP/.idea +VERBOSE="false" +while [ $# -gt 0 ] +do + case $1 in + -h | --help ) + usage + ;; + + -v | --vebose ) + VERBOSE="true" + ;; + + -o | --output ) + IDEA_OUTPUT=$2 + shift + ;; + + -*) # bad option + usage + ;; + + * ) # non option + break + ;; + esac + shift +done + +mkdir $IDEA_OUTPUT || exit 1 +cd $IDEA_OUTPUT; IDEA_OUTPUT=`pwd` + +IDEA_MAKE="$TOP/make/idea" +IDEA_TEMPLATE="$IDEA_MAKE/template" +IML_TEMPLATE="$IDEA_TEMPLATE/jdk.iml" +ANT_TEMPLATE="$IDEA_TEMPLATE/ant.xml" +IDEA_IML="$IDEA_OUTPUT/jdk.iml" +IDEA_ANT="$IDEA_OUTPUT/ant.xml" + +if [ "$VERBOSE" = "true" ] ; then + echo "output dir: $IDEA_OUTPUT" + echo "idea template dir: $IDEA_TEMPLATE" +fi + +if [ ! -f "$IML_TEMPLATE" ] ; then + echo "FATAL: cannot find $IML_TEMPLATE" >&2; exit 1 +fi + +if [ ! -f "$ANT_TEMPLATE" ] ; then + echo "FATAL: cannot find $ANT_TEMPLATE" >&2; exit 1 +fi + +cp -r "$IDEA_TEMPLATE"/* "$IDEA_OUTPUT" +cd $TOP ; make -f "$IDEA_MAKE/idea.gmk" -I make/common idea MAKEOVERRIDES= OUT=$IDEA_OUTPUT/env.cfg MODULES="$*" || exit 1 +cd $SCRIPT_DIR + +. $IDEA_OUTPUT/env.cfg + +# Expect MODULE_ROOTS, MODULE_NAMES, BOOT_JDK & SPEC to be set +if [ "x$MODULE_ROOTS" = "x" ] ; then + echo "FATAL: MODULE_ROOTS is empty" >&2; exit 1 +fi + +if [ "x$MODULE_NAMES" = "x" ] ; then + echo "FATAL: MODULE_NAMES is empty" >&2; exit 1 +fi + +if [ "x$BOOT_JDK" = "x" ] ; then + echo "FATAL: BOOT_JDK is empty" >&2; exit 1 +fi + +if [ "x$SPEC" = "x" ] ; then + echo "FATAL: SPEC is empty" >&2; exit 1 +fi + +SOURCE_FOLDER=" " +SOURCE_FOLDERS_DONE="false" + +addSourceFolder() { + root=$@ + relativePath="`echo "$root" | sed -e s@"$TOP/\(.*$\)"@"\1"@`" + folder="`echo "$SOURCE_FOLDER" | sed -e s@"\(.*/\)####\(.*\)"@"\1$relativePath\2"@`" + printf "%s\n" "$folder" >> $IDEA_IML +} + +### Generate project iml +RELATIVE_BUILD_DIR="`dirname $SPEC | sed -e s@"$TOP/\(.*$\)"@"\1"@`" +rm -f $IDEA_IML +while IFS= read -r line +do + if echo "$line" | egrep "^ .* /dev/null ; then + if [ "$SOURCE_FOLDERS_DONE" = "false" ] ; then + SOURCE_FOLDERS_DONE="true" + for root in $MODULE_ROOTS; do + addSourceFolder $root + done + fi + elif echo "$line" | egrep "^ .* /dev/null ; then + ul="`echo "$line" | sed -e s@"\(.*/\)####\(.*\)"@"\1$RELATIVE_BUILD_DIR\2"@`" + printf "%s\n" "$ul" >> $IDEA_IML + else + printf "%s\n" "$line" >> $IDEA_IML + fi +done < "$IML_TEMPLATE" + + +MODULE_NAME=" " + +addModuleName() { + mn="`echo "$MODULE_NAME" | sed -e s@"\(.*\)####\(.*\)"@"\1$MODULE_NAMES\2"@`" + printf "%s\n" "$mn" >> $IDEA_ANT +} + +BUILD_DIR=" " + +addBuildDir() { + DIR=`dirname $SPEC` + mn="`echo "$BUILD_DIR" | sed -e s@"\(.*\)####\(.*\)"@"\1$DIR\2"@`" + printf "%s\n" "$mn" >> $IDEA_ANT +} + +### Generate ant.xml + +rm -f $IDEA_ANT +while IFS= read -r line +do + if echo "$line" | egrep "^ .* /dev/null ; then + addModuleName + elif echo "$line" | egrep "^ .* /dev/null ; then + addBuildDir + else + printf "%s\n" "$line" >> $IDEA_ANT + fi +done < "$ANT_TEMPLATE" + +### Compile the custom Logger + +CLASSES=$IDEA_OUTPUT/classes + +if [ "x$ANT_HOME" = "x" ] ; then + # try some common locations, before giving up + if [ -f "/usr/share/ant/lib/ant.jar" ] ; then + ANT_HOME="/usr/share/ant" + elif [ -f "/usr/local/Cellar/ant/1.9.4/libexec/lib/ant.jar" ] ; then + ANT_HOME="/usr/local/Cellar/ant/1.9.4/libexec" + else + echo "FATAL: cannot find ant. Try setting ANT_HOME." >&2; exit 1 + fi +fi +CP=$ANT_HOME/lib/ant.jar +rm -rf $CLASSES; mkdir $CLASSES + +if [ "x$CYGPATH" = "x" ] ; then ## CYGPATH may be set in env.cfg + JAVAC_SOURCE_FILE=$IDEA_OUTPUT/src/idea/JdkIdeaAntLogger.java + JAVAC_CLASSES=$CLASSES + JAVAC_CP=$CP +else + JAVAC_SOURCE_FILE=`cygpath -am $IDEA_OUTPUT/src/idea/JdkIdeaAntLogger.java` + JAVAC_CLASSES=`cygpath -am $CLASSES` + JAVAC_CP=`cygpath -am $CP` +fi + +$BOOT_JDK/bin/javac -d $JAVAC_CLASSES -cp $JAVAC_CP $JAVAC_SOURCE_FILE diff --git a/common/bin/jib.sh b/common/bin/jib.sh index 454d78ce1d7..ea52385537b 100644 --- a/common/bin/jib.sh +++ b/common/bin/jib.sh @@ -89,7 +89,7 @@ install_jib() { fi if command -v curl > /dev/null; then - getcmd="curl -s" + getcmd="curl -s -L --retry 3 --retry-delay 5" elif command -v wget > /dev/null; then getcmd="wget --quiet -O -" else diff --git a/corba/.hgtags b/corba/.hgtags index 7a705d44659..feea5f070eb 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -360,3 +360,4 @@ cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113 7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115 7dfa7377a5e601b8f740741a9a80e04c72dd04d6 jdk-9+116 7a1b36bf2fe55a9a7732489ccdd326c910329a7e jdk-9+117 +8c2c2d17f7ce92a31c9ccb44a122ec62f5a85ace jdk-9+118 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index d308ce9a4c0..c2bf9fb792d 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -520,3 +520,4 @@ b64432bae5271735fd53300b2005b713e98ef411 jdk-9+114 88dd08d7be0fe7fb9f1914b1628f0aae9bf56e25 jdk-9+115 61a214186dae6811dd989e9165e42f7dbf02acde jdk-9+116 88170d3642905b9e6cac03e8efcc976885a7e6da jdk-9+117 +9b1075cac08dc836ec32e7b368415cbe3aceaf8c jdk-9+118 diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 5166478e5e7..834e1ae88fc 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -3387,14 +3387,14 @@ bool force_verify_field_access(Klass* current_class, Klass* field_class, AccessF return (!access.is_private() && InstanceKlass::cast(current_class)->is_same_class_package(field_class)); } -// Return the first non-null class loader up the execution stack, or null -// if only code from the null class loader is on the stack. +// Return the first user-defined class loader up the execution stack, or null +// if only code from the bootstrap or platform class loader is on the stack. JVM_ENTRY(jobject, JVM_LatestUserDefinedLoader(JNIEnv *env)) for (vframeStream vfst(thread); !vfst.at_end(); vfst.next()) { vfst.skip_reflection_related_frames(); // Only needed for 1.4 reflection oop loader = vfst.method()->method_holder()->class_loader(); - if (loader != NULL) { + if (loader != NULL && !SystemDictionary::is_platform_class_loader(loader)) { return JNIHandles::make_local(env, loader); } } diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile index 3468e65bcac..1dfecd6bce1 100644 --- a/hotspot/test/Makefile +++ b/hotspot/test/Makefile @@ -120,24 +120,33 @@ endif TEST_ROOT := $(shell pwd) # Root of all test results -ifdef ALT_OUTPUTDIR - ABS_BUILD_ROOT = $(ALT_OUTPUTDIR) +ifdef TEST_OUTPUT_DIR + $(shell $(MKDIR) -p $(TEST_OUTPUT_DIR)/jtreg) + ABS_TEST_OUTPUT_DIR := \ + $(shell $(CD) $(TEST_OUTPUT_DIR)/jtreg && $(PWD)) else - ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) + ifdef ALT_OUTPUTDIR + ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD)) + else + ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD)) + endif + + ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR) + ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) endif -ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) ifndef PRODUCT_HOME - # Try to use j2sdk-image if it exists - ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image - PRODUCT_HOME := \ - $(shell \ - if [ -d $(ABS_JDK_IMAGE) ] ; then \ - $(ECHO) "$(ABS_JDK_IMAGE)"; \ - else \ - $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + # Try to use images/jdk if it exists + ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/jdk + PRODUCT_HOME := \ + $(shell \ + if [ -d $(ABS_JDK_IMAGE) ] ; then \ + $(ECHO) "$(ABS_JDK_IMAGE)"; \ + else \ + $(ECHO) "$(ABS_PLATFORM_BUILD_ROOT)"; \ fi) + PRODUCT_HOME := $(PRODUCT_HOME) endif # Expect JPRT to set JAVA_ARGS (e.g. -server etc.) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index f36d86837fa..3bef243c570 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -360,3 +360,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115 9d71d20e614777cd23c1a43b38b5c08a9094d27a jdk-9+116 46b57560cd06ebcdd21489250628ff5f9d9d8916 jdk-9+117 +a8aa25fc6c5fda0ed7a93b8ffee62da326a752fc jdk-9+118 diff --git a/jaxp/THIRD_PARTY_README b/jaxp/THIRD_PARTY_README index a93b35b994c..4d3007051ce 100644 --- a/jaxp/THIRD_PARTY_README +++ b/jaxp/THIRD_PARTY_README @@ -3387,7 +3387,6 @@ included with JRE 8, JDK 8, and OpenJDK 8, except where noted: Apache Commons Math 2.2 Apache Derby 10.10.1.2 [included with JDK 8] Apache Jakarta BCEL 5.2 - Apache Jakarta Regexp 1.4 Apache Santuario XML Security for Java 1.5.4 Apache Xalan-Java 2.7.1 Apache Xerces Java 2.10.0 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java index 162afd1e0dd..f755549b902 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java @@ -4,64 +4,29 @@ */ package com.sun.org.apache.bcel.internal.util; -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Copyright (c) 2001 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" and - * "Apache BCEL" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * "Apache BCEL", nor may "Apache" appear in their name, without - * prior written permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . */ -import java.util.*; import com.sun.org.apache.bcel.internal.Constants; import com.sun.org.apache.bcel.internal.generic.*; -import com.sun.org.apache.regexp.internal.*; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * InstructionFinder is a tool to search for given instructions patterns, @@ -231,28 +196,22 @@ public class InstructionFinder { if(start == -1) throw new ClassGenException("Instruction handle " + from + " not found in instruction list."); - try { - RE regex = new RE(search); - ArrayList matches = new ArrayList(); - while(start < il_string.length() && regex.match(il_string, start)) { - int startExpr = regex.getParenStart(0); - int endExpr = regex.getParenEnd(0); - int lenExpr = regex.getParenLength(0); + Pattern regex = Pattern.compile(search); + List matches = new ArrayList<>(); + Matcher matcher = regex.matcher(il_string); + while(start < il_string.length() && matcher.find(start)) { + int startExpr = matcher.start(); + int endExpr = matcher.end(); + int lenExpr = endExpr - startExpr; + InstructionHandle[] match = getMatch(startExpr, lenExpr); - InstructionHandle[] match = getMatch(startExpr, lenExpr); - - if((constraint == null) || constraint.checkCode(match)) - matches.add(match); - start = endExpr; - } - - return matches.iterator(); - } catch(RESyntaxException e) { - System.err.println(e); + if((constraint == null) || constraint.checkCode(match)) + matches.add(match); + start = endExpr; } - return null; + return matches.iterator(); } /** diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterArrayCharacterIterator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterArrayCharacterIterator.java deleted file mode 100644 index 6382d478d96..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterArrayCharacterIterator.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -/** - * Encapsulates char[] as CharacterIterator - * - * @author Ales Novak - */ -public final class CharacterArrayCharacterIterator implements CharacterIterator -{ - /** encapsulated */ - private final char[] src; - /** offset in the char array */ - private final int off; - /** used portion of the array */ - private final int len; - - /** @param src - encapsulated String */ - public CharacterArrayCharacterIterator(char[] src, int off, int len) - { - this.src = src; - this.off = off; - this.len = len; - } - - /** @return a substring */ - public String substring(int beginIndex, int endIndex) - { - if (endIndex > len) { - throw new IndexOutOfBoundsException("endIndex=" + endIndex - + "; sequence size=" + len); - } - if (beginIndex < 0 || beginIndex > endIndex) { - throw new IndexOutOfBoundsException("beginIndex=" + beginIndex - + "; endIndex=" + endIndex); - } - return new String(src, off + beginIndex, endIndex - beginIndex); - } - - /** @return a substring */ - public String substring(int beginIndex) - { - return substring(beginIndex, len); - } - - /** @return a character at the specified position. */ - public char charAt(int pos) - { - return src[off + pos]; - } - - /** @return true iff if the specified index is after the end of the character stream */ - public boolean isEnd(int pos) - { - return (pos >= len); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterIterator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterIterator.java deleted file mode 100644 index 69db536aaa2..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/CharacterIterator.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -/** - * Encapsulates different types of character sources - String, InputStream, ... - * Defines a set of common methods - * - * @author Ales Novak - */ -public interface CharacterIterator -{ - /** @return a substring */ - String substring(int beginIndex, int endIndex); - - /** @return a substring */ - String substring(int beginIndex); - - /** @return a character at the specified position. */ - char charAt(int pos); - - /** @return true iff if the specified index is after the end of the character stream */ - boolean isEnd(int pos); -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RE.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RE.java deleted file mode 100644 index 0cdc012dbb7..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RE.java +++ /dev/null @@ -1,1760 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import java.io.Serializable; -import java.util.Vector; - -/** - * RE is an efficient, lightweight regular expression evaluator/matcher - * class. Regular expressions are pattern descriptions which enable - * sophisticated matching of strings. In addition to being able to - * match a string against a pattern, you can also extract parts of the - * match. This is especially useful in text parsing! Details on the - * syntax of regular expression patterns are given below. - * - *

- * To compile a regular expression (RE), you can simply construct an RE - * matcher object from the string specification of the pattern, like this: - * - *

- *  RE r = new RE("a*b");
- * 
- * - *

- * Once you have done this, you can call either of the RE.match methods to - * perform matching on a String. For example: - * - *

- *  boolean matched = r.match("aaaab");
- * 
- * - * will cause the boolean matched to be set to true because the - * pattern "a*b" matches the string "aaaab". - * - *

- * If you were interested in the number of a's which matched the - * first part of our example expression, you could change the expression to - * "(a*)b". Then when you compiled the expression and matched it against - * something like "xaaaab", you would get results like this: - * - *

- *  RE r = new RE("(a*)b");                  // Compile expression
- *  boolean matched = r.match("xaaaab");     // Match against "xaaaab"
- *
- *  String wholeExpr = r.getParen(0);        // wholeExpr will be 'aaaab'
- *  String insideParens = r.getParen(1);     // insideParens will be 'aaaa'
- *
- *  int startWholeExpr = r.getParenStart(0); // startWholeExpr will be index 1
- *  int endWholeExpr = r.getParenEnd(0);     // endWholeExpr will be index 6
- *  int lenWholeExpr = r.getParenLength(0);  // lenWholeExpr will be 5
- *
- *  int startInside = r.getParenStart(1);    // startInside will be index 1
- *  int endInside = r.getParenEnd(1);        // endInside will be index 5
- *  int lenInside = r.getParenLength(1);     // lenInside will be 4
- * 
- * - * You can also refer to the contents of a parenthesized expression - * within a regular expression itself. This is called a - * 'backreference'. The first backreference in a regular expression is - * denoted by \1, the second by \2 and so on. So the expression: - * - *
- *  ([0-9]+)=\1
- * 
- * - * will match any string of the form n=n (like 0=0 or 2=2). - * - *

- * The full regular expression syntax accepted by RE is described here: - * - *

- *
- *  Characters
- *
- *    unicodeChar   Matches any identical unicode character
- *    \                    Used to quote a meta-character (like '*')
- *    \\                   Matches a single '\' character
- *    \0nnn                Matches a given octal character
- *    \xhh                 Matches a given 8-bit hexadecimal character
- *    \\uhhhh              Matches a given 16-bit hexadecimal character
- *    \t                   Matches an ASCII tab character
- *    \n                   Matches an ASCII newline character
- *    \r                   Matches an ASCII return character
- *    \f                   Matches an ASCII form feed character
- *
- *
- *  Character Classes
- *
- *    [abc]                Simple character class
- *    [a-zA-Z]             Character class with ranges
- *    [^abc]               Negated character class
- * 
- * - * NOTE: Incomplete ranges will be interpreted as "starts - * from zero" or "ends with last character". - *
- * I.e. [-a] is the same as [\\u0000-a], and [a-] is the same as [a-\\uFFFF], - * [-] means "all characters". - * - *
- *
- *  Standard POSIX Character Classes
- *
- *    [:alnum:]            Alphanumeric characters.
- *    [:alpha:]            Alphabetic characters.
- *    [:blank:]            Space and tab characters.
- *    [:cntrl:]            Control characters.
- *    [:digit:]            Numeric characters.
- *    [:graph:]            Characters that are printable and are also visible.
- *                         (A space is printable, but not visible, while an
- *                         `a' is both.)
- *    [:lower:]            Lower-case alphabetic characters.
- *    [:print:]            Printable characters (characters that are not
- *                         control characters.)
- *    [:punct:]            Punctuation characters (characters that are not letter,
- *                         digits, control characters, or space characters).
- *    [:space:]            Space characters (such as space, tab, and formfeed,
- *                         to name a few).
- *    [:upper:]            Upper-case alphabetic characters.
- *    [:xdigit:]           Characters that are hexadecimal digits.
- *
- *
- *  Non-standard POSIX-style Character Classes
- *
- *    [:javastart:]        Start of a Java identifier
- *    [:javapart:]         Part of a Java identifier
- *
- *
- *  Predefined Classes
- *
- *    .         Matches any character other than newline
- *    \w        Matches a "word" character (alphanumeric plus "_")
- *    \W        Matches a non-word character
- *    \s        Matches a whitespace character
- *    \S        Matches a non-whitespace character
- *    \d        Matches a digit character
- *    \D        Matches a non-digit character
- *
- *
- *  Boundary Matchers
- *
- *    ^         Matches only at the beginning of a line
- *    $         Matches only at the end of a line
- *    \b        Matches only at a word boundary
- *    \B        Matches only at a non-word boundary
- *
- *
- *  Greedy Closures
- *
- *    A*        Matches A 0 or more times (greedy)
- *    A+        Matches A 1 or more times (greedy)
- *    A?        Matches A 1 or 0 times (greedy)
- *    A{n}      Matches A exactly n times (greedy)
- *    A{n,}     Matches A at least n times (greedy)
- *    A{n,m}    Matches A at least n but not more than m times (greedy)
- *
- *
- *  Reluctant Closures
- *
- *    A*?       Matches A 0 or more times (reluctant)
- *    A+?       Matches A 1 or more times (reluctant)
- *    A??       Matches A 0 or 1 times (reluctant)
- *
- *
- *  Logical Operators
- *
- *    AB        Matches A followed by B
- *    A|B       Matches either A or B
- *    (A)       Used for subexpression grouping
- *   (?:A)      Used for subexpression clustering (just like grouping but
- *              no backrefs)
- *
- *
- *  Backreferences
- *
- *    \1    Backreference to 1st parenthesized subexpression
- *    \2    Backreference to 2nd parenthesized subexpression
- *    \3    Backreference to 3rd parenthesized subexpression
- *    \4    Backreference to 4th parenthesized subexpression
- *    \5    Backreference to 5th parenthesized subexpression
- *    \6    Backreference to 6th parenthesized subexpression
- *    \7    Backreference to 7th parenthesized subexpression
- *    \8    Backreference to 8th parenthesized subexpression
- *    \9    Backreference to 9th parenthesized subexpression
- * 
- * - *

- * All closure operators (+, *, ?, {m,n}) are greedy by default, meaning - * that they match as many elements of the string as possible without - * causing the overall match to fail. If you want a closure to be - * reluctant (non-greedy), you can simply follow it with a '?'. A - * reluctant closure will match as few elements of the string as - * possible when finding matches. {m,n} closures don't currently - * support reluctancy. - * - *

- * Line terminators - *
- * A line terminator is a one- or two-character sequence that marks - * the end of a line of the input character sequence. The following - * are recognized as line terminators: - *

    - *
  • A newline (line feed) character ('\n'),
  • - *
  • A carriage-return character followed immediately by a newline character ("\r\n"),
  • - *
  • A standalone carriage-return character ('\r'),
  • - *
  • A next-line character ('\u0085'),
  • - *
  • A line-separator character ('\u2028'), or
  • - *
  • A paragraph-separator character ('\u2029).
  • - *
- * - *

- * RE runs programs compiled by the RECompiler class. But the RE - * matcher class does not include the actual regular expression compiler - * for reasons of efficiency. In fact, if you want to pre-compile one - * or more regular expressions, the 'recompile' class can be invoked - * from the command line to produce compiled output like this: - * - *

- *    // Pre-compiled regular expression "a*b"
- *    char[] re1Instructions =
- *    {
- *        0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
- *        0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
- *        0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
- *        0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
- *        0x0000,
- *    };
- *
- *
- *    REProgram re1 = new REProgram(re1Instructions);
- * 
- * - * You can then construct a regular expression matcher (RE) object from - * the pre-compiled expression re1 and thus avoid the overhead of - * compiling the expression at runtime. If you require more dynamic - * regular expressions, you can construct a single RECompiler object and - * re-use it to compile each expression. Similarly, you can change the - * program run by a given matcher object at any time. However, RE and - * RECompiler are not threadsafe (for efficiency reasons, and because - * requiring thread safety in this class is deemed to be a rare - * requirement), so you will need to construct a separate compiler or - * matcher object for each thread (unless you do thread synchronization - * yourself). Once expression compiled into the REProgram object, REProgram - * can be safely shared across multiple threads and RE objects. - * - *


- * - * - * ISSUES: - * - *

    - *
  • com.weusours.util.re is not currently compatible with all - * standard POSIX regcomp flags
  • - *
  • com.weusours.util.re does not support POSIX equivalence classes - * ([=foo=] syntax) (I18N/locale issue)
  • - *
  • com.weusours.util.re does not support nested POSIX character - * classes (definitely should, but not completely trivial)
  • - *
  • com.weusours.util.re Does not support POSIX character collation - * concepts ([.foo.] syntax) (I18N/locale issue)
  • - *
  • Should there be different matching styles (simple, POSIX, Perl etc?)
  • - *
  • Should RE support character iterators (for backwards RE matching!)?
  • - *
  • Should RE support reluctant {m,n} closures (does anyone care)?
  • - *
  • Not *all* possibilities are considered for greediness when backreferences - * are involved (as POSIX suggests should be the case). The POSIX RE - * "(ac*)c*d[ac]*\1", when matched against "acdacaa" should yield a match - * of acdacaa where \1 is "a". This is not the case in this RE package, - * and actually Perl doesn't go to this extent either! Until someone - * actually complains about this, I'm not sure it's worth "fixing". - * If it ever is fixed, test #137 in RETest.txt should be updated.
  • - *
- * - * - * - * @see recompile - * @see RECompiler - * - * @author Jonathan Locke - * @author Tobias Schäfer - */ -public class RE implements Serializable -{ - /** - * Specifies normal, case-sensitive matching behaviour. - */ - public static final int MATCH_NORMAL = 0x0000; - - /** - * Flag to indicate that matching should be case-independent (folded) - */ - public static final int MATCH_CASEINDEPENDENT = 0x0001; - - /** - * Newlines should match as BOL/EOL (^ and $) - */ - public static final int MATCH_MULTILINE = 0x0002; - - /** - * Consider all input a single body of text - newlines are matched by . - */ - public static final int MATCH_SINGLELINE = 0x0004; - - /************************************************ - * * - * The format of a node in a program is: * - * * - * [ OPCODE ] [ OPDATA ] [ OPNEXT ] [ OPERAND ] * - * * - * char OPCODE - instruction * - * char OPDATA - modifying data * - * char OPNEXT - next node (relative offset) * - * * - ************************************************/ - - // Opcode Char Opdata/Operand Meaning - // ---------- ---------- --------------- -------------------------------------------------- - static final char OP_END = 'E'; // end of program - static final char OP_BOL = '^'; // match only if at beginning of line - static final char OP_EOL = '$'; // match only if at end of line - static final char OP_ANY = '.'; // match any single character except newline - static final char OP_ANYOF = '['; // count/ranges match any char in the list of ranges - static final char OP_BRANCH = '|'; // node match this alternative or the next one - static final char OP_ATOM = 'A'; // length/string length of string followed by string itself - static final char OP_STAR = '*'; // node kleene closure - static final char OP_PLUS = '+'; // node positive closure - static final char OP_MAYBE = '?'; // node optional closure - static final char OP_ESCAPE = '\\'; // escape special escape code char class (escape is E_* code) - static final char OP_OPEN = '('; // number nth opening paren - static final char OP_OPEN_CLUSTER = '<'; // opening cluster - static final char OP_CLOSE = ')'; // number nth closing paren - static final char OP_CLOSE_CLUSTER = '>'; // closing cluster - static final char OP_BACKREF = '#'; // number reference nth already matched parenthesized string - static final char OP_GOTO = 'G'; // nothing but a (back-)pointer - static final char OP_NOTHING = 'N'; // match null string such as in '(a|)' - static final char OP_RELUCTANTSTAR = '8'; // none/expr reluctant '*' (mnemonic for char is unshifted '*') - static final char OP_RELUCTANTPLUS = '='; // none/expr reluctant '+' (mnemonic for char is unshifted '+') - static final char OP_RELUCTANTMAYBE = '/'; // none/expr reluctant '?' (mnemonic for char is unshifted '?') - static final char OP_POSIXCLASS = 'P'; // classid one of the posix character classes - - // Escape codes - static final char E_ALNUM = 'w'; // Alphanumeric - static final char E_NALNUM = 'W'; // Non-alphanumeric - static final char E_BOUND = 'b'; // Word boundary - static final char E_NBOUND = 'B'; // Non-word boundary - static final char E_SPACE = 's'; // Whitespace - static final char E_NSPACE = 'S'; // Non-whitespace - static final char E_DIGIT = 'd'; // Digit - static final char E_NDIGIT = 'D'; // Non-digit - - // Posix character classes - static final char POSIX_CLASS_ALNUM = 'w'; // Alphanumerics - static final char POSIX_CLASS_ALPHA = 'a'; // Alphabetics - static final char POSIX_CLASS_BLANK = 'b'; // Blanks - static final char POSIX_CLASS_CNTRL = 'c'; // Control characters - static final char POSIX_CLASS_DIGIT = 'd'; // Digits - static final char POSIX_CLASS_GRAPH = 'g'; // Graphic characters - static final char POSIX_CLASS_LOWER = 'l'; // Lowercase characters - static final char POSIX_CLASS_PRINT = 'p'; // Printable characters - static final char POSIX_CLASS_PUNCT = '!'; // Punctuation - static final char POSIX_CLASS_SPACE = 's'; // Spaces - static final char POSIX_CLASS_UPPER = 'u'; // Uppercase characters - static final char POSIX_CLASS_XDIGIT = 'x'; // Hexadecimal digits - static final char POSIX_CLASS_JSTART = 'j'; // Java identifier start - static final char POSIX_CLASS_JPART = 'k'; // Java identifier part - - // Limits - static final int maxNode = 65536; // Maximum number of nodes in a program - static final int MAX_PAREN = 16; // Number of paren pairs (only 9 can be backrefs) - - // Node layout constants - static final int offsetOpcode = 0; // Opcode offset (first character) - static final int offsetOpdata = 1; // Opdata offset (second char) - static final int offsetNext = 2; // Next index offset (third char) - static final int nodeSize = 3; // Node size (in chars) - - // State of current program - REProgram program; // Compiled regular expression 'program' - transient CharacterIterator search; // The string being matched against - int matchFlags; // Match behaviour flags - int maxParen = MAX_PAREN; - - // Parenthesized subexpressions - transient int parenCount; // Number of subexpressions matched (num open parens + 1) - transient int start0; // Cache of start[0] - transient int end0; // Cache of start[0] - transient int start1; // Cache of start[1] - transient int end1; // Cache of start[1] - transient int start2; // Cache of start[2] - transient int end2; // Cache of start[2] - transient int[] startn; // Lazy-alloced array of sub-expression starts - transient int[] endn; // Lazy-alloced array of sub-expression ends - - // Backreferences - transient int[] startBackref; // Lazy-alloced array of backref starts - transient int[] endBackref; // Lazy-alloced array of backref ends - - /** - * Constructs a regular expression matcher from a String by compiling it - * using a new instance of RECompiler. If you will be compiling many - * expressions, you may prefer to use a single RECompiler object instead. - * - * @param pattern The regular expression pattern to compile. - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - * @see RECompiler - * @see recompile - */ - public RE(String pattern) throws RESyntaxException - { - this(pattern, MATCH_NORMAL); - } - - /** - * Constructs a regular expression matcher from a String by compiling it - * using a new instance of RECompiler. If you will be compiling many - * expressions, you may prefer to use a single RECompiler object instead. - * - * @param pattern The regular expression pattern to compile. - * @param matchFlags The matching style - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - * @see RECompiler - * @see recompile - */ - public RE(String pattern, int matchFlags) throws RESyntaxException - { - this(new RECompiler().compile(pattern)); - setMatchFlags(matchFlags); - } - - /** - * Construct a matcher for a pre-compiled regular expression from program - * (bytecode) data. Permits special flags to be passed in to modify matching - * behaviour. - * - * @param program Compiled regular expression program (see RECompiler and/or recompile) - * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*): - * - *
-     *   MATCH_NORMAL              // Normal (case-sensitive) matching
-     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
-     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
-     * 
- * - * @see RECompiler - * @see REProgram - * @see recompile - */ - public RE(REProgram program, int matchFlags) - { - setProgram(program); - setMatchFlags(matchFlags); - } - - /** - * Construct a matcher for a pre-compiled regular expression from program - * (bytecode) data. - * - * @param program Compiled regular expression program - * @see RECompiler - * @see recompile - */ - public RE(REProgram program) - { - this(program, MATCH_NORMAL); - } - - /** - * Constructs a regular expression matcher with no initial program. - * This is likely to be an uncommon practice, but is still supported. - */ - public RE() - { - this((REProgram)null, MATCH_NORMAL); - } - - /** - * Converts a 'simplified' regular expression to a full regular expression - * - * @param pattern The pattern to convert - * @return The full regular expression - */ - public static String simplePatternToFullRegularExpression(String pattern) - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < pattern.length(); i++) - { - char c = pattern.charAt(i); - switch (c) - { - case '*': - buf.append(".*"); - break; - - case '.': - case '[': - case ']': - case '\\': - case '+': - case '?': - case '{': - case '}': - case '$': - case '^': - case '|': - case '(': - case ')': - buf.append('\\'); - default: - buf.append(c); - break; - } - } - return buf.toString(); - } - - /** - * Sets match behaviour flags which alter the way RE does matching. - * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*): - * - *
-     *   MATCH_NORMAL              // Normal (case-sensitive) matching
-     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
-     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
-     * 
- */ - public void setMatchFlags(int matchFlags) - { - this.matchFlags = matchFlags; - } - - /** - * Returns the current match behaviour flags. - * @return Current match behaviour flags (RE.MATCH_*). - * - *
-     *   MATCH_NORMAL              // Normal (case-sensitive) matching
-     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
-     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
-     * 
- * - * @see #setMatchFlags - */ - public int getMatchFlags() - { - return matchFlags; - } - - /** - * Sets the current regular expression program used by this matcher object. - * - * @param program Regular expression program compiled by RECompiler. - * @see RECompiler - * @see REProgram - * @see recompile - */ - public void setProgram(REProgram program) - { - this.program = program; - if (program != null && program.maxParens != -1) { - this.maxParen = program.maxParens; - } else { - this.maxParen = MAX_PAREN; - } - } - - /** - * Returns the current regular expression program in use by this matcher object. - * - * @return Regular expression program - * @see #setProgram - */ - public REProgram getProgram() - { - return program; - } - - /** - * Returns the number of parenthesized subexpressions available after a successful match. - * - * @return Number of available parenthesized subexpressions - */ - public int getParenCount() - { - return parenCount; - } - - /** - * Gets the contents of a parenthesized subexpression after a successful match. - * - * @param which Nesting level of subexpression - * @return String - */ - public String getParen(int which) - { - int start; - if (which < parenCount && (start = getParenStart(which)) >= 0) - { - return search.substring(start, getParenEnd(which)); - } - return null; - } - - /** - * Returns the start index of a given paren level. - * - * @param which Nesting level of subexpression - * @return String index - */ - public final int getParenStart(int which) - { - if (which < parenCount) - { - switch (which) - { - case 0: - return start0; - - case 1: - return start1; - - case 2: - return start2; - - default: - if (startn == null) - { - allocParens(); - } - return startn[which]; - } - } - return -1; - } - - /** - * Returns the end index of a given paren level. - * - * @param which Nesting level of subexpression - * @return String index - */ - public final int getParenEnd(int which) - { - if (which < parenCount) - { - switch (which) - { - case 0: - return end0; - - case 1: - return end1; - - case 2: - return end2; - - default: - if (endn == null) - { - allocParens(); - } - return endn[which]; - } - } - return -1; - } - - /** - * Returns the length of a given paren level. - * - * @param which Nesting level of subexpression - * @return Number of characters in the parenthesized subexpression - */ - public final int getParenLength(int which) - { - if (which < parenCount) - { - return getParenEnd(which) - getParenStart(which); - } - return -1; - } - - /** - * Sets the start of a paren level - * - * @param which Which paren level - * @param i Index in input array - */ - protected final void setParenStart(int which, int i) - { - if (which < parenCount) - { - switch (which) - { - case 0: - start0 = i; - break; - - case 1: - start1 = i; - break; - - case 2: - start2 = i; - break; - - default: - if (startn == null) - { - allocParens(); - } - startn[which] = i; - break; - } - } - } - - /** - * Sets the end of a paren level - * - * @param which Which paren level - * @param i Index in input array - */ - protected final void setParenEnd(int which, int i) - { - if (which < parenCount) - { - switch (which) - { - case 0: - end0 = i; - break; - - case 1: - end1 = i; - break; - - case 2: - end2 = i; - break; - - default: - if (endn == null) - { - allocParens(); - } - endn[which] = i; - break; - } - } - } - - /** - * Throws an Error representing an internal error condition probably resulting - * from a bug in the regular expression compiler (or possibly data corruption). - * In practice, this should be very rare. - * - * @param s Error description - */ - protected void internalError(String s) throws Error - { - throw new Error("RE internal error: " + s); - } - - /** - * Performs lazy allocation of subexpression arrays - */ - private final void allocParens() - { - // Allocate arrays for subexpressions - startn = new int[maxParen]; - endn = new int[maxParen]; - - // Set sub-expression pointers to invalid values - for (int i = 0; i < maxParen; i++) - { - startn[i] = -1; - endn[i] = -1; - } - } - - /** - * Try to match a string against a subset of nodes in the program - * - * @param firstNode Node to start at in program - * @param lastNode Last valid node (used for matching a subexpression without - * matching the rest of the program as well). - * @param idxStart Starting position in character array - * @return Final input array index if match succeeded. -1 if not. - */ - protected int matchNodes(int firstNode, int lastNode, int idxStart) - { - // Our current place in the string - int idx = idxStart; - - // Loop while node is valid - int next, opcode, opdata; - int idxNew; - char[] instruction = program.instruction; - for (int node = firstNode; node < lastNode; ) - { - opcode = instruction[node + offsetOpcode]; - next = node + (short)instruction[node + offsetNext]; - opdata = instruction[node + offsetOpdata]; - - switch (opcode) - { - case OP_RELUCTANTMAYBE: - { - int once = 0; - do - { - // Try to match the rest without using the reluctant subexpr - if ((idxNew = matchNodes(next, maxNode, idx)) != -1) - { - return idxNew; - } - } - while ((once++ == 0) && (idx = matchNodes(node + nodeSize, next, idx)) != -1); - return -1; - } - - case OP_RELUCTANTPLUS: - while ((idx = matchNodes(node + nodeSize, next, idx)) != -1) - { - // Try to match the rest without using the reluctant subexpr - if ((idxNew = matchNodes(next, maxNode, idx)) != -1) - { - return idxNew; - } - } - return -1; - - case OP_RELUCTANTSTAR: - do - { - // Try to match the rest without using the reluctant subexpr - if ((idxNew = matchNodes(next, maxNode, idx)) != -1) - { - return idxNew; - } - } - while ((idx = matchNodes(node + nodeSize, next, idx)) != -1); - return -1; - - case OP_OPEN: - - // Match subexpression - if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) - { - startBackref[opdata] = idx; - } - if ((idxNew = matchNodes(next, maxNode, idx)) != -1) - { - // Increase valid paren count - if ((opdata + 1) > parenCount) - { - parenCount = opdata + 1; - } - - // Don't set paren if already set later on - if (getParenStart(opdata) == -1) - { - setParenStart(opdata, idx); - } - } - return idxNew; - - case OP_CLOSE: - - // Done matching subexpression - if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) - { - endBackref[opdata] = idx; - } - if ((idxNew = matchNodes(next, maxNode, idx)) != -1) - { - // Increase valid paren count - if ((opdata + 1) > parenCount) - { - parenCount = opdata + 1; - } - - // Don't set paren if already set later on - if (getParenEnd(opdata) == -1) - { - setParenEnd(opdata, idx); - } - } - return idxNew; - - case OP_OPEN_CLUSTER: - case OP_CLOSE_CLUSTER: - // starting or ending the matching of a subexpression which has no backref. - return matchNodes( next, maxNode, idx ); - - case OP_BACKREF: - { - // Get the start and end of the backref - int s = startBackref[opdata]; - int e = endBackref[opdata]; - - // We don't know the backref yet - if (s == -1 || e == -1) - { - return -1; - } - - // The backref is empty size - if (s == e) - { - break; - } - - // Get the length of the backref - int l = e - s; - - // If there's not enough input left, give up. - if (search.isEnd(idx + l - 1)) - { - return -1; - } - - // Case fold the backref? - final boolean caseFold = - ((matchFlags & MATCH_CASEINDEPENDENT) != 0); - // Compare backref to input - for (int i = 0; i < l; i++) - { - if (compareChars(search.charAt(idx++), search.charAt(s + i), caseFold) != 0) - { - return -1; - } - } - } - break; - - case OP_BOL: - - // Fail if we're not at the start of the string - if (idx != 0) - { - // If we're multiline matching, we could still be at the start of a line - if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE) - { - // If not at start of line, give up - if (idx <= 0 || !isNewline(idx - 1)) { - return -1; - } else { - break; - } - } - return -1; - } - break; - - case OP_EOL: - - // If we're not at the end of string - if (!search.isEnd(0) && !search.isEnd(idx)) - { - // If we're multi-line matching - if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE) - { - // Give up if we're not at the end of a line - if (!isNewline(idx)) { - return -1; - } else { - break; - } - } - return -1; - } - break; - - case OP_ESCAPE: - - // Which escape? - switch (opdata) - { - // Word boundary match - case E_NBOUND: - case E_BOUND: - { - char cLast = ((idx == 0) ? '\n' : search.charAt(idx - 1)); - char cNext = ((search.isEnd(idx)) ? '\n' : search.charAt(idx)); - if ((Character.isLetterOrDigit(cLast) == Character.isLetterOrDigit(cNext)) == (opdata == E_BOUND)) - { - return -1; - } - } - break; - - // Alpha-numeric, digit, space, javaLetter, javaLetterOrDigit - case E_ALNUM: - case E_NALNUM: - case E_DIGIT: - case E_NDIGIT: - case E_SPACE: - case E_NSPACE: - - // Give up if out of input - if (search.isEnd(idx)) - { - return -1; - } - - char c = search.charAt(idx); - - // Switch on escape - switch (opdata) - { - case E_ALNUM: - case E_NALNUM: - if (!((Character.isLetterOrDigit(c) || c == '_') == (opdata == E_ALNUM))) - { - return -1; - } - break; - - case E_DIGIT: - case E_NDIGIT: - if (!(Character.isDigit(c) == (opdata == E_DIGIT))) - { - return -1; - } - break; - - case E_SPACE: - case E_NSPACE: - if (!(Character.isWhitespace(c) == (opdata == E_SPACE))) - { - return -1; - } - break; - } - idx++; - break; - - default: - internalError("Unrecognized escape '" + opdata + "'"); - } - break; - - case OP_ANY: - - if ((matchFlags & MATCH_SINGLELINE) == MATCH_SINGLELINE) { - // Match anything - if (search.isEnd(idx)) - { - return -1; - } - } - else - { - // Match anything but a newline - if (search.isEnd(idx) || isNewline(idx)) - { - return -1; - } - } - idx++; - break; - - case OP_ATOM: - { - // Match an atom value - if (search.isEnd(idx)) - { - return -1; - } - - // Get length of atom and starting index - int lenAtom = opdata; - int startAtom = node + nodeSize; - - // Give up if not enough input remains to have a match - if (search.isEnd(lenAtom + idx - 1)) - { - return -1; - } - - // Match atom differently depending on casefolding flag - final boolean caseFold = - ((matchFlags & MATCH_CASEINDEPENDENT) != 0); - - for (int i = 0; i < lenAtom; i++) - { - if (compareChars(search.charAt(idx++), instruction[startAtom + i], caseFold) != 0) - { - return -1; - } - } - } - break; - - case OP_POSIXCLASS: - { - // Out of input? - if (search.isEnd(idx)) - { - return -1; - } - - switch (opdata) - { - case POSIX_CLASS_ALNUM: - if (!Character.isLetterOrDigit(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_ALPHA: - if (!Character.isLetter(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_DIGIT: - if (!Character.isDigit(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_BLANK: // JWL - bugbug: is this right?? - if (!Character.isSpaceChar(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_SPACE: - if (!Character.isWhitespace(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_CNTRL: - if (Character.getType(search.charAt(idx)) != Character.CONTROL) - { - return -1; - } - break; - - case POSIX_CLASS_GRAPH: // JWL - bugbug??? - switch (Character.getType(search.charAt(idx))) - { - case Character.MATH_SYMBOL: - case Character.CURRENCY_SYMBOL: - case Character.MODIFIER_SYMBOL: - case Character.OTHER_SYMBOL: - break; - - default: - return -1; - } - break; - - case POSIX_CLASS_LOWER: - if (Character.getType(search.charAt(idx)) != Character.LOWERCASE_LETTER) - { - return -1; - } - break; - - case POSIX_CLASS_UPPER: - if (Character.getType(search.charAt(idx)) != Character.UPPERCASE_LETTER) - { - return -1; - } - break; - - case POSIX_CLASS_PRINT: - if (Character.getType(search.charAt(idx)) == Character.CONTROL) - { - return -1; - } - break; - - case POSIX_CLASS_PUNCT: - { - int type = Character.getType(search.charAt(idx)); - switch(type) - { - case Character.DASH_PUNCTUATION: - case Character.START_PUNCTUATION: - case Character.END_PUNCTUATION: - case Character.CONNECTOR_PUNCTUATION: - case Character.OTHER_PUNCTUATION: - break; - - default: - return -1; - } - } - break; - - case POSIX_CLASS_XDIGIT: // JWL - bugbug?? - { - boolean isXDigit = ((search.charAt(idx) >= '0' && search.charAt(idx) <= '9') || - (search.charAt(idx) >= 'a' && search.charAt(idx) <= 'f') || - (search.charAt(idx) >= 'A' && search.charAt(idx) <= 'F')); - if (!isXDigit) - { - return -1; - } - } - break; - - case POSIX_CLASS_JSTART: - if (!Character.isJavaIdentifierStart(search.charAt(idx))) - { - return -1; - } - break; - - case POSIX_CLASS_JPART: - if (!Character.isJavaIdentifierPart(search.charAt(idx))) - { - return -1; - } - break; - - default: - internalError("Bad posix class"); - break; - } - - // Matched. - idx++; - } - break; - - case OP_ANYOF: - { - // Out of input? - if (search.isEnd(idx)) - { - return -1; - } - - // Get character to match against character class and maybe casefold - char c = search.charAt(idx); - boolean caseFold = (matchFlags & MATCH_CASEINDEPENDENT) != 0; - // Loop through character class checking our match character - int idxRange = node + nodeSize; - int idxEnd = idxRange + (opdata * 2); - boolean match = false; - for (int i = idxRange; !match && i < idxEnd; ) - { - // Get start, end and match characters - char s = instruction[i++]; - char e = instruction[i++]; - - match = ((compareChars(c, s, caseFold) >= 0) - && (compareChars(c, e, caseFold) <= 0)); - } - - // Fail if we didn't match the character class - if (!match) - { - return -1; - } - idx++; - } - break; - - case OP_BRANCH: - { - // Check for choices - if (instruction[next + offsetOpcode] != OP_BRANCH) - { - // If there aren't any other choices, just evaluate this branch. - node += nodeSize; - continue; - } - - // Try all available branches - short nextBranch; - do - { - // Try matching the branch against the string - if ((idxNew = matchNodes(node + nodeSize, maxNode, idx)) != -1) - { - return idxNew; - } - - // Go to next branch (if any) - nextBranch = (short)instruction[node + offsetNext]; - node += nextBranch; - } - while (nextBranch != 0 && (instruction[node + offsetOpcode] == OP_BRANCH)); - - // Failed to match any branch! - return -1; - } - - case OP_NOTHING: - case OP_GOTO: - - // Just advance to the next node without doing anything - break; - - case OP_END: - - // Match has succeeded! - setParenEnd(0, idx); - return idx; - - default: - - // Corrupt program - internalError("Invalid opcode '" + opcode + "'"); - } - - // Advance to the next node in the program - node = next; - } - - // We "should" never end up here - internalError("Corrupt program"); - return -1; - } - - /** - * Match the current regular expression program against the current - * input string, starting at index i of the input string. This method - * is only meant for internal use. - * - * @param i The input string index to start matching at - * @return True if the input matched the expression - */ - protected boolean matchAt(int i) - { - // Initialize start pointer, paren cache and paren count - start0 = -1; - end0 = -1; - start1 = -1; - end1 = -1; - start2 = -1; - end2 = -1; - startn = null; - endn = null; - parenCount = 1; - setParenStart(0, i); - - // Allocate backref arrays (unless optimizations indicate otherwise) - if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) - { - startBackref = new int[maxParen]; - endBackref = new int[maxParen]; - } - - // Match against string - int idx; - if ((idx = matchNodes(0, maxNode, i)) != -1) - { - setParenEnd(0, idx); - return true; - } - - // Didn't match - parenCount = 0; - return false; - } - - /** - * Matches the current regular expression program against a character array, - * starting at a given index. - * - * @param search String to match against - * @param i Index to start searching at - * @return True if string matched - */ - public boolean match(String search, int i) - { - return match(new StringCharacterIterator(search), i); - } - - /** - * Matches the current regular expression program against a character array, - * starting at a given index. - * - * @param search String to match against - * @param i Index to start searching at - * @return True if string matched - */ - public boolean match(CharacterIterator search, int i) - { - // There is no compiled program to search with! - if (program == null) - { - // This should be uncommon enough to be an error case rather - // than an exception (which would have to be handled everywhere) - internalError("No RE program to run!"); - } - - // Save string to search - this.search = search; - - // Can we optimize the search by looking for a prefix string? - if (program.prefix == null) - { - // Unprefixed matching must try for a match at each character - for ( ;! search.isEnd(i - 1); i++) - { - // Try a match at index i - if (matchAt(i)) - { - return true; - } - } - return false; - } - else - { - // Prefix-anchored matching is possible - boolean caseIndependent = (matchFlags & MATCH_CASEINDEPENDENT) != 0; - char[] prefix = program.prefix; - for ( ; !search.isEnd(i + prefix.length - 1); i++) - { - int j = i; - int k = 0; - - boolean match; - do { - // If there's a mismatch of any character in the prefix, give up - match = (compareChars(search.charAt(j++), prefix[k++], caseIndependent) == 0); - } while (match && k < prefix.length); - - // See if the whole prefix string matched - if (k == prefix.length) - { - // We matched the full prefix at firstChar, so try it - if (matchAt(i)) - { - return true; - } - } - } - return false; - } - } - - /** - * Matches the current regular expression program against a String. - * - * @param search String to match against - * @return True if string matched - */ - public boolean match(String search) - { - return match(search, 0); - } - - /** - * Splits a string into an array of strings on regular expression boundaries. - * This function works the same way as the Perl function of the same name. - * Given a regular expression of "[ab]+" and a string to split of - * "xyzzyababbayyzabbbab123", the result would be the array of Strings - * "[xyzzy, yyz, 123]". - * - *

Please note that the first string in the resulting array may be an empty - * string. This happens when the very first character of input string is - * matched by the pattern. - * - * @param s String to split on this regular exression - * @return Array of strings - */ - public String[] split(String s) - { - // Create new vector - Vector v = new Vector(); - - // Start at position 0 and search the whole string - int pos = 0; - int len = s.length(); - - // Try a match at each position - while (pos < len && match(s, pos)) - { - // Get start of match - int start = getParenStart(0); - - // Get end of match - int newpos = getParenEnd(0); - - // Check if no progress was made - if (newpos == pos) - { - v.addElement(s.substring(pos, start + 1)); - newpos++; - } - else - { - v.addElement(s.substring(pos, start)); - } - - // Move to new position - pos = newpos; - } - - // Push remainder if it's not empty - String remainder = s.substring(pos); - if (remainder.length() != 0) - { - v.addElement(remainder); - } - - // Return vector as an array of strings - String[] ret = new String[v.size()]; - v.copyInto(ret); - return ret; - } - - /** - * Flag bit that indicates that subst should replace all occurrences of this - * regular expression. - */ - public static final int REPLACE_ALL = 0x0000; - - /** - * Flag bit that indicates that subst should only replace the first occurrence - * of this regular expression. - */ - public static final int REPLACE_FIRSTONLY = 0x0001; - - /** - * Flag bit that indicates that subst should replace backreferences - */ - public static final int REPLACE_BACKREFERENCES = 0x0002; - - /** - * Substitutes a string for this regular expression in another string. - * This method works like the Perl function of the same name. - * Given a regular expression of "a*b", a String to substituteIn of - * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the - * resulting String returned by subst would be "-foo-garply-wacky-". - * - * @param substituteIn String to substitute within - * @param substitution String to substitute for all matches of this regular expression. - * @return The string substituteIn with zero or more occurrences of the current - * regular expression replaced with the substitution String (if this regular - * expression object doesn't match at any position, the original String is returned - * unchanged). - */ - public String subst(String substituteIn, String substitution) - { - return subst(substituteIn, substitution, REPLACE_ALL); - } - - /** - * Substitutes a string for this regular expression in another string. - * This method works like the Perl function of the same name. - * Given a regular expression of "a*b", a String to substituteIn of - * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the - * resulting String returned by subst would be "-foo-garply-wacky-". - *

- * It is also possible to reference the contents of a parenthesized expression - * with $0, $1, ... $9. A regular expression of "http://[\\.\\w\\-\\?/~_@&=%]+", - * a String to substituteIn of "visit us: http://www.apache.org!" and the - * substitution String "<a href=\"$0\">$0</a>", the resulting String - * returned by subst would be - * "visit us: <a href=\"http://www.apache.org\">http://www.apache.org</a>!". - *

- * Note: $0 represents the whole match. - * - * @param substituteIn String to substitute within - * @param substitution String to substitute for matches of this regular expression - * @param flags One or more bitwise flags from REPLACE_*. If the REPLACE_FIRSTONLY - * flag bit is set, only the first occurrence of this regular expression is replaced. - * If the bit is not set (REPLACE_ALL), all occurrences of this pattern will be - * replaced. If the flag REPLACE_BACKREFERENCES is set, all backreferences will - * be processed. - * @return The string substituteIn with zero or more occurrences of the current - * regular expression replaced with the substitution String (if this regular - * expression object doesn't match at any position, the original String is returned - * unchanged). - */ - public String subst(String substituteIn, String substitution, int flags) - { - // String to return - StringBuffer ret = new StringBuffer(); - - // Start at position 0 and search the whole string - int pos = 0; - int len = substituteIn.length(); - - // Try a match at each position - while (pos < len && match(substituteIn, pos)) - { - // Append string before match - ret.append(substituteIn.substring(pos, getParenStart(0))); - - if ((flags & REPLACE_BACKREFERENCES) != 0) - { - // Process backreferences - int lCurrentPosition = 0; - int lLastPosition = -2; - int lLength = substitution.length(); - boolean bAddedPrefix = false; - - while ((lCurrentPosition = substitution.indexOf("$", lCurrentPosition)) >= 0) - { - if ((lCurrentPosition == 0 || substitution.charAt(lCurrentPosition - 1) != '\\') - && lCurrentPosition+1 < lLength) - { - char c = substitution.charAt(lCurrentPosition + 1); - if (c >= '0' && c <= '9') - { - if (bAddedPrefix == false) - { - // Append everything between the beginning of the - // substitution string and the current $ sign - ret.append(substitution.substring(0, lCurrentPosition)); - bAddedPrefix = true; - } - else - { - // Append everything between the last and the current $ sign - ret.append(substitution.substring(lLastPosition + 2, lCurrentPosition)); - } - - // Append the parenthesized expression - // Note: if a parenthesized expression of the requested - // index is not available "null" is added to the string - ret.append(getParen(c - '0')); - lLastPosition = lCurrentPosition; - } - } - - // Move forward, skipping past match - lCurrentPosition++; - } - - // Append everything after the last $ sign - ret.append(substitution.substring(lLastPosition + 2, lLength)); - } - else - { - // Append substitution without processing backreferences - ret.append(substitution); - } - - // Move forward, skipping past match - int newpos = getParenEnd(0); - - // We always want to make progress! - if (newpos == pos) - { - newpos++; - } - - // Try new position - pos = newpos; - - // Break out if we're only supposed to replace one occurrence - if ((flags & REPLACE_FIRSTONLY) != 0) - { - break; - } - } - - // If there's remaining input, append it - if (pos < len) - { - ret.append(substituteIn.substring(pos)); - } - - // Return string buffer as string - return ret.toString(); - } - - /** - * Returns an array of Strings, whose toString representation matches a regular - * expression. This method works like the Perl function of the same name. Given - * a regular expression of "a*b" and an array of String objects of [foo, aab, zzz, - * aaaab], the array of Strings returned by grep would be [aab, aaaab]. - * - * @param search Array of Objects to search - * @return Array of Strings whose toString() value matches this regular expression. - */ - public String[] grep(Object[] search) - { - // Create new vector to hold return items - Vector v = new Vector(); - - // Traverse array of objects - for (int i = 0; i < search.length; i++) - { - // Get next object as a string - String s = search[i].toString(); - - // If it matches this regexp, add it to the list - if (match(s)) - { - v.addElement(s); - } - } - - // Return vector as an array of strings - String[] ret = new String[v.size()]; - v.copyInto(ret); - return ret; - } - - /** - * @return true if character at i-th position in the search string is a newline - */ - private boolean isNewline(int i) - { - char nextChar = search.charAt(i); - - if (nextChar == '\n' || nextChar == '\r' || nextChar == '\u0085' - || nextChar == '\u2028' || nextChar == '\u2029') - { - return true; - } - - return false; - } - - /** - * Compares two characters. - * - * @param c1 first character to compare. - * @param c2 second character to compare. - * @param caseIndependent whether comparision is case insensitive or not. - * @return negative, 0, or positive integer as the first character - * less than, equal to, or greater then the second. - */ - private int compareChars(char c1, char c2, boolean caseIndependent) - { - if (caseIndependent) - { - c1 = Character.toLowerCase(c1); - c2 = Character.toLowerCase(c2); - } - return ((int)c1 - (int)c2); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RECompiler.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RECompiler.java deleted file mode 100644 index 23874ee8da0..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RECompiler.java +++ /dev/null @@ -1,1520 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import com.sun.org.apache.regexp.internal.RE; -import java.util.Hashtable; - -/** - * A regular expression compiler class. This class compiles a pattern string into a - * regular expression program interpretable by the RE evaluator class. The 'recompile' - * command line tool uses this compiler to pre-compile regular expressions for use - * with RE. For a description of the syntax accepted by RECompiler and what you can - * do with regular expressions, see the documentation for the RE matcher class. - * - * @see RE - * @see recompile - * - * @author Jonathan Locke - * @author Michael McCallum - */ -public class RECompiler -{ - // The compiled program - char[] instruction; // The compiled RE 'program' instruction buffer - int lenInstruction; // The amount of the program buffer currently in use - - // Input state for compiling regular expression - String pattern; // Input string - int len; // Length of the pattern string - int idx; // Current input index into ac - int parens; // Total number of paren pairs - - // Node flags - static final int NODE_NORMAL = 0; // No flags (nothing special) - static final int NODE_NULLABLE = 1; // True if node is potentially null - static final int NODE_TOPLEVEL = 2; // True if top level expr - - // Special types of 'escapes' - static final int ESC_MASK = 0xffff0; // Escape complexity mask - static final int ESC_BACKREF = 0xfffff; // Escape is really a backreference - static final int ESC_COMPLEX = 0xffffe; // Escape isn't really a true character - static final int ESC_CLASS = 0xffffd; // Escape represents a whole class of characters - - // {m,n} stacks - int maxBrackets = 10; // Maximum number of bracket pairs - static final int bracketUnbounded = -1; // Unbounded value - int brackets = 0; // Number of bracket sets - int[] bracketStart = null; // Starting point - int[] bracketEnd = null; // Ending point - int[] bracketMin = null; // Minimum number of matches - int[] bracketOpt = null; // Additional optional matches - - // Lookup table for POSIX character class names - static Hashtable hashPOSIX = new Hashtable(); - static - { - hashPOSIX.put("alnum", new Character(RE.POSIX_CLASS_ALNUM)); - hashPOSIX.put("alpha", new Character(RE.POSIX_CLASS_ALPHA)); - hashPOSIX.put("blank", new Character(RE.POSIX_CLASS_BLANK)); - hashPOSIX.put("cntrl", new Character(RE.POSIX_CLASS_CNTRL)); - hashPOSIX.put("digit", new Character(RE.POSIX_CLASS_DIGIT)); - hashPOSIX.put("graph", new Character(RE.POSIX_CLASS_GRAPH)); - hashPOSIX.put("lower", new Character(RE.POSIX_CLASS_LOWER)); - hashPOSIX.put("print", new Character(RE.POSIX_CLASS_PRINT)); - hashPOSIX.put("punct", new Character(RE.POSIX_CLASS_PUNCT)); - hashPOSIX.put("space", new Character(RE.POSIX_CLASS_SPACE)); - hashPOSIX.put("upper", new Character(RE.POSIX_CLASS_UPPER)); - hashPOSIX.put("xdigit", new Character(RE.POSIX_CLASS_XDIGIT)); - hashPOSIX.put("javastart", new Character(RE.POSIX_CLASS_JSTART)); - hashPOSIX.put("javapart", new Character(RE.POSIX_CLASS_JPART)); - } - - /** - * Constructor. Creates (initially empty) storage for a regular expression program. - */ - public RECompiler() - { - // Start off with a generous, yet reasonable, initial size - instruction = new char[128]; - lenInstruction = 0; - } - - /** - * Ensures that n more characters can fit in the program buffer. - * If n more can't fit, then the size is doubled until it can. - * @param n Number of additional characters to ensure will fit. - */ - void ensure(int n) - { - // Get current program length - int curlen = instruction.length; - - // If the current length + n more is too much - if (lenInstruction + n >= curlen) - { - // Double the size of the program array until n more will fit - while (lenInstruction + n >= curlen) - { - curlen *= 2; - } - - // Allocate new program array and move data into it - char[] newInstruction = new char[curlen]; - System.arraycopy(instruction, 0, newInstruction, 0, lenInstruction); - instruction = newInstruction; - } - } - - /** - * Emit a single character into the program stream. - * @param c Character to add - */ - void emit(char c) - { - // Make room for character - ensure(1); - - // Add character - instruction[lenInstruction++] = c; - } - - /** - * Inserts a node with a given opcode and opdata at insertAt. The node relative next - * pointer is initialized to 0. - * @param opcode Opcode for new node - * @param opdata Opdata for new node (only the low 16 bits are currently used) - * @param insertAt Index at which to insert the new node in the program - */ - void nodeInsert(char opcode, int opdata, int insertAt) - { - // Make room for a new node - ensure(RE.nodeSize); - - // Move everything from insertAt to the end down nodeSize elements - System.arraycopy(instruction, insertAt, instruction, insertAt + RE.nodeSize, lenInstruction - insertAt); - instruction[insertAt + RE.offsetOpcode] = opcode; - instruction[insertAt + RE.offsetOpdata] = (char)opdata; - instruction[insertAt + RE.offsetNext] = 0; - lenInstruction += RE.nodeSize; - } - - /** - * Appends a node to the end of a node chain - * @param node Start of node chain to traverse - * @param pointTo Node to have the tail of the chain point to - */ - void setNextOfEnd(int node, int pointTo) - { - // Traverse the chain until the next offset is 0 - int next = instruction[node + RE.offsetNext]; - // while the 'node' is not the last in the chain - // and the 'node' is not the last in the program. - while ( next != 0 && node < lenInstruction ) - { - // if the node we are supposed to point to is in the chain then - // point to the end of the program instead. - // Michael McCallum - // FIXME: // This is a _hack_ to stop infinite programs. - // I believe that the implementation of the reluctant matches is wrong but - // have not worked out a better way yet. - if ( node == pointTo ) { - pointTo = lenInstruction; - } - node += next; - next = instruction[node + RE.offsetNext]; - } - // if we have reached the end of the program then dont set the pointTo. - // im not sure if this will break any thing but passes all the tests. - if ( node < lenInstruction ) { - // Point the last node in the chain to pointTo. - instruction[node + RE.offsetNext] = (char)(short)(pointTo - node); - } - } - - /** - * Adds a new node - * @param opcode Opcode for node - * @param opdata Opdata for node (only the low 16 bits are currently used) - * @return Index of new node in program - */ - int node(char opcode, int opdata) - { - // Make room for a new node - ensure(RE.nodeSize); - - // Add new node at end - instruction[lenInstruction + RE.offsetOpcode] = opcode; - instruction[lenInstruction + RE.offsetOpdata] = (char)opdata; - instruction[lenInstruction + RE.offsetNext] = 0; - lenInstruction += RE.nodeSize; - - // Return index of new node - return lenInstruction - RE.nodeSize; - } - - - /** - * Throws a new internal error exception - * @exception Error Thrown in the event of an internal error. - */ - void internalError() throws Error - { - throw new Error("Internal error!"); - } - - /** - * Throws a new syntax error exception - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - void syntaxError(String s) throws RESyntaxException - { - throw new RESyntaxException(s); - } - - /** - * Allocate storage for brackets only as needed - */ - void allocBrackets() - { - // Allocate bracket stacks if not already done - if (bracketStart == null) - { - // Allocate storage - bracketStart = new int[maxBrackets]; - bracketEnd = new int[maxBrackets]; - bracketMin = new int[maxBrackets]; - bracketOpt = new int[maxBrackets]; - - // Initialize to invalid values - for (int i = 0; i < maxBrackets; i++) - { - bracketStart[i] = bracketEnd[i] = bracketMin[i] = bracketOpt[i] = -1; - } - } - } - - /** Enlarge storage for brackets only as needed. */ - synchronized void reallocBrackets() { - // trick the tricky - if (bracketStart == null) { - allocBrackets(); - } - - int new_size = maxBrackets * 2; - int[] new_bS = new int[new_size]; - int[] new_bE = new int[new_size]; - int[] new_bM = new int[new_size]; - int[] new_bO = new int[new_size]; - // Initialize to invalid values - for (int i=brackets; i= len || pattern.charAt(idx++) != '{') - { - internalError(); - } - - // Next char must be a digit - if (idx >= len || !Character.isDigit(pattern.charAt(idx))) - { - syntaxError("Expected digit"); - } - - // Get min ('m' of {m,n}) number - StringBuffer number = new StringBuffer(); - while (idx < len && Character.isDigit(pattern.charAt(idx))) - { - number.append(pattern.charAt(idx++)); - } - try - { - bracketMin[brackets] = Integer.parseInt(number.toString()); - } - catch (NumberFormatException e) - { - syntaxError("Expected valid number"); - } - - // If out of input, fail - if (idx >= len) - { - syntaxError("Expected comma or right bracket"); - } - - // If end of expr, optional limit is 0 - if (pattern.charAt(idx) == '}') - { - idx++; - bracketOpt[brackets] = 0; - return; - } - - // Must have at least {m,} and maybe {m,n}. - if (idx >= len || pattern.charAt(idx++) != ',') - { - syntaxError("Expected comma"); - } - - // If out of input, fail - if (idx >= len) - { - syntaxError("Expected comma or right bracket"); - } - - // If {m,} max is unlimited - if (pattern.charAt(idx) == '}') - { - idx++; - bracketOpt[brackets] = bracketUnbounded; - return; - } - - // Next char must be a digit - if (idx >= len || !Character.isDigit(pattern.charAt(idx))) - { - syntaxError("Expected digit"); - } - - // Get max number - number.setLength(0); - while (idx < len && Character.isDigit(pattern.charAt(idx))) - { - number.append(pattern.charAt(idx++)); - } - try - { - bracketOpt[brackets] = Integer.parseInt(number.toString()) - bracketMin[brackets]; - } - catch (NumberFormatException e) - { - syntaxError("Expected valid number"); - } - - // Optional repetitions must be >= 0 - if (bracketOpt[brackets] < 0) - { - syntaxError("Bad range"); - } - - // Must have close brace - if (idx >= len || pattern.charAt(idx++) != '}') - { - syntaxError("Missing close brace"); - } - } - - /** - * Match an escape sequence. Handles quoted chars and octal escapes as well - * as normal escape characters. Always advances the input stream by the - * right amount. This code "understands" the subtle difference between an - * octal escape and a backref. You can access the type of ESC_CLASS or - * ESC_COMPLEX or ESC_BACKREF by looking at pattern[idx - 1]. - * @return ESC_* code or character if simple escape - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int escape() throws RESyntaxException - { - // "Shouldn't" happen - if (pattern.charAt(idx) != '\\') - { - internalError(); - } - - // Escape shouldn't occur as last character in string! - if (idx + 1 == len) - { - syntaxError("Escape terminates string"); - } - - // Switch on character after backslash - idx += 2; - char escapeChar = pattern.charAt(idx - 1); - switch (escapeChar) - { - case RE.E_BOUND: - case RE.E_NBOUND: - return ESC_COMPLEX; - - case RE.E_ALNUM: - case RE.E_NALNUM: - case RE.E_SPACE: - case RE.E_NSPACE: - case RE.E_DIGIT: - case RE.E_NDIGIT: - return ESC_CLASS; - - case 'u': - case 'x': - { - // Exact required hex digits for escape type - int hexDigits = (escapeChar == 'u' ? 4 : 2); - - // Parse up to hexDigits characters from input - int val = 0; - for ( ; idx < len && hexDigits-- > 0; idx++) - { - // Get char - char c = pattern.charAt(idx); - - // If it's a hexadecimal digit (0-9) - if (c >= '0' && c <= '9') - { - // Compute new value - val = (val << 4) + c - '0'; - } - else - { - // If it's a hexadecimal letter (a-f) - c = Character.toLowerCase(c); - if (c >= 'a' && c <= 'f') - { - // Compute new value - val = (val << 4) + (c - 'a') + 10; - } - else - { - // If it's not a valid digit or hex letter, the escape must be invalid - // because hexDigits of input have not been absorbed yet. - syntaxError("Expected " + hexDigits + " hexadecimal digits after \\" + escapeChar); - } - } - } - return val; - } - - case 't': - return '\t'; - - case 'n': - return '\n'; - - case 'r': - return '\r'; - - case 'f': - return '\f'; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - - // An octal escape starts with a 0 or has two digits in a row - if ((idx < len && Character.isDigit(pattern.charAt(idx))) || escapeChar == '0') - { - // Handle \nnn octal escapes - int val = escapeChar - '0'; - if (idx < len && Character.isDigit(pattern.charAt(idx))) - { - val = ((val << 3) + (pattern.charAt(idx++) - '0')); - if (idx < len && Character.isDigit(pattern.charAt(idx))) - { - val = ((val << 3) + (pattern.charAt(idx++) - '0')); - } - } - return val; - } - - // It's actually a backreference (\[1-9]), not an escape - return ESC_BACKREF; - - default: - - // Simple quoting of a character - return escapeChar; - } - } - - /** - * Compile a character class - * @return Index of class node - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int characterClass() throws RESyntaxException - { - // Check for bad calling or empty class - if (pattern.charAt(idx) != '[') - { - internalError(); - } - - // Check for unterminated or empty class - if ((idx + 1) >= len || pattern.charAt(++idx) == ']') - { - syntaxError("Empty or unterminated class"); - } - - // Check for POSIX character class - if (idx < len && pattern.charAt(idx) == ':') - { - // Skip colon - idx++; - - // POSIX character classes are denoted with lowercase ASCII strings - int idxStart = idx; - while (idx < len && pattern.charAt(idx) >= 'a' && pattern.charAt(idx) <= 'z') - { - idx++; - } - - // Should be a ":]" to terminate the POSIX character class - if ((idx + 1) < len && pattern.charAt(idx) == ':' && pattern.charAt(idx + 1) == ']') - { - // Get character class - String charClass = pattern.substring(idxStart, idx); - - // Select the POSIX class id - Character i = (Character)hashPOSIX.get(charClass); - if (i != null) - { - // Move past colon and right bracket - idx += 2; - - // Return new POSIX character class node - return node(RE.OP_POSIXCLASS, i.charValue()); - } - syntaxError("Invalid POSIX character class '" + charClass + "'"); - } - syntaxError("Invalid POSIX character class syntax"); - } - - // Try to build a class. Create OP_ANYOF node - int ret = node(RE.OP_ANYOF, 0); - - // Parse class declaration - char CHAR_INVALID = Character.MAX_VALUE; - char last = CHAR_INVALID; - char simpleChar = 0; - boolean include = true; - boolean definingRange = false; - int idxFirst = idx; - char rangeStart = Character.MIN_VALUE; - char rangeEnd; - RERange range = new RERange(); - while (idx < len && pattern.charAt(idx) != ']') - { - - switchOnCharacter: - - // Switch on character - switch (pattern.charAt(idx)) - { - case '^': - include = !include; - if (idx == idxFirst) - { - range.include(Character.MIN_VALUE, Character.MAX_VALUE, true); - } - idx++; - continue; - - case '\\': - { - // Escape always advances the stream - int c; - switch (c = escape ()) - { - case ESC_COMPLEX: - case ESC_BACKREF: - - // Word boundaries and backrefs not allowed in a character class! - syntaxError("Bad character class"); - - case ESC_CLASS: - - // Classes can't be an endpoint of a range - if (definingRange) - { - syntaxError("Bad character class"); - } - - // Handle specific type of class (some are ok) - switch (pattern.charAt(idx - 1)) - { - case RE.E_NSPACE: - case RE.E_NDIGIT: - case RE.E_NALNUM: - syntaxError("Bad character class"); - - case RE.E_SPACE: - range.include('\t', include); - range.include('\r', include); - range.include('\f', include); - range.include('\n', include); - range.include('\b', include); - range.include(' ', include); - break; - - case RE.E_ALNUM: - range.include('a', 'z', include); - range.include('A', 'Z', include); - range.include('_', include); - - // Fall through! - - case RE.E_DIGIT: - range.include('0', '9', include); - break; - } - - // Make last char invalid (can't be a range start) - last = CHAR_INVALID; - break; - - default: - - // Escape is simple so treat as a simple char - simpleChar = (char) c; - break switchOnCharacter; - } - } - continue; - - case '-': - - // Start a range if one isn't already started - if (definingRange) - { - syntaxError("Bad class range"); - } - definingRange = true; - - // If no last character, start of range is 0 - rangeStart = (last == CHAR_INVALID ? 0 : last); - - // Premature end of range. define up to Character.MAX_VALUE - if ((idx + 1) < len && pattern.charAt(++idx) == ']') - { - simpleChar = Character.MAX_VALUE; - break; - } - continue; - - default: - simpleChar = pattern.charAt(idx++); - break; - } - - // Handle simple character simpleChar - if (definingRange) - { - // if we are defining a range make it now - rangeEnd = simpleChar; - - // Actually create a range if the range is ok - if (rangeStart >= rangeEnd) - { - syntaxError("Bad character class"); - } - range.include(rangeStart, rangeEnd, include); - - // We are done defining the range - last = CHAR_INVALID; - definingRange = false; - } - else - { - // If simple character and not start of range, include it - if (idx >= len || pattern.charAt(idx) != '-') - { - range.include(simpleChar, include); - } - last = simpleChar; - } - } - - // Shouldn't be out of input - if (idx == len) - { - syntaxError("Unterminated character class"); - } - - // Absorb the ']' end of class marker - idx++; - - // Emit character class definition - instruction[ret + RE.offsetOpdata] = (char)range.num; - for (int i = 0; i < range.num; i++) - { - emit((char)range.minRange[i]); - emit((char)range.maxRange[i]); - } - return ret; - } - - /** - * Absorb an atomic character string. This method is a little tricky because - * it can un-include the last character of string if a closure operator follows. - * This is correct because *+? have higher precedence than concatentation (thus - * ABC* means AB(C*) and NOT (ABC)*). - * @return Index of new atom node - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int atom() throws RESyntaxException - { - // Create a string node - int ret = node(RE.OP_ATOM, 0); - - // Length of atom - int lenAtom = 0; - - // Loop while we've got input - - atomLoop: - - while (idx < len) - { - // Is there a next char? - if ((idx + 1) < len) - { - char c = pattern.charAt(idx + 1); - - // If the next 'char' is an escape, look past the whole escape - if (pattern.charAt(idx) == '\\') - { - int idxEscape = idx; - escape(); - if (idx < len) - { - c = pattern.charAt(idx); - } - idx = idxEscape; - } - - // Switch on next char - switch (c) - { - case '{': - case '?': - case '*': - case '+': - - // If the next character is a closure operator and our atom is non-empty, the - // current character should bind to the closure operator rather than the atom - if (lenAtom != 0) - { - break atomLoop; - } - } - } - - // Switch on current char - switch (pattern.charAt(idx)) - { - case ']': - case '^': - case '$': - case '.': - case '[': - case '(': - case ')': - case '|': - break atomLoop; - - case '{': - case '?': - case '*': - case '+': - - // We should have an atom by now - if (lenAtom == 0) - { - // No atom before closure - syntaxError("Missing operand to closure"); - } - break atomLoop; - - case '\\': - - { - // Get the escaped character (advances input automatically) - int idxBeforeEscape = idx; - int c = escape(); - - // Check if it's a simple escape (as opposed to, say, a backreference) - if ((c & ESC_MASK) == ESC_MASK) - { - // Not a simple escape, so backup to where we were before the escape. - idx = idxBeforeEscape; - break atomLoop; - } - - // Add escaped char to atom - emit((char) c); - lenAtom++; - } - break; - - default: - - // Add normal character to atom - emit(pattern.charAt(idx++)); - lenAtom++; - break; - } - } - - // This "shouldn't" happen - if (lenAtom == 0) - { - internalError(); - } - - // Emit the atom length into the program - instruction[ret + RE.offsetOpdata] = (char)lenAtom; - return ret; - } - - /** - * Match a terminal node. - * @param flags Flags - * @return Index of terminal node (closeable) - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int terminal(int[] flags) throws RESyntaxException - { - switch (pattern.charAt(idx)) - { - case RE.OP_EOL: - case RE.OP_BOL: - case RE.OP_ANY: - return node(pattern.charAt(idx++), 0); - - case '[': - return characterClass(); - - case '(': - return expr(flags); - - case ')': - syntaxError("Unexpected close paren"); - - case '|': - internalError(); - - case ']': - syntaxError("Mismatched class"); - - case 0: - syntaxError("Unexpected end of input"); - - case '?': - case '+': - case '{': - case '*': - syntaxError("Missing operand to closure"); - - case '\\': - { - // Don't forget, escape() advances the input stream! - int idxBeforeEscape = idx; - - // Switch on escaped character - switch (escape()) - { - case ESC_CLASS: - case ESC_COMPLEX: - flags[0] &= ~NODE_NULLABLE; - return node(RE.OP_ESCAPE, pattern.charAt(idx - 1)); - - case ESC_BACKREF: - { - char backreference = (char)(pattern.charAt(idx - 1) - '0'); - if (parens <= backreference) - { - syntaxError("Bad backreference"); - } - flags[0] |= NODE_NULLABLE; - return node(RE.OP_BACKREF, backreference); - } - - default: - - // We had a simple escape and we want to have it end up in - // an atom, so we back up and fall though to the default handling - idx = idxBeforeEscape; - flags[0] &= ~NODE_NULLABLE; - break; - } - } - } - - // Everything above either fails or returns. - // If it wasn't one of the above, it must be the start of an atom. - flags[0] &= ~NODE_NULLABLE; - return atom(); - } - - /** - * Compile a possibly closured terminal - * @param flags Flags passed by reference - * @return Index of closured node - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int closure(int[] flags) throws RESyntaxException - { - // Before terminal - int idxBeforeTerminal = idx; - - // Values to pass by reference to terminal() - int[] terminalFlags = { NODE_NORMAL }; - - // Get terminal symbol - int ret = terminal(terminalFlags); - - // Or in flags from terminal symbol - flags[0] |= terminalFlags[0]; - - // Advance input, set NODE_NULLABLE flag and do sanity checks - if (idx >= len) - { - return ret; - } - boolean greedy = true; - char closureType = pattern.charAt(idx); - switch (closureType) - { - case '?': - case '*': - - // The current node can be null - flags[0] |= NODE_NULLABLE; - - case '+': - - // Eat closure character - idx++; - - case '{': - - // Don't allow blantant stupidity - int opcode = instruction[ret + RE.offsetOpcode]; - if (opcode == RE.OP_BOL || opcode == RE.OP_EOL) - { - syntaxError("Bad closure operand"); - } - if ((terminalFlags[0] & NODE_NULLABLE) != 0) - { - syntaxError("Closure operand can't be nullable"); - } - break; - } - - // If the next character is a '?', make the closure non-greedy (reluctant) - if (idx < len && pattern.charAt(idx) == '?') - { - idx++; - greedy = false; - } - - if (greedy) - { - // Actually do the closure now - switch (closureType) - { - case '{': - { - // We look for our bracket in the list - boolean found = false; - int i; - allocBrackets(); - for (i = 0; i < brackets; i++) - { - if (bracketStart[i] == idx) - { - found = true; - break; - } - } - - // If its not in the list we parse the {m,n} - if (!found) - { - if (brackets >= maxBrackets) - { - reallocBrackets(); - } - bracketStart[brackets] = idx; - bracket(); - bracketEnd[brackets] = idx; - i = brackets++; - } - - // Process min first - if (bracketMin[i]-- > 0) - { - if (bracketMin[i] > 0 || bracketOpt[i] != 0) { - // Rewind stream and run it through again - more matchers coming - for (int j = 0; j < brackets; j++) { - if (j != i && bracketStart[j] < idx - && bracketStart[j] >= idxBeforeTerminal) - { - brackets--; - bracketStart[j] = bracketStart[brackets]; - bracketEnd[j] = bracketEnd[brackets]; - bracketMin[j] = bracketMin[brackets]; - bracketOpt[j] = bracketOpt[brackets]; - } - } - - idx = idxBeforeTerminal; - } else { - // Bug #1030: No optinal matches - no need to rewind - idx = bracketEnd[i]; - } - break; - } - - // Do the right thing for maximum ({m,}) - if (bracketOpt[i] == bracketUnbounded) - { - // Drop through now and closure expression. - // We are done with the {m,} expr, so skip rest - closureType = '*'; - bracketOpt[i] = 0; - idx = bracketEnd[i]; - } - else - if (bracketOpt[i]-- > 0) - { - if (bracketOpt[i] > 0) - { - // More optional matchers - 'play it again sam!' - idx = idxBeforeTerminal; - } else { - // Bug #1030: We are done - this one is last and optional - idx = bracketEnd[i]; - } - // Drop through to optionally close - closureType = '?'; - } - else - { - // Rollback terminal - neither min nor opt matchers present - lenInstruction = ret; - node(RE.OP_NOTHING, 0); - - // We are done. skip the rest of {m,n} expr - idx = bracketEnd[i]; - break; - } - } - - // Fall through! - - case '?': - case '*': - - if (!greedy) - { - break; - } - - if (closureType == '?') - { - // X? is compiled as (X|) - nodeInsert(RE.OP_BRANCH, 0, ret); // branch before X - setNextOfEnd(ret, node (RE.OP_BRANCH, 0)); // inserted branch to option - int nothing = node (RE.OP_NOTHING, 0); // which is OP_NOTHING - setNextOfEnd(ret, nothing); // point (second) branch to OP_NOTHING - setNextOfEnd(ret + RE.nodeSize, nothing); // point the end of X to OP_NOTHING node - } - - if (closureType == '*') - { - // X* is compiled as (X{gotoX}|) - nodeInsert(RE.OP_BRANCH, 0, ret); // branch before X - setNextOfEnd(ret + RE.nodeSize, node(RE.OP_BRANCH, 0)); // end of X points to an option - setNextOfEnd(ret + RE.nodeSize, node(RE.OP_GOTO, 0)); // to goto - setNextOfEnd(ret + RE.nodeSize, ret); // the start again - setNextOfEnd(ret, node(RE.OP_BRANCH, 0)); // the other option is - setNextOfEnd(ret, node(RE.OP_NOTHING, 0)); // OP_NOTHING - } - break; - - case '+': - { - // X+ is compiled as X({gotoX}|) - int branch; - branch = node(RE.OP_BRANCH, 0); // a new branch - setNextOfEnd(ret, branch); // is added to the end of X - setNextOfEnd(node(RE.OP_GOTO, 0), ret); // one option is to go back to the start - setNextOfEnd(branch, node(RE.OP_BRANCH, 0)); // the other option - setNextOfEnd(ret, node(RE.OP_NOTHING, 0)); // is OP_NOTHING - } - break; - } - } - else - { - // Add end after closured subexpr - setNextOfEnd(ret, node(RE.OP_END, 0)); - - // Actually do the closure now - switch (closureType) - { - case '?': - nodeInsert(RE.OP_RELUCTANTMAYBE, 0, ret); - break; - - case '*': - nodeInsert(RE.OP_RELUCTANTSTAR, 0, ret); - break; - - case '+': - nodeInsert(RE.OP_RELUCTANTPLUS, 0, ret); - break; - } - - // Point to the expr after the closure - setNextOfEnd(ret, lenInstruction); - } - return ret; - } - - /** - * Compile one branch of an or operator (implements concatenation) - * @param flags Flags passed by reference - * @return Pointer to branch node - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int branch(int[] flags) throws RESyntaxException - { - // Get each possibly closured piece and concat - int node; - int ret = node(RE.OP_BRANCH, 0); - int chain = -1; - int[] closureFlags = new int[1]; - boolean nullable = true; - while (idx < len && pattern.charAt(idx) != '|' && pattern.charAt(idx) != ')') - { - // Get new node - closureFlags[0] = NODE_NORMAL; - node = closure(closureFlags); - if (closureFlags[0] == NODE_NORMAL) - { - nullable = false; - } - - // If there's a chain, append to the end - if (chain != -1) - { - setNextOfEnd(chain, node); - } - - // Chain starts at current - chain = node; - } - - // If we don't run loop, make a nothing node - if (chain == -1) - { - node(RE.OP_NOTHING, 0); - } - - // Set nullable flag for this branch - if (nullable) - { - flags[0] |= NODE_NULLABLE; - } - return ret; - } - - /** - * Compile an expression with possible parens around it. Paren matching - * is done at this level so we can tie the branch tails together. - * @param flags Flag value passed by reference - * @return Node index of expression in instruction array - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - */ - int expr(int[] flags) throws RESyntaxException - { - // Create open paren node unless we were called from the top level (which has no parens) - int paren = -1; - int ret = -1; - int closeParens = parens; - if ((flags[0] & NODE_TOPLEVEL) == 0 && pattern.charAt(idx) == '(') - { - // if its a cluster ( rather than a proper subexpression ie with backrefs ) - if ( idx + 2 < len && pattern.charAt( idx + 1 ) == '?' && pattern.charAt( idx + 2 ) == ':' ) - { - paren = 2; - idx += 3; - ret = node( RE.OP_OPEN_CLUSTER, 0 ); - } - else - { - paren = 1; - idx++; - ret = node(RE.OP_OPEN, parens++); - } - } - flags[0] &= ~NODE_TOPLEVEL; - - // Create a branch node - int branch = branch(flags); - if (ret == -1) - { - ret = branch; - } - else - { - setNextOfEnd(ret, branch); - } - - // Loop through branches - while (idx < len && pattern.charAt(idx) == '|') - { - idx++; - branch = branch(flags); - setNextOfEnd(ret, branch); - } - - // Create an ending node (either a close paren or an OP_END) - int end; - if ( paren > 0 ) - { - if (idx < len && pattern.charAt(idx) == ')') - { - idx++; - } - else - { - syntaxError("Missing close paren"); - } - if ( paren == 1 ) - { - end = node(RE.OP_CLOSE, closeParens); - } - else - { - end = node( RE.OP_CLOSE_CLUSTER, 0 ); - } - } - else - { - end = node(RE.OP_END, 0); - } - - // Append the ending node to the ret nodelist - setNextOfEnd(ret, end); - - // Hook the ends of each branch to the end node - int currentNode = ret; - int nextNodeOffset = instruction[ currentNode + RE.offsetNext ]; - // while the next node o - while ( nextNodeOffset != 0 && currentNode < lenInstruction ) - { - // If branch, make the end of the branch's operand chain point to the end node. - if ( instruction[ currentNode + RE.offsetOpcode ] == RE.OP_BRANCH ) - { - setNextOfEnd( currentNode + RE.nodeSize, end ); - } - nextNodeOffset = instruction[ currentNode + RE.offsetNext ]; - currentNode += nextNodeOffset; - } - - // Return the node list - return ret; - } - - /** - * Compiles a regular expression pattern into a program runnable by the pattern - * matcher class 'RE'. - * @param pattern Regular expression pattern to compile (see RECompiler class - * for details). - * @return A compiled regular expression program. - * @exception RESyntaxException Thrown if the regular expression has invalid syntax. - * @see RECompiler - * @see RE - */ - public REProgram compile(String pattern) throws RESyntaxException - { - // Initialize variables for compilation - this.pattern = pattern; // Save pattern in instance variable - len = pattern.length(); // Precompute pattern length for speed - idx = 0; // Set parsing index to the first character - lenInstruction = 0; // Set emitted instruction count to zero - parens = 1; // Set paren level to 1 (the implicit outer parens) - brackets = 0; // No bracketed closures yet - - // Initialize pass by reference flags value - int[] flags = { NODE_TOPLEVEL }; - - // Parse expression - expr(flags); - - // Should be at end of input - if (idx != len) - { - if (pattern.charAt(idx) == ')') - { - syntaxError("Unmatched close paren"); - } - syntaxError("Unexpected input remains"); - } - - // Return the result - char[] ins = new char[lenInstruction]; - System.arraycopy(instruction, 0, ins, 0, lenInstruction); - return new REProgram(parens, ins); - } - - /** - * Local, nested class for maintaining character ranges for character classes. - */ - class RERange - { - int size = 16; // Capacity of current range arrays - int[] minRange = new int[size]; // Range minima - int[] maxRange = new int[size]; // Range maxima - int num = 0; // Number of range array elements in use - - /** - * Deletes the range at a given index from the range lists - * @param index Index of range to delete from minRange and maxRange arrays. - */ - void delete(int index) - { - // Return if no elements left or index is out of range - if (num == 0 || index >= num) - { - return; - } - - // Move elements down - while (++index < num) - { - if (index - 1 >= 0) - { - minRange[index-1] = minRange[index]; - maxRange[index-1] = maxRange[index]; - } - } - - // One less element now - num--; - } - - /** - * Merges a range into the range list, coalescing ranges if possible. - * @param min Minimum end of range - * @param max Maximum end of range - */ - void merge(int min, int max) - { - // Loop through ranges - for (int i = 0; i < num; i++) - { - // Min-max is subsumed by minRange[i]-maxRange[i] - if (min >= minRange[i] && max <= maxRange[i]) - { - return; - } - - // Min-max subsumes minRange[i]-maxRange[i] - else if (min <= minRange[i] && max >= maxRange[i]) - { - delete(i); - merge(min, max); - return; - } - - // Min is in the range, but max is outside - else if (min >= minRange[i] && min <= maxRange[i]) - { - delete(i); - min = minRange[i]; - merge(min, max); - return; - } - - // Max is in the range, but min is outside - else if (max >= minRange[i] && max <= maxRange[i]) - { - delete(i); - max = maxRange[i]; - merge(min, max); - return; - } - } - - // Must not overlap any other ranges - if (num >= size) - { - size *= 2; - int[] newMin = new int[size]; - int[] newMax = new int[size]; - System.arraycopy(minRange, 0, newMin, 0, num); - System.arraycopy(maxRange, 0, newMax, 0, num); - minRange = newMin; - maxRange = newMax; - } - minRange[num] = min; - maxRange[num] = max; - num++; - } - - /** - * Removes a range by deleting or shrinking all other ranges - * @param min Minimum end of range - * @param max Maximum end of range - */ - void remove(int min, int max) - { - // Loop through ranges - for (int i = 0; i < num; i++) - { - // minRange[i]-maxRange[i] is subsumed by min-max - if (minRange[i] >= min && maxRange[i] <= max) - { - delete(i); - i--; - return; - } - - // min-max is subsumed by minRange[i]-maxRange[i] - else if (min >= minRange[i] && max <= maxRange[i]) - { - int minr = minRange[i]; - int maxr = maxRange[i]; - delete(i); - if (minr < min) - { - merge(minr, min - 1); - } - if (max < maxr) - { - merge(max + 1, maxr); - } - return; - } - - // minRange is in the range, but maxRange is outside - else if (minRange[i] >= min && minRange[i] <= max) - { - minRange[i] = max + 1; - return; - } - - // maxRange is in the range, but minRange is outside - else if (maxRange[i] >= min && maxRange[i] <= max) - { - maxRange[i] = min - 1; - return; - } - } - } - - /** - * Includes (or excludes) the range from min to max, inclusive. - * @param min Minimum end of range - * @param max Maximum end of range - * @param include True if range should be included. False otherwise. - */ - void include(int min, int max, boolean include) - { - if (include) - { - merge(min, max); - } - else - { - remove(min, max); - } - } - - /** - * Includes a range with the same min and max - * @param minmax Minimum and maximum end of range (inclusive) - * @param include True if range should be included. False otherwise. - */ - void include(char minmax, boolean include) - { - include(minmax, minmax, include); - } - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REDebugCompiler.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REDebugCompiler.java deleted file mode 100644 index 815d4fdfa81..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REDebugCompiler.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import java.io.PrintWriter; -import java.util.Hashtable; - -/** - * A subclass of RECompiler which can dump a regular expression program - * for debugging purposes. - * - * @author Jonathan Locke - */ -public class REDebugCompiler extends RECompiler -{ - /** - * Mapping from opcodes to descriptive strings - */ - static Hashtable hashOpcode = new Hashtable(); - static - { - hashOpcode.put(new Integer(RE.OP_RELUCTANTSTAR), "OP_RELUCTANTSTAR"); - hashOpcode.put(new Integer(RE.OP_RELUCTANTPLUS), "OP_RELUCTANTPLUS"); - hashOpcode.put(new Integer(RE.OP_RELUCTANTMAYBE), "OP_RELUCTANTMAYBE"); - hashOpcode.put(new Integer(RE.OP_END), "OP_END"); - hashOpcode.put(new Integer(RE.OP_BOL), "OP_BOL"); - hashOpcode.put(new Integer(RE.OP_EOL), "OP_EOL"); - hashOpcode.put(new Integer(RE.OP_ANY), "OP_ANY"); - hashOpcode.put(new Integer(RE.OP_ANYOF), "OP_ANYOF"); - hashOpcode.put(new Integer(RE.OP_BRANCH), "OP_BRANCH"); - hashOpcode.put(new Integer(RE.OP_ATOM), "OP_ATOM"); - hashOpcode.put(new Integer(RE.OP_STAR), "OP_STAR"); - hashOpcode.put(new Integer(RE.OP_PLUS), "OP_PLUS"); - hashOpcode.put(new Integer(RE.OP_MAYBE), "OP_MAYBE"); - hashOpcode.put(new Integer(RE.OP_NOTHING), "OP_NOTHING"); - hashOpcode.put(new Integer(RE.OP_GOTO), "OP_GOTO"); - hashOpcode.put(new Integer(RE.OP_ESCAPE), "OP_ESCAPE"); - hashOpcode.put(new Integer(RE.OP_OPEN), "OP_OPEN"); - hashOpcode.put(new Integer(RE.OP_CLOSE), "OP_CLOSE"); - hashOpcode.put(new Integer(RE.OP_BACKREF), "OP_BACKREF"); - hashOpcode.put(new Integer(RE.OP_POSIXCLASS), "OP_POSIXCLASS"); - hashOpcode.put(new Integer(RE.OP_OPEN_CLUSTER), "OP_OPEN_CLUSTER"); - hashOpcode.put(new Integer(RE.OP_CLOSE_CLUSTER), "OP_CLOSE_CLUSTER"); - } - - /** - * Returns a descriptive string for an opcode. - * @param opcode Opcode to convert to a string - * @return Description of opcode - */ - String opcodeToString(char opcode) - { - // Get string for opcode - String ret =(String)hashOpcode.get(new Integer(opcode)); - - // Just in case we have a corrupt program - if (ret == null) - { - ret = "OP_????"; - } - return ret; - } - - /** - * Return a string describing a (possibly unprintable) character. - * @param c Character to convert to a printable representation - * @return String representation of character - */ - String charToString(char c) - { - // If it's unprintable, convert to '\###' - if (c < ' ' || c > 127) - { - return "\\" + (int)c; - } - - // Return the character as a string - return String.valueOf(c); - } - - /** - * Returns a descriptive string for a node in a regular expression program. - * @param node Node to describe - * @return Description of node - */ - String nodeToString(int node) - { - // Get opcode and opdata for node - char opcode = instruction[node + RE.offsetOpcode]; - int opdata = (int)instruction[node + RE.offsetOpdata]; - - // Return opcode as a string and opdata value - return opcodeToString(opcode) + ", opdata = " + opdata; - } - - /** - * Inserts a node with a given opcode and opdata at insertAt. The node relative next - * pointer is initialized to 0. - * @param opcode Opcode for new node - * @param opdata Opdata for new node (only the low 16 bits are currently used) - * @param insertAt Index at which to insert the new node in the program * / - void nodeInsert(char opcode, int opdata, int insertAt) { - System.out.println( "====> " + opcode + " " + opdata + " " + insertAt ); - PrintWriter writer = new PrintWriter( System.out ); - dumpProgram( writer ); - super.nodeInsert( opcode, opdata, insertAt ); - System.out.println( "====< " ); - dumpProgram( writer ); - writer.flush(); - }/**/ - - - /** - * Appends a node to the end of a node chain - * @param node Start of node chain to traverse - * @param pointTo Node to have the tail of the chain point to * / - void setNextOfEnd(int node, int pointTo) { - System.out.println( "====> " + node + " " + pointTo ); - PrintWriter writer = new PrintWriter( System.out ); - dumpProgram( writer ); - super.setNextOfEnd( node, pointTo ); - System.out.println( "====< " ); - dumpProgram( writer ); - writer.flush(); - }/**/ - - - /** - * Dumps the current program to a PrintWriter - * @param p PrintWriter for program dump output - */ - public void dumpProgram(PrintWriter p) - { - // Loop through the whole program - for (int i = 0; i < lenInstruction; ) - { - // Get opcode, opdata and next fields of current program node - char opcode = instruction[i + RE.offsetOpcode]; - char opdata = instruction[i + RE.offsetOpdata]; - short next = (short)instruction[i + RE.offsetNext]; - - // Display the current program node - p.print(i + ". " + nodeToString(i) + ", next = "); - - // If there's no next, say 'none', otherwise give absolute index of next node - if (next == 0) - { - p.print("none"); - } - else - { - p.print(i + next); - } - - // Move past node - i += RE.nodeSize; - - // If character class - if (opcode == RE.OP_ANYOF) - { - // Opening bracket for start of char class - p.print(", ["); - - // Show each range in the char class - int rangeCount = opdata; - for (int r = 0; r < rangeCount; r++) - { - // Get first and last chars in range - char charFirst = instruction[i++]; - char charLast = instruction[i++]; - - // Print range as X-Y, unless range encompasses only one char - if (charFirst == charLast) - { - p.print(charToString(charFirst)); - } - else - { - p.print(charToString(charFirst) + "-" + charToString(charLast)); - } - } - - // Annotate the end of the char class - p.print("]"); - } - - // If atom - if (opcode == RE.OP_ATOM) - { - // Open quote - p.print(", \""); - - // Print each character in the atom - for (int len = opdata; len-- != 0; ) - { - p.print(charToString(instruction[i++])); - } - - // Close quote - p.print("\""); - } - - // Print a newline - p.println(""); - } - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REProgram.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REProgram.java deleted file mode 100644 index f7a39ce3fe1..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REProgram.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import java.io.Serializable; - -/** - * A class that holds compiled regular expressions. This is exposed mainly - * for use by the recompile utility (which helps you produce precompiled - * REProgram objects). You should not otherwise need to work directly with - * this class. -* - * @see RE - * @see RECompiler - * - * @author Jonathan Locke - */ -public class REProgram implements Serializable -{ - static final int OPT_HASBACKREFS = 1; - - char[] instruction; // The compiled regular expression 'program' - int lenInstruction; // The amount of the instruction buffer in use - char[] prefix; // Prefix string optimization - int flags; // Optimization flags (REProgram.OPT_*) - int maxParens = -1; - - /** - * Constructs a program object from a character array - * @param instruction Character array with RE opcode instructions in it - */ - public REProgram(char[] instruction) - { - this(instruction, instruction.length); - } - - /** - * Constructs a program object from a character array - * @param parens Count of parens in the program - * @param instruction Character array with RE opcode instructions in it - */ - public REProgram(int parens, char[] instruction) - { - this(instruction, instruction.length); - this.maxParens = parens; - } - - /** - * Constructs a program object from a character array - * @param instruction Character array with RE opcode instructions in it - * @param lenInstruction Amount of instruction array in use - */ - public REProgram(char[] instruction, int lenInstruction) - { - setInstructions(instruction, lenInstruction); - } - - /** - * Returns a copy of the current regular expression program in a character - * array that is exactly the right length to hold the program. If there is - * no program compiled yet, getInstructions() will return null. - * @return A copy of the current compiled RE program - */ - public char[] getInstructions() - { - // Ensure program has been compiled! - if (lenInstruction != 0) - { - // Return copy of program - char[] ret = new char[lenInstruction]; - System.arraycopy(instruction, 0, ret, 0, lenInstruction); - return ret; - } - return null; - } - - /** - * Sets a new regular expression program to run. It is this method which - * performs any special compile-time search optimizations. Currently only - * two optimizations are in place - one which checks for backreferences - * (so that they can be lazily allocated) and another which attempts to - * find an prefix anchor string so that substantial amounts of input can - * potentially be skipped without running the actual program. - * @param instruction Program instruction buffer - * @param lenInstruction Length of instruction buffer in use - */ - public void setInstructions(char[] instruction, int lenInstruction) - { - // Save reference to instruction array - this.instruction = instruction; - this.lenInstruction = lenInstruction; - - // Initialize other program-related variables - flags = 0; - prefix = null; - - // Try various compile-time optimizations if there's a program - if (instruction != null && lenInstruction != 0) - { - // If the first node is a branch - if (lenInstruction >= RE.nodeSize && instruction[0 + RE.offsetOpcode] == RE.OP_BRANCH) - { - // to the end node - int next = instruction[0 + RE.offsetNext]; - if (instruction[next + RE.offsetOpcode] == RE.OP_END) - { - // and the branch starts with an atom - if (lenInstruction >= (RE.nodeSize * 2) && instruction[RE.nodeSize + RE.offsetOpcode] == RE.OP_ATOM) - { - // then get that atom as an prefix because there's no other choice - int lenAtom = instruction[RE.nodeSize + RE.offsetOpdata]; - prefix = new char[lenAtom]; - System.arraycopy(instruction, RE.nodeSize * 2, prefix, 0, lenAtom); - } - } - } - - BackrefScanLoop: - - // Check for backreferences - for (int i = 0; i < lenInstruction; i += RE.nodeSize) - { - switch (instruction[i + RE.offsetOpcode]) - { - case RE.OP_ANYOF: - i += (instruction[i + RE.offsetOpdata] * 2); - break; - - case RE.OP_ATOM: - i += instruction[i + RE.offsetOpdata]; - break; - - case RE.OP_BACKREF: - flags |= OPT_HASBACKREFS; - break BackrefScanLoop; - } - } - } - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RESyntaxException.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RESyntaxException.java deleted file mode 100644 index a13f901ece4..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RESyntaxException.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -/** - * Exception thrown to indicate a syntax error in a regular expression. - * This is a non-checked exception because you should only have problems compiling - * a regular expression during development. - * If you are making regular expresion programs dynamically then you can catch it - * if you wish. But should not be forced to. - * - * @author Jonathan Locke - * @author Jonathan Locke - * @author Jon S. Stevens - * @author Michael McCallum - */ -public class RETest -{ - // True if we want to see output from success cases - static final boolean showSuccesses = false; - - // A new line character. - static final String NEW_LINE = System.getProperty( "line.separator" ); - - // Construct a debug compiler - REDebugCompiler compiler = new REDebugCompiler(); - - /** - * Main program entrypoint. If an argument is given, it will be compiled - * and interactive matching will ensue. If no argument is given, the - * file RETest.txt will be used as automated testing input. - * @param args Command line arguments (optional regular expression) - */ - public static void main(String[] args) - { - try - { - if (!test( args )) { - System.exit(1); - } - } - catch (Exception e) - { - e.printStackTrace(); - System.exit(1); - } - } - - /** - * Testing entrypoint. - * @param args Command line arguments - * @exception Exception thrown in case of error - */ - public static boolean test( String[] args ) throws Exception - { - RETest test = new RETest(); - // Run interactive tests against a single regexp - if (args.length == 2) - { - test.runInteractiveTests(args[1]); - } - else if (args.length == 1) - { - // Run automated tests - test.runAutomatedTests(args[0]); - } - else - { - System.out.println( "Usage: RETest ([-i] [regex]) ([/path/to/testfile.txt])" ); - System.out.println( "By Default will run automated tests from file 'docs/RETest.txt' ..." ); - System.out.println(); - test.runAutomatedTests("docs/RETest.txt"); - } - return test.failures == 0; - } - - /** - * Constructor - */ - public RETest() - { - } - - /** - * Compile and test matching against a single expression - * @param expr Expression to compile and test - */ - void runInteractiveTests(String expr) - { - RE r = new RE(); - try - { - // Compile expression - r.setProgram(compiler.compile(expr)); - - // Show expression - say("" + NEW_LINE + "" + expr + "" + NEW_LINE + ""); - - // Show program for compiled expression - PrintWriter writer = new PrintWriter( System.out ); - compiler.dumpProgram( writer ); - writer.flush(); - - boolean running = true; - // Test matching against compiled expression - while ( running ) - { - // Read from keyboard - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - System.out.print("> "); - System.out.flush(); - String match = br.readLine(); - - if ( match != null ) - { - // Try a match against the keyboard input - if (r.match(match)) - { - say("Match successful."); - } - else - { - say("Match failed."); - } - - // Show subparen registers - showParens(r); - } - else - { - running = false; - System.out.println(); - } - } - } - catch (Exception e) - { - say("Error: " + e.toString()); - e.printStackTrace(); - } - } - - /** - * Exit with a fatal error. - * @param s Last famous words before exiting - */ - void die(String s) - { - say("FATAL ERROR: " + s); - System.exit(-1); - } - - /** - * Fail with an error. Will print a big failure message to System.out. - * - * @param log Output before failure - * @param s Failure description - */ - void fail(StringBuffer log, String s) - { - System.out.print(log.toString()); - fail(s); - } - - /** - * Fail with an error. Will print a big failure message to System.out. - * - * @param s Failure description - */ - void fail(String s) - { - failures++; - say("" + NEW_LINE + ""); - say("*******************************************************"); - say("********************* FAILURE! **********************"); - say("*******************************************************"); - say("" + NEW_LINE + ""); - say(s); - say(""); - // make sure the writer gets flushed. - if (compiler != null) { - PrintWriter writer = new PrintWriter( System.out ); - compiler.dumpProgram( writer ); - writer.flush(); - say("" + NEW_LINE + ""); - } - } - - /** - * Say something to standard out - * @param s What to say - */ - void say(String s) - { - System.out.println(s); - } - - /** - * Dump parenthesized subexpressions found by a regular expression matcher object - * @param r Matcher object with results to show - */ - void showParens(RE r) - { - // Loop through each paren - for (int i = 0; i < r.getParenCount(); i++) - { - // Show paren register - say("$" + i + " = " + r.getParen(i)); - } - } - - /* - * number in automated test - */ - int testCount = 0; - - /* - * Count of failures in automated test - */ - int failures = 0; - - /** - * Run automated tests in RETest.txt file (from Perl 4.0 test battery) - * @exception Exception thrown in case of error - */ - void runAutomatedTests(String testDocument) throws Exception - { - long ms = System.currentTimeMillis(); - - // Some unit tests - testPrecompiledRE(); - testSplitAndGrep(); - testSubst(); - testOther(); - - // Test from script file - File testInput = new File(testDocument); - if (! testInput.exists()) { - throw new Exception ("Could not find: " + testDocument); - } - - BufferedReader br = new BufferedReader(new FileReader(testInput)); - try - { - // While input is available, parse lines - while (br.ready()) - { - RETestCase testcase = getNextTestCase(br); - if (testcase != null) { - testcase.runTest(); - } - } - } - finally - { - br.close(); - } - - // Show match time - say(NEW_LINE + NEW_LINE + "Match time = " + (System.currentTimeMillis() - ms) + " ms."); - - // Print final results - if (failures > 0) { - say("*************** THERE ARE FAILURES! *******************"); - } - say("Tests complete. " + testCount + " tests, " + failures + " failure(s)."); - } - - /** - * Run automated unit test - * @exception Exception thrown in case of error - */ - void testOther() throws Exception - { - // Serialization test 1: Compile regexp and serialize/deserialize it - RE r = new RE("(a*)b"); - say("Serialized/deserialized (a*)b"); - ByteArrayOutputStream out = new ByteArrayOutputStream(128); - new ObjectOutputStream(out).writeObject(r); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - r = (RE)new ObjectInputStream(in).readObject(); - if (!r.match("aaab")) - { - fail("Did not match 'aaab' with deserialized RE."); - } else { - say("aaaab = true"); - showParens(r); - } - - // Serialization test 2: serialize/deserialize used regexp - out.reset(); - say("Deserialized (a*)b"); - new ObjectOutputStream(out).writeObject(r); - in = new ByteArrayInputStream(out.toByteArray()); - r = (RE)new ObjectInputStream(in).readObject(); - if (r.getParenCount() != 0) - { - fail("Has parens after deserialization."); - } - if (!r.match("aaab")) - { - fail("Did not match 'aaab' with deserialized RE."); - } else { - say("aaaab = true"); - showParens(r); - } - - // Test MATCH_CASEINDEPENDENT - r = new RE("abc(\\w*)"); - say("MATCH_CASEINDEPENDENT abc(\\w*)"); - r.setMatchFlags(RE.MATCH_CASEINDEPENDENT); - say("abc(d*)"); - if (!r.match("abcddd")) - { - fail("Did not match 'abcddd'."); - } else { - say("abcddd = true"); - showParens(r); - } - - if (!r.match("aBcDDdd")) - { - fail("Did not match 'aBcDDdd'."); - } else { - say("aBcDDdd = true"); - showParens(r); - } - - if (!r.match("ABCDDDDD")) - { - fail("Did not match 'ABCDDDDD'."); - } else { - say("ABCDDDDD = true"); - showParens(r); - } - - r = new RE("(A*)b\\1"); - r.setMatchFlags(RE.MATCH_CASEINDEPENDENT); - if (!r.match("AaAaaaBAAAAAA")) - { - fail("Did not match 'AaAaaaBAAAAAA'."); - } else { - say("AaAaaaBAAAAAA = true"); - showParens(r); - } - - r = new RE("[A-Z]*"); - r.setMatchFlags(RE.MATCH_CASEINDEPENDENT); - if (!r.match("CaBgDe12")) - { - fail("Did not match 'CaBgDe12'."); - } else { - say("CaBgDe12 = true"); - showParens(r); - } - - // Test MATCH_MULTILINE. Test for eol/bol symbols. - r = new RE("^abc$", RE.MATCH_MULTILINE); - if (!r.match("\nabc")) { - fail("\"\\nabc\" doesn't match \"^abc$\""); - } - if (!r.match("\rabc")) { - fail("\"\\rabc\" doesn't match \"^abc$\""); - } - if (!r.match("\r\nabc")) { - fail("\"\\r\\nabc\" doesn't match \"^abc$\""); - } - if (!r.match("\u0085abc")) { - fail("\"\\u0085abc\" doesn't match \"^abc$\""); - } - if (!r.match("\u2028abc")) { - fail("\"\\u2028abc\" doesn't match \"^abc$\""); - } - if (!r.match("\u2029abc")) { - fail("\"\\u2029abc\" doesn't match \"^abc$\""); - } - - // Test MATCH_MULTILINE. Test that '.' does not matches new line. - r = new RE("^a.*b$", RE.MATCH_MULTILINE); - if (r.match("a\nb")) { - fail("\"a\\nb\" matches \"^a.*b$\""); - } - if (r.match("a\rb")) { - fail("\"a\\rb\" matches \"^a.*b$\""); - } - if (r.match("a\r\nb")) { - fail("\"a\\r\\nb\" matches \"^a.*b$\""); - } - if (r.match("a\u0085b")) { - fail("\"a\\u0085b\" matches \"^a.*b$\""); - } - if (r.match("a\u2028b")) { - fail("\"a\\u2028b\" matches \"^a.*b$\""); - } - if (r.match("a\u2029b")) { - fail("\"a\\u2029b\" matches \"^a.*b$\""); - } - } - - private void testPrecompiledRE() - { - // Pre-compiled regular expression "a*b" - char[] re1Instructions = - { - 0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041, - 0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047, - 0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000, - 0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000, - 0x0000, - }; - - REProgram re1 = new REProgram(re1Instructions); - - // Simple test of pre-compiled regular expressions - RE r = new RE(re1); - say("a*b"); - boolean result = r.match("aaab"); - say("aaab = " + result); - showParens(r); - if (!result) { - fail("\"aaab\" doesn't match to precompiled \"a*b\""); - } - - result = r.match("b"); - say("b = " + result); - showParens(r); - if (!result) { - fail("\"b\" doesn't match to precompiled \"a*b\""); - } - - result = r.match("c"); - say("c = " + result); - showParens(r); - if (result) { - fail("\"c\" matches to precompiled \"a*b\""); - } - - result = r.match("ccccaaaaab"); - say("ccccaaaaab = " + result); - showParens(r); - if (!result) { - fail("\"ccccaaaaab\" doesn't match to precompiled \"a*b\""); - } - } - - private void testSplitAndGrep() - { - String[] expected = {"xxxx", "xxxx", "yyyy", "zzz"}; - RE r = new RE("a*b"); - String[] s = r.split("xxxxaabxxxxbyyyyaaabzzz"); - for (int i = 0; i < expected.length && i < s.length; i++) { - assertEquals("Wrong splitted part", expected[i], s[i]); - } - assertEquals("Wrong number of splitted parts", expected.length, - s.length); - - r = new RE("x+"); - expected = new String[] {"xxxx", "xxxx"}; - s = r.grep(s); - for (int i = 0; i < s.length; i++) - { - say("s[" + i + "] = " + s[i]); - assertEquals("Grep fails", expected[i], s[i]); - } - assertEquals("Wrong number of string found by grep", expected.length, - s.length); - } - - private void testSubst() - { - RE r = new RE("a*b"); - String expected = "-foo-garply-wacky-"; - String actual = r.subst("aaaabfooaaabgarplyaaabwackyb", "-"); - assertEquals("Wrong result of substitution in \"a*b\"", expected, actual); - - // Test subst() with backreferences - r = new RE("http://[\\.\\w\\-\\?/~_@&=%]+"); - actual = r.subst("visit us: http://www.apache.org!", - "1234$0", RE.REPLACE_BACKREFERENCES); - assertEquals("Wrong subst() result", "visit us: 1234http://www.apache.org!", actual); - - // Test subst() with backreferences without leading characters - // before first backreference - r = new RE("(.*?)=(.*)"); - actual = r.subst("variable=value", - "$1_test_$212", RE.REPLACE_BACKREFERENCES); - assertEquals("Wrong subst() result", "variable_test_value12", actual); - - // Test subst() with NO backreferences - r = new RE("^a$"); - actual = r.subst("a", - "b", RE.REPLACE_BACKREFERENCES); - assertEquals("Wrong subst() result", "b", actual); - - // Test subst() with NO backreferences - r = new RE("^a$", RE.MATCH_MULTILINE); - actual = r.subst("\r\na\r\n", - "b", RE.REPLACE_BACKREFERENCES); - assertEquals("Wrong subst() result", "\r\nb\r\n", actual); - } - - public void assertEquals(String message, String expected, String actual) - { - if (expected != null && !expected.equals(actual) - || actual != null && !actual.equals(expected)) - { - fail(message + " (expected \"" + expected - + "\", actual \"" + actual + "\")"); - } - } - - public void assertEquals(String message, int expected, int actual) - { - if (expected != actual) { - fail(message + " (expected \"" + expected - + "\", actual \"" + actual + "\")"); - } - } - - /** - * Converts yesno string to boolean. - * @param yesno string representation of expected result - * @return true if yesno is "YES", false if yesno is "NO" - * stops program otherwise. - */ - private boolean getExpectedResult(String yesno) - { - if ("NO".equals(yesno)) - { - return false; - } - else if ("YES".equals(yesno)) - { - return true; - } - else - { - // Bad test script - die("Test script error!"); - return false; //to please javac - } - } - - /** - * Finds next test description in a given script. - * @param br BufferedReader for a script file - * @return strign tag for next test description - * @exception IOException if some io problems occured - */ - private String findNextTest(BufferedReader br) throws IOException - { - String number = ""; - - while (br.ready()) - { - number = br.readLine(); - if (number == null) - { - break; - } - number = number.trim(); - if (number.startsWith("#")) - { - break; - } - if (!number.equals("")) - { - say("Script error. Line = " + number); - System.exit(-1); - } - } - return number; - } - - /** - * Creates testcase for the next test description in the script file. - * @param br BufferedReader for script file. - * @return a new tescase or null. - * @exception IOException if some io problems occured - */ - private RETestCase getNextTestCase(BufferedReader br) throws IOException - { - // Find next re test case - final String tag = findNextTest(br); - - // Are we done? - if (!br.ready()) - { - return null; - } - - // Get expression - final String expr = br.readLine(); - - // Get test information - final String matchAgainst = br.readLine(); - final boolean badPattern = "ERR".equals(matchAgainst); - boolean shouldMatch = false; - int expectedParenCount = 0; - String[] expectedParens = null; - - if (!badPattern) { - shouldMatch = getExpectedResult(br.readLine().trim()); - if (shouldMatch) { - expectedParenCount = Integer.parseInt(br.readLine().trim()); - expectedParens = new String[expectedParenCount]; - for (int i = 0; i < expectedParenCount; i++) { - expectedParens[i] = br.readLine(); - } - } - } - - return new RETestCase(this, tag, expr, matchAgainst, badPattern, - shouldMatch, expectedParens); - } -} - -final class RETestCase -{ - final private StringBuffer log = new StringBuffer(); - final private int number; - final private String tag; // number from script file - final private String pattern; - final private String toMatch; - final private boolean badPattern; - final private boolean shouldMatch; - final private String[] parens; - final private RETest test; - private RE regexp; - - public RETestCase(RETest test, String tag, String pattern, - String toMatch, boolean badPattern, - boolean shouldMatch, String[] parens) - { - this.number = ++test.testCount; - this.test = test; - this.tag = tag; - this.pattern = pattern; - this.toMatch = toMatch; - this.badPattern = badPattern; - this.shouldMatch = shouldMatch; - if (parens != null) { - this.parens = new String[parens.length]; - for (int i = 0; i < parens.length; i++) { - this.parens[i] = parens[i]; - } - } else { - this.parens = null; - } - } - - public void runTest() - { - test.say(tag + "(" + number + "): " + pattern); - if (testCreation()) { - testMatch(); - } - } - - boolean testCreation() - { - try - { - // Compile it - regexp = new RE(); - regexp.setProgram(test.compiler.compile(pattern)); - // Expression didn't cause an expected error - if (badPattern) - { - test.fail(log, "Was expected to be an error, but wasn't."); - return false; - } - - return true; - } - // Some expressions *should* cause exceptions to be thrown - catch (Exception e) - { - // If it was supposed to be an error, report success and continue - if (badPattern) - { - log.append(" Match: ERR\n"); - success("Produces an error (" + e.toString() + "), as expected."); - return false; - } - - // Wasn't supposed to be an error - String message = (e.getMessage() == null) ? e.toString() : e.getMessage(); - test.fail(log, "Produces an unexpected exception \"" + message + "\""); - e.printStackTrace(); - } - catch (Error e) - { - // Internal error happened - test.fail(log, "Compiler threw fatal error \"" + e.getMessage() + "\""); - e.printStackTrace(); - } - - return false; - } - - private void testMatch() - { - log.append(" Match against: '" + toMatch + "'\n"); - // Try regular matching - try - { - // Match against the string - boolean result = regexp.match(toMatch); - log.append(" Matched: " + (result ? "YES" : "NO") + "\n"); - - // Check result, parens, and iterators - if (checkResult(result) && (!shouldMatch || checkParens())) - { - // test match(CharacterIterator, int) - // for every CharacterIterator implementation. - log.append(" Match using StringCharacterIterator\n"); - if (!tryMatchUsingCI(new StringCharacterIterator(toMatch))) - return; - - log.append(" Match using CharacterArrayCharacterIterator\n"); - if (!tryMatchUsingCI(new CharacterArrayCharacterIterator(toMatch.toCharArray(), 0, toMatch.length()))) - return; - - log.append(" Match using StreamCharacterIterator\n"); - if (!tryMatchUsingCI(new StreamCharacterIterator(new StringBufferInputStream(toMatch)))) - return; - - log.append(" Match using ReaderCharacterIterator\n"); - if (!tryMatchUsingCI(new ReaderCharacterIterator(new StringReader(toMatch)))) - return; - } - } - // Matcher blew it - catch(Exception e) - { - test.fail(log, "Matcher threw exception: " + e.toString()); - e.printStackTrace(); - } - // Internal error - catch(Error e) - { - test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\""); - e.printStackTrace(); - } - } - - private boolean checkResult(boolean result) - { - // Write status - if (result == shouldMatch) { - success((shouldMatch ? "Matched" : "Did not match") - + " \"" + toMatch + "\", as expected:"); - return true; - } else { - if (shouldMatch) { - test.fail(log, "Did not match \"" + toMatch + "\", when expected to."); - } else { - test.fail(log, "Matched \"" + toMatch + "\", when not expected to."); - } - return false; - } - } - - private boolean checkParens() - { - // Show subexpression registers - if (RETest.showSuccesses) - { - test.showParens(regexp); - } - - log.append(" Paren count: " + regexp.getParenCount() + "\n"); - if (!assertEquals(log, "Wrong number of parens", parens.length, regexp.getParenCount())) - { - return false; - } - - // Check registers against expected contents - for (int p = 0; p < regexp.getParenCount(); p++) - { - log.append(" Paren " + p + ": " + regexp.getParen(p) + "\n"); - - // Compare expected result with actual - if ("null".equals(parens[p]) && regexp.getParen(p) == null) - { - // Consider "null" in test file equal to null - continue; - } - if (!assertEquals(log, "Wrong register " + p, parens[p], regexp.getParen(p))) - { - return false; - } - } - - return true; - } - - boolean tryMatchUsingCI(CharacterIterator matchAgainst) - { - try { - boolean result = regexp.match(matchAgainst, 0); - log.append(" Match: " + (result ? "YES" : "NO") + "\n"); - return checkResult(result) && (!shouldMatch || checkParens()); - } - // Matcher blew it - catch(Exception e) - { - test.fail(log, "Matcher threw exception: " + e.toString()); - e.printStackTrace(); - } - // Internal error - catch(Error e) - { - test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\""); - e.printStackTrace(); - } - return false; - } - - public boolean assertEquals(StringBuffer log, String message, String expected, String actual) - { - if (expected != null && !expected.equals(actual) - || actual != null && !actual.equals(expected)) - { - test.fail(log, message + " (expected \"" + expected - + "\", actual \"" + actual + "\")"); - return false; - } - return true; - } - - public boolean assertEquals(StringBuffer log, String message, int expected, int actual) - { - if (expected != actual) { - test.fail(log, message + " (expected \"" + expected - + "\", actual \"" + actual + "\")"); - return false; - } - return true; - } - - /** - * Show a success - * @param s Success story - */ - void success(String s) - { - if (RETest.showSuccesses) - { - test.say("" + RETest.NEW_LINE + "-----------------------" + RETest.NEW_LINE + ""); - test.say("Expression #" + (number) + " \"" + pattern + "\" "); - test.say("Success: " + s); - } - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REUtil.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REUtil.java deleted file mode 100644 index 10907ece8d6..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/REUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -/** - * This is a class that contains utility helper methods for this package. - * - * @author Jonathan Locke - */ -public class REUtil -{ - /** complex: */ - private static final String complexPrefix = "complex:"; - - /** - * Creates a regular expression, permitting simple or complex syntax - * @param expression The expression, beginning with a prefix if it's complex or - * having no prefix if it's simple - * @param matchFlags Matching style flags - * @return The regular expression object - * @exception RESyntaxException thrown in case of error - */ - public static RE createRE(String expression, int matchFlags) throws RESyntaxException - { - if (expression.startsWith(complexPrefix)) - { - return new RE(expression.substring(complexPrefix.length()), matchFlags); - } - return new RE(RE.simplePatternToFullRegularExpression(expression), matchFlags); - } - - /** - * Creates a regular expression, permitting simple or complex syntax - * @param expression The expression, beginning with a prefix if it's complex or - * having no prefix if it's simple - * @return The regular expression object - * @exception RESyntaxException thrown in case of error - */ - public static RE createRE(String expression) throws RESyntaxException - { - return createRE(expression, RE.MATCH_NORMAL); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/ReaderCharacterIterator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/ReaderCharacterIterator.java deleted file mode 100644 index 7eafff44121..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/ReaderCharacterIterator.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import java.io.Reader; -import java.io.IOException; - -/** - * Encapsulates java.io.Reader as CharacterIterator - * - * @author Ales Novak - */ -public final class ReaderCharacterIterator implements CharacterIterator -{ - /** Underlying reader */ - private final Reader reader; - - /** Buffer of read chars */ - private final StringBuffer buff; - - /** read end? */ - private boolean closed; - - /** @param reader a Reader, which is parsed */ - public ReaderCharacterIterator(Reader reader) - { - this.reader = reader; - this.buff = new StringBuffer(512); - this.closed = false; - } - - /** @return a substring */ - public String substring(int beginIndex, int endIndex) - { - try - { - ensure(endIndex); - return buff.toString().substring(beginIndex, endIndex); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - /** @return a substring */ - public String substring(int beginIndex) - { - try - { - readAll(); - return buff.toString().substring(beginIndex); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - /** @return a character at the specified position. */ - public char charAt(int pos) - { - try - { - ensure(pos); - return buff.charAt(pos); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - /** @return true iff if the specified index is after the end of the character stream */ - public boolean isEnd(int pos) - { - if (buff.length() > pos) - { - return false; - } - else - { - try - { - ensure(pos); - return (buff.length() <= pos); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - } - - /** Reads n characters from the stream and appends them to the buffer */ - private int read(int n) throws IOException - { - if (closed) - { - return 0; - } - - char[] c = new char[n]; - int count = 0; - int read = 0; - - do - { - read = reader.read(c); - if (read < 0) // EOF - { - closed = true; - break; - } - count += read; - buff.append(c, 0, read); - } - while (count < n); - - return count; - } - - /** Reads rest of the stream. */ - private void readAll() throws IOException - { - while(! closed) - { - read(1000); - } - } - - /** Reads chars up to the idx */ - private void ensure(int idx) throws IOException - { - if (closed) - { - return; - } - - if (idx < buff.length()) - { - return; - } - read(idx + 1 - buff.length()); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StreamCharacterIterator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StreamCharacterIterator.java deleted file mode 100644 index e489065b79b..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StreamCharacterIterator.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import java.io.InputStream; -import java.io.IOException; - -/** - * Encapsulates java.io.InputStream as CharacterIterator. - * - * @author Ales Novak - */ -public final class StreamCharacterIterator implements CharacterIterator -{ - /** Underlying is */ - private final InputStream is; - - /** Buffer of read chars */ - private final StringBuffer buff; - - /** read end? */ - private boolean closed; - - /** @param is an InputStream, which is parsed */ - public StreamCharacterIterator(InputStream is) - { - this.is = is; - this.buff = new StringBuffer(512); - this.closed = false; - } - - /** @return a substring */ - public String substring(int beginIndex, int endIndex) - { - try - { - ensure(endIndex); - return buff.toString().substring(beginIndex, endIndex); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - /** @return a substring */ - public String substring(int beginIndex) - { - try - { - readAll(); - return buff.toString().substring(beginIndex); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - - /** @return a character at the specified position. */ - public char charAt(int pos) - { - try - { - ensure(pos); - return buff.charAt(pos); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - - /** @return true iff if the specified index is after the end of the character stream */ - public boolean isEnd(int pos) - { - if (buff.length() > pos) - { - return false; - } - else - { - try - { - ensure(pos); - return (buff.length() <= pos); - } - catch (IOException e) - { - throw new StringIndexOutOfBoundsException(e.getMessage()); - } - } - } - - /** Reads n characters from the stream and appends them to the buffer */ - private int read(int n) throws IOException - { - if (closed) - { - return 0; - } - - int c; - int i = n; - while (--i >= 0) - { - c = is.read(); - if (c < 0) // EOF - { - closed = true; - break; - } - buff.append((char) c); - } - return n - i; - } - - /** Reads rest of the stream. */ - private void readAll() throws IOException - { - while(! closed) - { - read(1000); - } - } - - /** Reads chars up to the idx */ - private void ensure(int idx) throws IOException - { - if (closed) - { - return; - } - - if (idx < buff.length()) - { - return; - } - - read(idx + 1 - buff.length()); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StringCharacterIterator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StringCharacterIterator.java deleted file mode 100644 index bc6c859973c..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/StringCharacterIterator.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -/** - * Encapsulates String as CharacterIterator. - * - * @author Ales Novak - */ -public final class StringCharacterIterator implements CharacterIterator -{ - /** encapsulated */ - private final String src; - - /** @param src - encapsulated String */ - public StringCharacterIterator(String src) - { - this.src = src; - } - - /** @return a substring */ - public String substring(int beginIndex, int endIndex) - { - return src.substring(beginIndex, endIndex); - } - - /** @return a substring */ - public String substring(int beginIndex) - { - return src.substring(beginIndex); - } - - /** @return a character at the specified position. */ - public char charAt(int pos) - { - return src.charAt(pos); - } - - /** @return true iff if the specified index is after the end of the character stream */ - public boolean isEnd(int pos) - { - return (pos >= src.length()); - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/recompile.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/recompile.java deleted file mode 100644 index fc0cbb3b977..00000000000 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/recompile.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.regexp.internal; - -import com.sun.org.apache.regexp.internal.RECompiler; -import com.sun.org.apache.regexp.internal.RESyntaxException; - -/** - * 'recompile' is a command line tool that pre-compiles one or more regular expressions - * for use with the regular expression matcher class 'RE'. For example, the command - * "java recompile a*b" produces output like this: - * - *

- *
- *    // Pre-compiled regular expression "a*b"
- *    char[] re1Instructions =
- *    {
- *        0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
- *        0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
- *        0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
- *        0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
- *        0x0000,
- *    };
- *
- *    REProgram re1 = new REProgram(re1Instructions);
- *
- * 
- * - * By pasting this output into your code, you can construct a regular expression matcher - * (RE) object directly from the pre-compiled data (the character array re1), thus avoiding - * the overhead of compiling the expression at runtime. For example: - * - *
- *
- *    RE r = new RE(re1);
- *
- * 
- * - * @see RE - * @see RECompiler - * - * @author Jonathan Locke - */ -public class recompile -{ - /** - * Main application entrypoint. - * @param arg Command line arguments - */ - static public void main(String[] arg) - { - // Create a compiler object - RECompiler r = new RECompiler(); - - // Print usage if arguments are incorrect - if (arg.length <= 0 || arg.length % 2 != 0) - { - System.out.println("Usage: recompile "); - System.exit(0); - } - - // Loop through arguments, compiling each - for (int i = 0; i < arg.length; i += 2) - { - try - { - // Compile regular expression - String name = arg[i]; - String pattern = arg[i+1]; - String instructions = name + "PatternInstructions"; - - // Output program as a nice, formatted character array - System.out.print("\n // Pre-compiled regular expression '" + pattern + "'\n" - + " private static char[] " + instructions + " = \n {"); - - // Compile program for pattern - REProgram program = r.compile(pattern); - - // Number of columns in output - int numColumns = 7; - - // Loop through program - char[] p = program.getInstructions(); - for (int j = 0; j < p.length; j++) - { - // End of column? - if ((j % numColumns) == 0) - { - System.out.print("\n "); - } - - // Print character as padded hex number - String hex = Integer.toHexString(p[j]); - while (hex.length() < 4) - { - hex = "0" + hex; - } - System.out.print("0x" + hex + ", "); - } - - // End of program block - System.out.println("\n };"); - System.out.println("\n private static RE " + name + "Pattern = new RE(new REProgram(" + instructions + "));"); - } - catch (RESyntaxException e) - { - System.out.println("Syntax error in expression \"" + arg[i] + "\": " + e.toString()); - } - catch (Exception e) - { - System.out.println("Unexpected exception: " + e.toString()); - } - catch (Error e) - { - System.out.println("Internal error: " + e.toString()); - } - } - } -} diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java index 8262111f444..f3b9b50397a 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java @@ -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 @@ -1345,6 +1345,15 @@ public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamW } } + /** + * Writes character reference in hex format. + */ + private void writeCharRef(int codePoint) throws IOException { + fWriter.write( "&#x" ); + fWriter.write( Integer.toHexString(codePoint) ); + fWriter.write( ';' ); + } + /** * Writes XML content to underlying writer. Escapes characters unless * escaping character feature is turned off. @@ -1368,10 +1377,14 @@ public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamW if (fEncoder != null && !fEncoder.canEncode(ch)){ fWriter.write(content, startWritePos, index - startWritePos ); - // Escape this char as underlying encoder cannot handle it - fWriter.write( "&#x" ); - fWriter.write(Integer.toHexString(ch)); - fWriter.write( ';' ); + // Check if current and next characters forms a surrogate pair + // and escape it to avoid generation of invalid xml content + if ( index != end - 1 && Character.isSurrogatePair(ch, content[index+1])) { + writeCharRef(Character.toCodePoint(ch, content[index+1])); + index++; + } else { + writeCharRef(ch); + } startWritePos = index + 1; continue; } @@ -1439,10 +1452,15 @@ public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamW if (fEncoder != null && !fEncoder.canEncode(ch)){ fWriter.write(content, startWritePos, index - startWritePos ); - // Escape this char as underlying encoder cannot handle it - fWriter.write( "&#x" ); - fWriter.write(Integer.toHexString(ch)); - fWriter.write( ';' ); + // Check if current and next characters forms a surrogate pair + // and escape it to avoid generation of invalid xml content + if ( index != end - 1 && Character.isSurrogatePair(ch, content.charAt(index+1))) { + writeCharRef(Character.toCodePoint(ch, content.charAt(index+1))); + index++; + } else { + writeCharRef(ch); + } + startWritePos = index + 1; continue; } diff --git a/jaxp/src/java.xml/share/classes/module-info.java b/jaxp/src/java.xml/share/classes/module-info.java index 3bd3fa340e7..ed48672adfc 100644 --- a/jaxp/src/java.xml/share/classes/module-info.java +++ b/jaxp/src/java.xml/share/classes/module-info.java @@ -86,5 +86,6 @@ module java.xml { uses javax.xml.transform.TransformerFactory; uses javax.xml.validation.SchemaFactory; uses javax.xml.xpath.XPathFactory; + uses org.xml.sax.XMLReader; } diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/AttributeList.java b/jaxp/src/java.xml/share/classes/org/xml/sax/AttributeList.java index 3b9f0f0f376..f79d5067c31 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/AttributeList.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/AttributeList.java @@ -93,6 +93,7 @@ package org.xml.sax; * @see org.xml.sax.DocumentHandler#startElement startElement * @see org.xml.sax.helpers.AttributeListImpl AttributeListImpl */ +@Deprecated(since="5") public interface AttributeList { diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/DocumentHandler.java b/jaxp/src/java.xml/share/classes/org/xml/sax/DocumentHandler.java index 0c8b93b85b2..91cdac156ca 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/DocumentHandler.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/DocumentHandler.java @@ -68,6 +68,7 @@ package org.xml.sax; * @see org.xml.sax.Locator * @see org.xml.sax.HandlerBase */ +@Deprecated(since="5") public interface DocumentHandler { diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/Parser.java b/jaxp/src/java.xml/share/classes/org/xml/sax/Parser.java index 099df32951b..fef6e44843b 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/Parser.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/Parser.java @@ -73,6 +73,7 @@ import java.util.Locale; * @see org.xml.sax.HandlerBase * @see org.xml.sax.InputSource */ +@Deprecated(since="5") public interface Parser { diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/NewInstance.java b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/NewInstance.java index c3516b17b5a..acd3996d014 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/NewInstance.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/NewInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, 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 @@ -32,8 +32,7 @@ package org.xml.sax.helpers; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.util.Objects; /** * Create a new instance of a class by name. @@ -57,31 +56,26 @@ import java.lang.reflect.InvocationTargetException; * @version 2.0.1 (sax2r2) */ class NewInstance { + private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; /** * Creates a new instance of the specified class name * * Package private so this code is not exposed at the API level. */ - static Object newInstance (ClassLoader classLoader, String className) + static T newInstance (Class type, ClassLoader loader, String clsName) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - // make sure we have access to restricted packages - boolean internal = false; - if (System.getSecurityManager() != null) { - if (className != null && className.startsWith(DEFAULT_PACKAGE)) { - internal = true; - } + ClassLoader classLoader = Objects.requireNonNull(loader); + String className = Objects.requireNonNull(clsName); + + if (className.startsWith(DEFAULT_PACKAGE)) { + return type.cast(new com.sun.org.apache.xerces.internal.parsers.SAXParser()); } - Class driverClass; - if (classLoader == null || internal) { - driverClass = Class.forName(className); - } else { - driverClass = classLoader.loadClass(className); - } - return driverClass.newInstance(); + Class driverClass = classLoader.loadClass(className); + return type.cast(driverClass.newInstance()); } } diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/ParserFactory.java b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/ParserFactory.java index efbefe01509..6e658867220 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/ParserFactory.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/ParserFactory.java @@ -30,8 +30,6 @@ package org.xml.sax.helpers; -import org.xml.sax.Parser; - /** * Java-specific class for dynamically loading SAX parsers. @@ -65,6 +63,8 @@ import org.xml.sax.Parser; * @author David Megginson * @version 2.0.1 (sax2r2) */ +@SuppressWarnings( "deprecation" ) +@Deprecated(since="5") public class ParserFactory { private static SecuritySupport ss = new SecuritySupport(); @@ -97,7 +97,7 @@ public class ParserFactory { * @see #makeParser(java.lang.String) * @see org.xml.sax.Parser */ - public static Parser makeParser () + public static org.xml.sax.Parser makeParser () throws ClassNotFoundException, IllegalAccessException, InstantiationException, @@ -134,14 +134,13 @@ public class ParserFactory { * @see #makeParser() * @see org.xml.sax.Parser */ - public static Parser makeParser (String className) + public static org.xml.sax.Parser makeParser (String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException, ClassCastException { - return (Parser) NewInstance.newInstance ( - ss.getContextClassLoader(), className); + return NewInstance.newInstance (org.xml.sax.Parser.class, ss.getClassLoader(), className); } } diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/SecuritySupport.java b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/SecuritySupport.java index ecd5696942d..3d753b1dcd3 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/SecuritySupport.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/SecuritySupport.java @@ -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 @@ -37,72 +37,56 @@ import java.security.*; */ class SecuritySupport { - - ClassLoader getContextClassLoader() throws SecurityException{ - return (ClassLoader) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - ClassLoader cl = null; - //try { - cl = Thread.currentThread().getContextClassLoader(); - //} catch (SecurityException ex) { } - - if (cl == null) - cl = ClassLoader.getSystemClassLoader(); - - return cl; + /** + * Returns the current thread's context class loader, or the system class loader + * if the context class loader is null. + * @return the current thread's context class loader, or the system class loader + * @throws SecurityException + */ + ClassLoader getClassLoader() throws SecurityException{ + return AccessController.doPrivileged((PrivilegedAction)() -> { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); } + + return cl; }); } String getSystemProperty(final String propName) { - return (String) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return System.getProperty(propName); - } - }); + return AccessController.doPrivileged((PrivilegedAction)() + -> System.getProperty(propName)); } FileInputStream getFileInputStream(final File file) throws FileNotFoundException { try { - return (FileInputStream) - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws FileNotFoundException { - return new FileInputStream(file); - } - }); + return AccessController.doPrivileged((PrivilegedExceptionAction)() -> + new FileInputStream(file)); } catch (PrivilegedActionException e) { throw (FileNotFoundException)e.getException(); } } - InputStream getResourceAsStream(final ClassLoader cl, - final String name) + + InputStream getResourceAsStream(final ClassLoader cl, final String name) { - return (InputStream) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - InputStream ris; - if (cl == null) { - ris = SecuritySupport.class.getResourceAsStream(name); - } else { - ris = cl.getResourceAsStream(name); - } - return ris; - } - }); + return AccessController.doPrivileged((PrivilegedAction) () -> { + InputStream ris; + if (cl == null) { + ris = SecuritySupport.class.getResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + }); } boolean doesFileExist(final File f) { - return ((Boolean) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return new Boolean(f.exists()); - } - })).booleanValue(); + return (AccessController.doPrivileged((PrivilegedAction)() -> + new Boolean(f.exists()))); } } diff --git a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/XMLReaderFactory.java b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/XMLReaderFactory.java index 9635e4cf777..6b183ff7350 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/XMLReaderFactory.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/helpers/XMLReaderFactory.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 @@ -32,10 +32,17 @@ package org.xml.sax.helpers; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import org.xml.sax.XMLReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; +import java.util.Objects; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; /** @@ -70,7 +77,11 @@ import org.xml.sax.SAXException; * @since 1.4, SAX 2.0 * @author David Megginson, David Brownell * @version 2.0.1 (sax2r2) + * + * @deprecated It is recommended to use {@link javax.xml.parsers.SAXParserFactory} + * instead. */ +@Deprecated(since="9") final public class XMLReaderFactory { /** @@ -83,47 +94,43 @@ final public class XMLReaderFactory } private static final String property = "org.xml.sax.driver"; - private static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); - private static String _clsFromJar = null; - private static boolean _jarread = false; /** - * Attempt to create an XMLReader from system defaults. - * In environments which can support it, the name of the XMLReader - * class is determined by trying each these options in order, and - * using the first one which succeeds: - *
    - * + * Obtains a new instance of a {@link org.xml.sax.XMLReader}. + * This method uses the following ordered lookup procedure to find and load + * the {@link org.xml.sax.XMLReader} implementation class: + *

    + *

      *
    1. If the system property {@code org.xml.sax.driver} * has a value, that is used as an XMLReader class name.
    2. + *
    3. + * Use the service-provider loading facility, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service {@link org.xml.sax.XMLReader} by using the + * {@linkplain java.lang.Thread#getContextClassLoader() current thread's context class loader}. + * If the context class loader is null, the + * {@linkplain ClassLoader#getSystemClassLoader() system class loader} will + * be used. + *
    4. + *
    5. + * Deprecated. Look for a class name in the {@code META-INF/services/org.xml.sax.driver} + * file in a jar file available to the runtime.
    6. + *
    7. + *

      + * Otherwise, the system-default implementation is returned. + *

    8. + *
    * - *
  • The JAR "Services API" is used to look for a class name - * in the META-INF/services/org.xml.sax.driver file in - * jarfiles available to the runtime.
  • + * @apiNote + * The process that looks for a class name in the + * {@code META-INF/services/org.xml.sax.driver} file in a jar file does not + * conform to the specification of the service-provider loading facility + * as defined in {@link java.util.ServiceLoader} and therefore does not + * support modularization. It is deprecated as of Java SE 9 and subject to + * removal in a future release. * - *
  • SAX parser distributions are strongly encouraged to provide - * a default XMLReader class name that will take effect only when - * previous options (on this list) are not successful.
  • - * - *
  • Finally, if {@link ParserFactory#makeParser()} can - * return a system default SAX1 parser, that parser is wrapped in - * a {@link ParserAdapter}. (This is a migration aid for SAX1 - * environments, where the {@code org.xml.sax.parser} system - * property will often be usable.)
  • - *
- * - *

In environments such as small embedded systems, which can not - * support that flexibility, other mechanisms to determine the default - * may be used. - * - *

Note that many Java environments allow system properties to be - * initialized on a command line. This means that in most cases - * setting a good value for that property ensures that calls to this - * method will succeed, except when security policies intervene. - * This will also maximize application portability to older SAX - * environments, with less robust implementations of this method. - * - * @return A new XMLReader. + * @return a new XMLReader. * @exception org.xml.sax.SAXException If no default XMLReader class * can be identified and instantiated. * @see #createXMLReader(java.lang.String) @@ -132,7 +139,7 @@ final public class XMLReaderFactory throws SAXException { String className = null; - ClassLoader cl = ss.getContextClassLoader(); + ClassLoader cl = ss.getClassLoader(); // 1. try the JVM-instance-wide system property try { @@ -140,62 +147,26 @@ final public class XMLReaderFactory } catch (RuntimeException e) { /* continue searching */ } - // 2. if that fails, try META-INF/services/ + // 2. try the ServiceLoader if (className == null) { - if (!_jarread) { - _jarread = true; - String service = "META-INF/services/" + property; - InputStream in; - BufferedReader reader; - - try { - if (cl != null) { - in = ss.getResourceAsStream(cl, service); - - // If no provider found then try the current ClassLoader - if (in == null) { - cl = null; - in = ss.getResourceAsStream(cl, service); - } - } else { - // No Context ClassLoader, try the current ClassLoader - in = ss.getResourceAsStream(cl, service); - } - - if (in != null) { - reader = new BufferedReader (new InputStreamReader (in, "UTF8")); - _clsFromJar = reader.readLine (); - in.close (); - } - } catch (Exception e) { - } + final XMLReader provider = findServiceProvider(XMLReader.class, cl); + if (provider != null) { + return provider; } - className = _clsFromJar; } - // 3. Distro-specific fallback + // 3. try META-INF/services/org.xml.sax.driver. This old process allows + // legacy providers to be found if (className == null) { -// BEGIN DISTRIBUTION-SPECIFIC - - // EXAMPLE: - // className = "com.example.sax.XmlReader"; - // or a $JAVA_HOME/jre/lib/*properties setting... - className = "com.sun.org.apache.xerces.internal.parsers.SAXParser"; - -// END DISTRIBUTION-SPECIFIC + className = jarLookup(cl); } - // do we know the XMLReader implementation class yet? - if (className != null) - return loadClass (cl, className); - - // 4. panic -- adapt any SAX1 parser - try { - return new ParserAdapter (ParserFactory.makeParser ()); - } catch (Exception e) { - throw new SAXException ("Can't create default XMLReader; " - + "is system property org.xml.sax.driver set?"); + // 4. Distro-specific fallback + if (className == null) { + return new com.sun.org.apache.xerces.internal.parsers.SAXParser(); } + + return loadClass (cl, className); } @@ -217,14 +188,14 @@ final public class XMLReaderFactory public static XMLReader createXMLReader (String className) throws SAXException { - return loadClass (ss.getContextClassLoader(), className); + return loadClass (ss.getClassLoader(), className); } private static XMLReader loadClass (ClassLoader loader, String className) throws SAXException { try { - return (XMLReader) NewInstance.newInstance (loader, className); + return NewInstance.newInstance (XMLReader.class, loader, className); } catch (ClassNotFoundException e1) { throw new SAXException("SAX2 driver class " + className + " not found", e1); @@ -240,4 +211,64 @@ final public class XMLReaderFactory " does not implement XMLReader", e4); } } + + /** + * Locates a provider by directly reading the jar service file. + * @param loader the ClassLoader to be used to read the service file + * @return the name of the provider, or null if nothing is found + */ + private static String jarLookup(final ClassLoader loader) { + final ClassLoader cl = Objects.requireNonNull(loader); + String clsFromJar = null; + String service = "META-INF/services/" + property; + InputStream in; + BufferedReader reader; + + try { + in = ss.getResourceAsStream(cl, service); + + // If no provider found then try the current ClassLoader + if (in == null) { + in = ss.getResourceAsStream(null, service); + } + + if (in != null) { + reader = new BufferedReader (new InputStreamReader (in, "UTF8")); + clsFromJar = reader.readLine (); + in.close (); + } + } catch (IOException e) { + } + return clsFromJar; + } + + /* + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. + * + * @return instance of provider class if found or null + */ + private static T findServiceProvider(final Class type, final ClassLoader loader) + throws SAXException { + ClassLoader cl = Objects.requireNonNull(loader); + try { + return AccessController.doPrivileged((PrivilegedAction) () -> { + final ServiceLoader serviceLoader; + serviceLoader = ServiceLoader.load(type, cl); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + }); + } catch(ServiceConfigurationError e) { + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + throw new SAXException("Provider for " + type + " cannot be created", x); + + } + } + } diff --git a/jaxp/test/Makefile b/jaxp/test/Makefile index 912f2b98406..bf94d252889 100644 --- a/jaxp/test/Makefile +++ b/jaxp/test/Makefile @@ -76,14 +76,20 @@ endif TEST_ROOT := $(shell $(PWD)) # Root of all test results -ifdef ALT_OUTPUTDIR - ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD)) +ifdef TEST_OUTPUT_DIR + $(shell $(MKDIR) -p $(TEST_OUTPUT_DIR)/jtreg) + ABS_TEST_OUTPUT_DIR := \ + $(shell $(CD) $(TEST_OUTPUT_DIR)/jtreg && $(PWD)) else - ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD)) -endif + ifdef ALT_OUTPUTDIR + ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD)) + else + ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD)) + endif -ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR) -ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) + ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR) + ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) +endif # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) ifndef PRODUCT_HOME diff --git a/jaxp/test/ProblemList.txt b/jaxp/test/ProblemList.txt index c9aaf13d1fb..b6b8b41ba4f 100644 --- a/jaxp/test/ProblemList.txt +++ b/jaxp/test/ProblemList.txt @@ -29,3 +29,5 @@ javax/xml/jaxp/isolatedjdk/catalog/PropertiesTest.sh generic-all # 8150145 javax/xml/jaxp/unittest/common/TransformationWarningsTest.java generic-all +# 8156508 +javax/xml/jaxp/unittest/stream/FactoryFindTest.java generic-all diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java index c3403f9d1d0..c2bf928ba1f 100644 --- a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/BasicModularXMLParserTest.java @@ -38,7 +38,7 @@ import org.testng.annotations.Test; * @library /javax/xml/jaxp/libs * @build jdk.testlibrary.* * @run testng BasicModularXMLParserTest - * @bug 8078820 + * @bug 8078820 8156119 * @summary Tests JAXP lib can instantiate the following interfaces * with customized provider module on boot layer * @@ -51,6 +51,7 @@ import org.testng.annotations.Test; * javax.xml.transform.TransformerFactory * javax.xml.validation.SchemaFactory * javax.xml.xpath.XPathFactory + * org.xml.sax.XMLReader */ @Test diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java index 45f24001278..3e157679b9e 100644 --- a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/LayerModularXMLParserTest.java @@ -50,7 +50,7 @@ import jdk.testlibrary.CompilerUtils; * @library /javax/xml/jaxp/libs * @build jdk.testlibrary.* * @run testng LayerModularXMLParserTest - * @bug 8078820 + * @bug 8078820 8156119 * @summary Tests JAXP lib works with layer and TCCL */ @@ -75,7 +75,7 @@ public class LayerModularXMLParserTest { * services provided by provider2 */ private static final String[] services2 = { "javax.xml.datatype.DatatypeFactory", - "javax.xml.stream.XMLEventFactory" }; + "javax.xml.stream.XMLEventFactory", "org.xml.sax.XMLReader" }; /* * Compiles all modules used by the test diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/XMLReaderFactoryTest.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/XMLReaderFactoryTest.java new file mode 100644 index 00000000000..ef3507fe9d1 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/XMLReaderFactoryTest.java @@ -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. + */ + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.testlibrary.CompilerUtils; + +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/* + * @test + * @library /javax/xml/jaxp/libs + * @build jdk.testlibrary.* + * @run testng XMLReaderFactoryTest + * @bug 8152912 8015099 8156119 + * @summary Tests XMLReaderFactory can work as ServiceLoader compliant, as well as backward compatible + */ + +@Test +public class XMLReaderFactoryTest { + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src").resolve("xmlprovider3"); + private static final Path CLASSES_DIR = Paths.get("classes"); + private static final Path LEGACY_DIR = CLASSES_DIR.resolve("legacy"); + private static final Path SERVICE_DIR = CLASSES_DIR.resolve("service"); + + // resources to copy to the class path + private static final String LEGACY_SERVICE_FILE = "legacy/META-INF/services/org.xml.sax.driver"; + private static final String SERVICE_FILE = "service/META-INF/services/org.xml.sax.XMLReader"; + + /* + * Compile class and copy service files + */ + @BeforeTest + public void setup() throws Exception { + setup(LEGACY_DIR, LEGACY_SERVICE_FILE); + setup(SERVICE_DIR, SERVICE_FILE); + } + + private void setup(Path dest, String serviceFile) throws Exception { + Files.createDirectories(dest); + assertTrue(CompilerUtils.compile(SRC_DIR, dest)); + + Path file = Paths.get(serviceFile.replace('/', File.separatorChar)); + Path source = SRC_DIR.resolve(file); + Path target = CLASSES_DIR.resolve(file); + Files.createDirectories(target.getParent()); + Files.copy(source, target); + + } + + public void testService() throws Exception { + ClassLoader clBackup = Thread.currentThread().getContextClassLoader(); + try { + URL[] classUrls = { SERVICE_DIR.toUri().toURL() }; + URLClassLoader loader = new URLClassLoader(classUrls, ClassLoader.getSystemClassLoader().getParent()); + + // set TCCL and try locating the provider + Thread.currentThread().setContextClassLoader(loader); + XMLReader reader = XMLReaderFactory.createXMLReader(); + assertEquals(reader.getClass().getName(), "xp3.XMLReaderImpl"); + } finally { + Thread.currentThread().setContextClassLoader(clBackup); + } + } + + public void testLegacy() throws Exception { + ClassLoader clBackup = Thread.currentThread().getContextClassLoader(); + try { + URL[] classUrls = { LEGACY_DIR.toUri().toURL() }; + URLClassLoader loader = new URLClassLoader(classUrls, ClassLoader.getSystemClassLoader().getParent()); + + // set TCCL and try locating the provider + Thread.currentThread().setContextClassLoader(loader); + XMLReader reader1 = XMLReaderFactory.createXMLReader(); + assertEquals(reader1.getClass().getName(), "xp3.XMLReaderImpl"); + + // now point to a random URL + Thread.currentThread().setContextClassLoader( + new URLClassLoader(new URL[0], ClassLoader.getSystemClassLoader().getParent())); + // ClassNotFoundException if also trying to load class of reader1, which + // would be the case before 8152912 + XMLReader reader2 = XMLReaderFactory.createXMLReader(); + assertEquals(reader2.getClass().getName(), "com.sun.org.apache.xerces.internal.parsers.SAXParser"); + } finally { + Thread.currentThread().setContextClassLoader(clBackup); + } + } +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java index 6dfaec5cedf..4f4a530a288 100644 --- a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/test/test/XMLFactoryHelper.java @@ -31,6 +31,8 @@ import java.lang.System; import java.util.Iterator; import java.util.ServiceLoader; +import org.xml.sax.helpers.XMLReaderFactory; + public class XMLFactoryHelper { /* * instantiate a xml factory by reflection e.g. @@ -41,7 +43,9 @@ public class XMLFactoryHelper { try { // set thread context class loader to module class loader Thread.currentThread().setContextClassLoader(XMLFactoryHelper.class.getClassLoader()); - if (serviceName.equals("javax.xml.validation.SchemaFactory")) + if (serviceName.equals("org.xml.sax.XMLReader")) + return XMLReaderFactory.createXMLReader(); + else if (serviceName.equals("javax.xml.validation.SchemaFactory")) return Class.forName(serviceName).getMethod("newInstance", String.class) .invoke(null, W3C_XML_SCHEMA_NS_URI); else diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java index cb0a37e916b..ee3e3e004d5 100644 --- a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/unnamed/Main.java @@ -30,6 +30,8 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; +import org.xml.sax.helpers.XMLReaderFactory; + public class Main { /* * @param args, the names of provider modules, which have been loaded @@ -69,7 +71,9 @@ public class Main { */ private static Object instantiateXMLService(String serviceName) { try { - if (serviceName.equals("javax.xml.validation.SchemaFactory")) + if (serviceName.equals("org.xml.sax.XMLReader")) + return XMLReaderFactory.createXMLReader(); + else if (serviceName.equals("javax.xml.validation.SchemaFactory")) return Class.forName(serviceName).getMethod("newInstance", String.class) .invoke(null, W3C_XML_SCHEMA_NS_URI); else @@ -102,6 +106,7 @@ public class Main { "javax.xml.parsers.DocumentBuilderFactory", "javax.xml.parsers.SAXParserFactory", "javax.xml.stream.XMLEventFactory", "javax.xml.stream.XMLInputFactory", "javax.xml.stream.XMLOutputFactory", "javax.xml.transform.TransformerFactory", - "javax.xml.validation.SchemaFactory", "javax.xml.xpath.XPathFactory" }; + "javax.xml.validation.SchemaFactory", "javax.xml.xpath.XPathFactory", + "org.xml.sax.XMLReader"}; } diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java index d55645e58e9..c8bc623aa7a 100644 --- a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/module-info.java @@ -26,4 +26,5 @@ module xmlprovider2 { provides javax.xml.datatype.DatatypeFactory with xp2.DatatypeFactoryImpl; provides javax.xml.stream.XMLEventFactory with xp2.XMLEventFactoryImpl; + provides org.xml.sax.XMLReader with xp2.XMLReaderImpl; } \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLReaderImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLReaderImpl.java new file mode 100644 index 00000000000..0b6276f818e --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider2/xp2/XMLReaderImpl.java @@ -0,0 +1,106 @@ +/* + * 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 xp2; + +import java.io.IOException; + +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +public class XMLReaderImpl implements XMLReader { + + @Override + public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return false; + } + + @Override + public void setFeature(String name, boolean value) throws SAXNotRecognizedException, + SAXNotSupportedException { + } + + @Override + public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return null; + } + + @Override + public void setProperty(String name, Object value) throws SAXNotRecognizedException, + SAXNotSupportedException { + } + + @Override + public void setEntityResolver(EntityResolver resolver) { + // TODO Auto-generated method stub + + } + + @Override + public EntityResolver getEntityResolver() { + return null; + } + + @Override + public void setDTDHandler(DTDHandler handler) { + } + + @Override + public DTDHandler getDTDHandler() { + return null; + } + + @Override + public void setContentHandler(ContentHandler handler) { + } + + @Override + public ContentHandler getContentHandler() { + return null; + } + + @Override + public void setErrorHandler(ErrorHandler handler) { + } + + @Override + public ErrorHandler getErrorHandler() { + return null; + } + + @Override + public void parse(InputSource input) throws IOException, SAXException { + } + + @Override + public void parse(String systemId) throws IOException, SAXException { + } + +} diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/legacy/META-INF/services/org.xml.sax.driver b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/legacy/META-INF/services/org.xml.sax.driver new file mode 100644 index 00000000000..ef9ddc888ef --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/legacy/META-INF/services/org.xml.sax.driver @@ -0,0 +1 @@ +xp3.XMLReaderImpl diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/service/META-INF/services/org.xml.sax.XMLReader b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/service/META-INF/services/org.xml.sax.XMLReader new file mode 100644 index 00000000000..ef9ddc888ef --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/service/META-INF/services/org.xml.sax.XMLReader @@ -0,0 +1 @@ +xp3.XMLReaderImpl diff --git a/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/xp3/XMLReaderImpl.java b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/xp3/XMLReaderImpl.java new file mode 100644 index 00000000000..80738a961c1 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/module/ServiceProviderTest/src/xmlprovider3/xp3/XMLReaderImpl.java @@ -0,0 +1,106 @@ +/* + * 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 xp3; + +import java.io.IOException; + +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +public class XMLReaderImpl implements XMLReader { + + @Override + public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return false; + } + + @Override + public void setFeature(String name, boolean value) throws SAXNotRecognizedException, + SAXNotSupportedException { + } + + @Override + public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return null; + } + + @Override + public void setProperty(String name, Object value) throws SAXNotRecognizedException, + SAXNotSupportedException { + } + + @Override + public void setEntityResolver(EntityResolver resolver) { + // TODO Auto-generated method stub + + } + + @Override + public EntityResolver getEntityResolver() { + return null; + } + + @Override + public void setDTDHandler(DTDHandler handler) { + } + + @Override + public DTDHandler getDTDHandler() { + return null; + } + + @Override + public void setContentHandler(ContentHandler handler) { + } + + @Override + public ContentHandler getContentHandler() { + return null; + } + + @Override + public void setErrorHandler(ErrorHandler handler) { + } + + @Override + public ErrorHandler getErrorHandler() { + return null; + } + + @Override + public void parse(InputSource input) throws IOException, SAXException { + } + + @Override + public void parse(String systemId) throws IOException, SAXException { + } + +} diff --git a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamWriterTest/SurrogatesTest.java b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamWriterTest/SurrogatesTest.java new file mode 100644 index 00000000000..a24c6b8b54f --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamWriterTest/SurrogatesTest.java @@ -0,0 +1,171 @@ +/* + * 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 stream.XMLStreamWriterTest; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStreamWriter; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.testng.Assert; +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; + +/* + * @test + * @bug 8145974 + * @modules javax.xml + * @summary Check that XMLStreamWriter generates valid xml with surrogate pair + * used within element text + */ + +public class SurrogatesTest { + + // Test that valid surrogate characters can be written/readen by xml stream + // reader/writer + @Test(dataProvider = "validData") + public void xmlWithValidSurrogatesTest(String content) + throws Exception { + generateAndReadXml(content); + } + + // Test that unbalanced surrogate character will + @Test(dataProvider = "invalidData", + expectedExceptions = XMLStreamException.class) + public void xmlWithUnbalancedSurrogatesTest(String content) + throws Exception { + generateAndReadXml(content); + } + + // Generates xml content with XMLStreamWriter and read it to check + // for correctness of xml and generated data + void generateAndReadXml(String content) throws Exception { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + OutputStreamWriter streamWriter = new OutputStreamWriter(stream); + XMLStreamWriter writer = factory.createXMLStreamWriter(streamWriter); + + // Generate xml with selected stream writer type + generateXML(writer, content); + String output = stream.toString(); + System.out.println("Generated xml: " + output); + // Read generated xml with StAX parser + readXML(output.getBytes(), content); + } + + // Generates XML with provided xml stream writer. Provided string + // is inserted into xml twice: with usage of writeCharacters( String ) + // and writeCharacters( char [], int , int ) + private void generateXML(XMLStreamWriter writer, String sequence) + throws XMLStreamException { + char[] seqArr = sequence.toCharArray(); + writer.writeStartDocument(); + writer.writeStartElement("root"); + + // Use writeCharacters( String ) to write characters + writer.writeStartElement("writeCharactersWithString"); + writer.writeCharacters(sequence); + writer.writeEndElement(); + + // Use writeCharacters( char [], int , int ) to write characters + writer.writeStartElement("writeCharactersWithArray"); + writer.writeCharacters(seqArr, 0, seqArr.length); + writer.writeEndElement(); + + // Close root element and document + writer.writeEndElement(); + writer.writeEndDocument(); + writer.flush(); + writer.close(); + } + + // Reads generated XML data and check if it contains expected + // text in writeCharactersWithString and writeCharactersWithArray + // elements + private void readXML(byte[] xmlData, String expectedContent) + throws Exception { + InputStream stream = new ByteArrayInputStream(xmlData); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLStreamReader xmlReader + = factory.createXMLStreamReader(stream); + boolean inTestElement = false; + StringBuilder sb = new StringBuilder(); + while (xmlReader.hasNext()) { + String ename; + switch (xmlReader.getEventType()) { + case XMLStreamConstants.START_ELEMENT: + ename = xmlReader.getLocalName(); + if (ename.equals("writeCharactersWithString") + || ename.equals("writeCharactersWithArray")) { + inTestElement = true; + } + break; + case XMLStreamConstants.END_ELEMENT: + ename = xmlReader.getLocalName(); + if (ename.equals("writeCharactersWithString") + || ename.equals("writeCharactersWithArray")) { + inTestElement = false; + String content = sb.toString(); + System.out.println(ename + " text:'" + content + "' expected:'" + expectedContent+"'"); + Assert.assertEquals(content, expectedContent); + sb.setLength(0); + } + break; + case XMLStreamConstants.CHARACTERS: + if (inTestElement) { + sb.append(xmlReader.getText()); + } + break; + } + xmlReader.next(); + } + } + + @DataProvider(name = "validData") + Object[][] getValidData() { + return new Object[][] { + {"Don't Worry Be \uD83D\uDE0A"}, + {"BMP characters \uE000\uFFFD"}, + {"Simple text"}, + }; + } + + @DataProvider(name = "invalidData") + Object[][] getInvalidData() { + return new Object[][] { + {"Unbalanced surrogate \uD83D"}, + {"Unbalanced surrogate \uD83Dis here"}, + {"Surrogate with followup BMP\uD83D\uFFF9"}, + }; + } +} diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 514c6a8ced9..4d92200f4dc 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -363,3 +363,4 @@ b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114 4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115 529f0bf896e58525614d863e283ad155531941cb jdk-9+116 58265b39fc74b932bda4d4f4649c530a89f55c4e jdk-9+117 +6ba73d04589ccc0705a5d8ae5111b63632b6ad20 jdk-9+118 diff --git a/jdk/.hgtags b/jdk/.hgtags index 59c7f91c625..2b6d80debed 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -360,3 +360,4 @@ bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114 35225b837d66582037eeadeb471c13235dfd793d jdk-9+115 baeb5edb38939cdb78ae0ac6f4fd368465cbf188 jdk-9+116 4da0f73ce03aaf245b92cc040cc0ab0e3fa54dc2 jdk-9+117 +e1eba5cfa5cc8c66d524396a05323dc93568730a jdk-9+118 diff --git a/jdk/make/Import.gmk b/jdk/make/Import.gmk index d479b095514..29e4ce0f19e 100644 --- a/jdk/make/Import.gmk +++ b/jdk/make/Import.gmk @@ -112,7 +112,7 @@ $(BASE_INSTALL_LIBRARIES_HERE)/server/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_ $(LN) -s ../$(@F) $@ ifeq ($(OPENJDK_TARGET_OS), macosx) - $(BASE_INSTALL_LIBRARIES_HERE)/server/%.dSYM : $(BASE_INSTALL_LIBRARIES_HERE)/%.dSYM + $(BASE_INSTALL_LIBRARIES_HERE)/server/%.dSYM: $(MKDIR) -p $(@D) $(RM) $@ $(LN) -s ../$(@F) $@ diff --git a/jdk/make/launcher/Launcher-java.base.gmk b/jdk/make/launcher/Launcher-java.base.gmk index 77d241405c3..d5ded27b9ea 100644 --- a/jdk/make/launcher/Launcher-java.base.gmk +++ b/jdk/make/launcher/Launcher-java.base.gmk @@ -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 @@ -25,11 +25,11 @@ include LauncherCommon.gmk -JAVA_RC_FLAGS += -i $(JDK_TOPDIR)/src/java.base/windows/native/common +JAVA_RC_FLAGS += -I $(JDK_TOPDIR)/src/java.base/windows/native/common ifdef OPENJDK - JAVA_RC_FLAGS += -i "$(JDK_TOPDIR)/src/java.base/windows/native/launcher/icons" + JAVA_RC_FLAGS += -I $(JDK_TOPDIR)/src/java.base/windows/native/launcher/icons else - JAVA_RC_FLAGS += -i "$(JDK_TOPDIR)/src/closed/java.base/windows/native/launcher/icons" + JAVA_RC_FLAGS += -I $(JDK_TOPDIR)/src/closed/java.base/windows/native/launcher/icons endif ################################################################################ diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index 57067da008d..b4c6f5e20a3 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -213,9 +213,9 @@ ifeq ($(OPENJDK_TARGET_OS), windows) endif ifdef OPENJDK - LIBAWT_RC_FLAGS := -i "$(JDK_TOPDIR)/src/java.base/windows/native/launcher/icons" + LIBAWT_RC_FLAGS := -I $(JDK_TOPDIR)/src/java.base/windows/native/launcher/icons else - LIBAWT_RC_FLAGS := -i "$(JDK_TOPDIR)/src/closed/java.base/windows/native/launcher/icons" + LIBAWT_RC_FLAGS := -I $(JDK_TOPDIR)/src/closed/java.base/windows/native/launcher/icons endif LIBAWT_VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/java.desktop/windows/native/libawt/windows/awt.rc endif diff --git a/jdk/make/mapfiles/libj2ucrypto/mapfile-vers b/jdk/make/mapfiles/libj2ucrypto/mapfile-vers index 833da53297e..2f2b8d6a4dd 100644 --- a/jdk/make/mapfiles/libj2ucrypto/mapfile-vers +++ b/jdk/make/mapfiles/libj2ucrypto/mapfile-vers @@ -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 @@ -30,28 +30,35 @@ SUNWprivate_1.1 { JNI_OnLoad; Java_com_oracle_security_ucrypto_UcryptoProvider_loadLibraries; Java_com_oracle_security_ucrypto_UcryptoProvider_getMechList; - Java_com_oracle_security_ucrypto_NativeDigest_nativeInit; + Java_com_oracle_security_ucrypto_NativeDigestMD_nativeInit; + Java_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate; + Java_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest; + Java_com_oracle_security_ucrypto_NativeDigestMD_nativeClone; + Java_com_oracle_security_ucrypto_NativeDigestMD_nativeFree; + Java_com_oracle_security_ucrypto_NativeDigest_nativeInit; Java_com_oracle_security_ucrypto_NativeDigest_nativeUpdate; Java_com_oracle_security_ucrypto_NativeDigest_nativeDigest; - Java_com_oracle_security_ucrypto_NativeDigest_nativeClone; Java_com_oracle_security_ucrypto_NativeDigest_nativeFree; - Java_com_oracle_security_ucrypto_NativeCipher_nativeInit; - Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate; - Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal; + Java_com_oracle_security_ucrypto_NativeCipher_nativeInit; + Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate; + Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal; Java_com_oracle_security_ucrypto_NativeKey_nativeFree; Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit; Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit; Java_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit; - Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit; - Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII; - Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI; - Java_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal; - Java_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic; - + Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit; + Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII; + Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI; + Java_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal; + Java_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic; + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit; + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate; + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest; + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone; + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree; JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit; JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate; JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest; - JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone; JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeFree; JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeInit; JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate; @@ -60,10 +67,10 @@ SUNWprivate_1.1 { JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit; JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit; JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit; - JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit; - JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII; - JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI; - JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal; + JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit; + JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII; + JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI; + JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal; JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic; local: diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 118b0fd3ddf..693f5a87fb8 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -262,7 +262,7 @@ SUNWprivate_1.1 { 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_latestUserDefinedLoader0; Java_jdk_internal_misc_VM_getuid; Java_jdk_internal_misc_VM_geteuid; Java_jdk_internal_misc_VM_getgid; diff --git a/jdk/src/java.base/share/classes/java/io/BufferedWriter.java b/jdk/src/java.base/share/classes/java/io/BufferedWriter.java index 28e170fe800..3d8e1ee1b19 100644 --- a/jdk/src/java.base/share/classes/java/io/BufferedWriter.java +++ b/jdk/src/java.base/share/classes/java/io/BufferedWriter.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 @@ -153,13 +153,18 @@ public class BufferedWriter extends Writer { * needed. If the requested length is at least as large as the buffer, * however, then this method will flush the buffer and write the characters * directly to the underlying stream. Thus redundant - * BufferedWriters will not copy data unnecessarily. + * {@code BufferedWriter}s will not copy data unnecessarily. * * @param cbuf A character array * @param off Offset from which to start reading characters * @param len Number of characters to write * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array + * + * @throws IOException If an I/O error occurs */ public void write(char cbuf[], int off, int len) throws IOException { synchronized (lock) { @@ -195,17 +200,24 @@ public class BufferedWriter extends Writer { /** * Writes a portion of a String. * - *

If the value of the {@code len} parameter is negative then no - * characters are written. This is contrary to the specification of this - * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int) - * superclass}, which requires that an {@link IndexOutOfBoundsException} be - * thrown. + * @implSpec + * While the specification of this method in the + * {@linkplain java.io.Writer#write(java.lang.String,int,int) superclass} + * recommends that an {@link IndexOutOfBoundsException} be thrown + * if {@code len} is negative or {@code off + len} is negative, + * the implementation in this class does not throw such an exception in + * these cases but instead simply writes no characters. * * @param s String to be written * @param off Offset from which to start reading characters * @param len Number of characters to be written * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If {@code off} is negative, + * or {@code off + len} is greater than the length + * of the given string + * + * @throws IOException If an I/O error occurs */ public void write(String s, int off, int len) throws IOException { synchronized (lock) { diff --git a/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java b/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java index ed27bbae314..773b59614d9 100644 --- a/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java +++ b/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, 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 @@ -91,6 +91,11 @@ class CharArrayWriter extends Writer { * @param c the data to be written * @param off the start offset in the data * @param len the number of chars that are written + * + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array */ public void write(char c[], int off, int len) { if ((off < 0) || (off > c.length) || (len < 0) || @@ -114,6 +119,11 @@ class CharArrayWriter extends Writer { * @param str String to be written from * @param off Offset from which to start reading characters * @param len Number of characters to be written + * + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given string */ public void write(String str, int off, int len) { synchronized (lock) { diff --git a/jdk/src/java.base/share/classes/java/io/FilterWriter.java b/jdk/src/java.base/share/classes/java/io/FilterWriter.java index 303c674e0c0..8272b3cc8bf 100644 --- a/jdk/src/java.base/share/classes/java/io/FilterWriter.java +++ b/jdk/src/java.base/share/classes/java/io/FilterWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, 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 @@ -72,7 +72,12 @@ public abstract class FilterWriter extends Writer { * @param off Offset from which to start reading characters * @param len Number of characters to be written * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If the values of the {@code off} and {@code len} parameters + * cause the corresponding method of the underlying {@code Writer} + * to throw an {@code IndexOutOfBoundsException} + * + * @throws IOException If an I/O error occurs */ public void write(char cbuf[], int off, int len) throws IOException { out.write(cbuf, off, len); @@ -85,7 +90,12 @@ public abstract class FilterWriter extends Writer { * @param off Offset from which to start reading characters * @param len Number of characters to be written * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If the values of the {@code off} and {@code len} parameters + * cause the corresponding method of the underlying {@code Writer} + * to throw an {@code IndexOutOfBoundsException} + * + * @throws IOException If an I/O error occurs */ public void write(String str, int off, int len) throws IOException { out.write(str, off, len); 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 a591136419d..9f13c9216a3 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -603,12 +603,12 @@ public class ObjectInputStream * Class.forName(desc.getName(), false, loader) * * where loader is determined as follows: if there is a - * method on the current thread's stack whose declaring class was - * defined by a user-defined class loader (and was not a generated to - * implement reflective invocations), then loader is class - * loader corresponding to the closest such method to the currently - * executing frame; otherwise, loader is - * null. If this call results in a + * method on the current thread's stack whose declaring class is not a + * + * platform class, then loader is + * the class loader of such class; otherwise, loader + * is the {@linkplain ClassLoader#getPlatformClassLoader() + * platform class loader}. If this call results in a * ClassNotFoundException and the name of the passed * ObjectStreamClass instance is the Java language keyword * for a primitive type or void, then the Class object @@ -666,12 +666,15 @@ public class ObjectInputStream *

      *     Class.forName(i, false, loader)
      * 
- * where loader is that of the first non-null - * class loader up the execution stack, or null if no - * non-null class loaders are on the stack (the same class - * loader choice used by the resolveClass method). Unless any - * of the resolved interfaces are non-public, this same value of - * loader is also the class loader passed to + * where loader is determined as follows: if there is a + * method on the current thread's stack whose declaring class is not a + * + * platform class, then loader is + * the class loader of such class; otherwise, loader + * is the {@linkplain ClassLoader#getPlatformClassLoader() + * platform class loader}. + * Unless any of the resolved interfaces are non-public, this same value + * of loader is also the class loader passed to * Proxy.getProxyClass; if non-public interfaces are present, * their class loader is passed instead (if more than one non-public * interface class loader is encountered, an @@ -2154,10 +2157,11 @@ public class ObjectInputStream int ndoubles); /** - * Returns the first non-null class loader (not counting class loaders of - * generated reflection implementation classes) up the execution stack, or - * null if only code from the null class loader is on the stack. This - * method is also called via reflection by the following RMI-IIOP class: + * Returns the first non-null and non-platform class loader + * (not counting class loaders of generated reflection implementation classes) + * up the execution stack, or null if only code from the bootstrap and + * platform class loader is on the stack. + * This method is also called via reflection by the following RMI-IIOP class: * * com.sun.corba.se.internal.util.JDKClassLoader * diff --git a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java index 0d597e6bef4..4fdb148baaf 100644 --- a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java +++ b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.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 @@ -202,7 +202,12 @@ public class OutputStreamWriter extends Writer { * @param off Offset from which to start writing characters * @param len Number of characters to write * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array + * + * @throws IOException If an I/O error occurs */ public void write(char cbuf[], int off, int len) throws IOException { se.write(cbuf, off, len); @@ -215,7 +220,12 @@ public class OutputStreamWriter extends Writer { * @param off Offset from which to start writing characters * @param len Number of characters to write * - * @exception IOException If an I/O error occurs + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given string + * + * @throws IOException If an I/O error occurs */ public void write(String str, int off, int len) throws IOException { se.write(str, off, len); diff --git a/jdk/src/java.base/share/classes/java/io/PipedWriter.java b/jdk/src/java.base/share/classes/java/io/PipedWriter.java index 02201fbec1a..a4534b8604c 100644 --- a/jdk/src/java.base/share/classes/java/io/PipedWriter.java +++ b/jdk/src/java.base/share/classes/java/io/PipedWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, 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 @@ -125,19 +125,25 @@ public class PipedWriter extends Writer { } /** - * Writes len characters from the specified character array - * starting at offset off to this piped output stream. + * Writes {@code len} characters from the specified character array + * starting at offset {@code off} to this piped output stream. * This method blocks until all the characters are written to the output * stream. * If a thread was reading data characters from the connected piped input * stream, but the thread is no longer alive, then an - * IOException is thrown. + * {@code IOException} is thrown. * * @param cbuf the data. * @param off the start offset in the data. * @param len the number of characters to write. - * @exception IOException if the pipe is - * broken, + * + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array + * + * @throws IOException if the pipe is + * broken, * {@link #connect(java.io.PipedReader) unconnected}, closed * or an I/O error occurs. */ diff --git a/jdk/src/java.base/share/classes/java/io/PrintWriter.java b/jdk/src/java.base/share/classes/java/io/PrintWriter.java index 662f930ef90..d516b8ef404 100644 --- a/jdk/src/java.base/share/classes/java/io/PrintWriter.java +++ b/jdk/src/java.base/share/classes/java/io/PrintWriter.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 @@ -410,6 +410,11 @@ public class PrintWriter extends Writer { * @param buf Array of characters * @param off Offset from which to start writing characters * @param len Number of characters to write + * + * @throws IndexOutOfBoundsException + * If the values of the {@code off} and {@code len} parameters + * cause the corresponding method of the underlying {@code Writer} + * to throw an {@code IndexOutOfBoundsException} */ public void write(char buf[], int off, int len) { try { @@ -440,6 +445,11 @@ public class PrintWriter extends Writer { * @param s A String * @param off Offset from which to start writing characters * @param len Number of characters to write + * + * @throws IndexOutOfBoundsException + * If the values of the {@code off} and {@code len} parameters + * cause the corresponding method of the underlying {@code Writer} + * to throw an {@code IndexOutOfBoundsException} */ public void write(String s, int off, int len) { try { diff --git a/jdk/src/java.base/share/classes/java/io/StringWriter.java b/jdk/src/java.base/share/classes/java/io/StringWriter.java index 5d1babc3127..15022b353a8 100644 --- a/jdk/src/java.base/share/classes/java/io/StringWriter.java +++ b/jdk/src/java.base/share/classes/java/io/StringWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2004, 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 @@ -83,6 +83,11 @@ public class StringWriter extends Writer { * @param cbuf Array of characters * @param off Offset from which to start writing characters * @param len Number of characters to write + * + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array */ public void write(char cbuf[], int off, int len) { if ((off < 0) || (off > cbuf.length) || (len < 0) || @@ -107,6 +112,11 @@ public class StringWriter extends Writer { * @param str String to be written * @param off Offset from which to start writing characters * @param len Number of characters to write + * + * @throws IndexOutOfBoundsException + * If {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given string */ public void write(String str, int off, int len) { buf.append(str, off, off + len); diff --git a/jdk/src/java.base/share/classes/java/io/Writer.java b/jdk/src/java.base/share/classes/java/io/Writer.java index 5ad5e554fb3..17e8de3ef8a 100644 --- a/jdk/src/java.base/share/classes/java/io/Writer.java +++ b/jdk/src/java.base/share/classes/java/io/Writer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,11 @@ package java.io; * Most subclasses, however, will override some of the methods defined here in * order to provide higher efficiency, additional functionality, or both. * - * @see Writer * @see BufferedWriter * @see CharArrayWriter * @see FilterWriter * @see OutputStreamWriter - * @see FileWriter + * @see FileWriter * @see PipedWriter * @see PrintWriter * @see StringWriter @@ -139,6 +138,12 @@ public abstract class Writer implements Appendable, Closeable, Flushable { * @param len * Number of characters to write * + * @throws IndexOutOfBoundsException + * Implementations should throw this exception + * if {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length + * of the given array + * * @throws IOException * If an I/O error occurs */ @@ -160,6 +165,11 @@ public abstract class Writer implements Appendable, Closeable, Flushable { /** * Writes a portion of a string. * + * @implSpec + * The implementation in this class throws an + * {@code IndexOutOfBoundsException} for the indicated conditions; + * overriding methods may choose to do otherwise. + * * @param str * A String * @@ -170,8 +180,9 @@ public abstract class Writer implements Appendable, Closeable, Flushable { * Number of characters to write * * @throws IndexOutOfBoundsException - * If {@code off} is negative, or {@code len} is negative, - * or {@code off+len} is negative or greater than the length + * Implementations should throw this exception + * if {@code off} is negative, or {@code len} is negative, + * or {@code off + len} is negative or greater than the length * of the given string * * @throws IOException 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 54fc27f31b5..310ada1b470 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -340,6 +340,45 @@ class Thread implements Runnable { sleep(millis); } + /** + * Indicates that the caller is momentarily unable to progress, until the + * occurrence of one or more actions on the part of other activities. By + * invoking this method within each iteration of a spin-wait loop construct, + * the calling thread indicates to the runtime that it is busy-waiting. + * The runtime may take action to improve the performance of invoking + * spin-wait loop constructions. + *

+ * @apiNote + * As an example consider a method in a class that spins in a loop until + * some flag is set outside of that method. A call to the {@code onSpinWait} + * method should be placed inside the spin loop. + *

{@code
+     *     class EventHandler {
+     *         volatile boolean eventNotificationNotReceived;
+     *         void waitForEventAndHandleIt() {
+     *             while ( eventNotificationNotReceived ) {
+     *                 java.lang.Thread.onSpinWait();
+     *             }
+     *             readAndProcessEvent();
+     *         }
+     *
+     *         void readAndProcessEvent() {
+     *             // Read event from some source and process it
+     *              . . .
+     *         }
+     *     }
+     * }
+ *

+ * The code above would remain correct even if the {@code onSpinWait} + * method was not called at all. However on some architectures the Java + * Virtual Machine may issue the processor instructions to address such + * code patterns in a more beneficial way. + *

+ * @since 9 + */ + @HotSpotIntrinsicCandidate + public static void onSpinWait() {} + /** * Initializes a Thread with the current AccessControlContext. * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 08e38987bf2..da1700ffdb1 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -706,6 +706,9 @@ class InvokerBytecodeGenerator { case ARRAY_STORE: emitArrayStore(name); continue; + case ARRAY_LENGTH: + emitArrayLength(name); + continue; case IDENTITY: assert(name.arguments.length == 1); emitPushArguments(name); @@ -740,15 +743,16 @@ class InvokerBytecodeGenerator { return classFile; } - void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); } - void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); } + void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); } + void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); } + void emitArrayLength(Name name) { emitArrayOp(name, Opcodes.ARRAYLENGTH); } void emitArrayOp(Name name, int arrayOpcode) { - assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE; + assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE || arrayOpcode == Opcodes.ARRAYLENGTH; Class elementType = name.function.methodType().parameterType(0).getComponentType(); assert elementType != null; emitPushArguments(name); - if (elementType.isPrimitive()) { + if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) { Wrapper w = Wrapper.forPrimitiveType(elementType); arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java index 29cc430f877..1aca86298fe 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -95,12 +95,12 @@ class Invokers { /*non-public*/ MethodHandle varHandleMethodInvoker(VarHandle.AccessMode ak) { // TODO cache invoker - return makeVarHandleMethodInvoker(ak); + return makeVarHandleMethodInvoker(ak, false); } /*non-public*/ MethodHandle varHandleMethodExactInvoker(VarHandle.AccessMode ak) { // TODO cache invoker - return makeVarHandleMethodExactInvoker(ak); + return makeVarHandleMethodInvoker(ak, true); } private MethodHandle cachedInvoker(int idx) { @@ -127,26 +127,11 @@ class Invokers { return invoker; } - private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak) { + private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak, boolean isExact) { MethodType mtype = targetType; MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class); - LambdaForm lform = varHandleMethodGenericInvokerHandleForm(ak.methodName(), mtype); - VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal()); - MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad); - - invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false); - assert(checkVarHandleInvoker(invoker)); - - maybeCompileToBytecode(invoker); - return invoker; - } - - private MethodHandle makeVarHandleMethodExactInvoker(VarHandle.AccessMode ak) { - MethodType mtype = targetType; - MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class); - - LambdaForm lform = varHandleMethodExactInvokerHandleForm(ak.methodName(), mtype); + LambdaForm lform = varHandleMethodInvokerHandleForm(ak.methodName(), mtype, isExact); VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal()); MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad); @@ -400,59 +385,7 @@ class Invokers { return lform; } - private static LambdaForm varHandleMethodExactInvokerHandleForm(String name, MethodType mtype) { - // TODO Cache form? - - final int THIS_MH = 0; - final int CALL_VH = THIS_MH + 1; - final int ARG_BASE = CALL_VH + 1; - final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); - int nameCursor = ARG_LIMIT; - final int VAD_ARG = nameCursor++; - final int CHECK_TYPE = nameCursor++; - final int GET_MEMBER = nameCursor++; - final int LINKER_CALL = nameCursor++; - - MethodType invokerFormType = mtype.insertParameterTypes(0, VarHandle.class) - .basicType() - .appendParameterTypes(MemberName.class); - - MemberName linker = new MemberName(MethodHandle.class, "linkToStatic", invokerFormType, REF_invokeStatic); - try { - linker = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - - Name[] names = new Name[LINKER_CALL + 1]; - names[THIS_MH] = argument(THIS_MH, BasicType.basicType(Object.class)); - names[CALL_VH] = argument(CALL_VH, BasicType.basicType(Object.class)); - for (int i = 0; i < mtype.parameterCount(); i++) { - names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i))); - } - - BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L(); - names[THIS_MH] = names[THIS_MH].withConstraint(speciesData); - - NamedFunction getter = speciesData.getterFunction(0); - names[VAD_ARG] = new Name(getter, names[THIS_MH]); - - Object[] outArgs = Arrays.copyOfRange(names, CALL_VH, ARG_LIMIT + 1, Object[].class); - - names[CHECK_TYPE] = new Name(NF_checkVarHandleExactType, names[CALL_VH], names[VAD_ARG]); - - names[GET_MEMBER] = new Name(NF_getVarHandleMemberName, names[CALL_VH], names[VAD_ARG]); - outArgs[outArgs.length - 1] = names[GET_MEMBER]; - - names[LINKER_CALL] = new Name(linker, outArgs); - LambdaForm lform = new LambdaForm(name + ":VarHandle_exactInvoker" + shortenSignature(basicTypeSignature(mtype)), - ARG_LIMIT, names); - - lform.compileToBytecode(); - return lform; - } - - private static LambdaForm varHandleMethodGenericInvokerHandleForm(String name, MethodType mtype) { + private static LambdaForm varHandleMethodInvokerHandleForm(String name, MethodType mtype, boolean isExact) { // TODO Cache form? final int THIS_MH = 0; @@ -477,8 +410,11 @@ class Invokers { NamedFunction getter = speciesData.getterFunction(0); names[VAD_ARG] = new Name(getter, names[THIS_MH]); - names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[CALL_VH], names[VAD_ARG]); - + if (isExact) { + names[CHECK_TYPE] = new Name(NF_checkVarHandleExactType, names[CALL_VH], names[VAD_ARG]); + } else { + names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[CALL_VH], names[VAD_ARG]); + } Object[] outArgs = new Object[ARG_LIMIT]; outArgs[0] = names[CHECK_TYPE]; for (int i = 1; i < ARG_LIMIT; i++) { @@ -488,7 +424,8 @@ class Invokers { MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) .basicType(); names[LINKER_CALL] = new Name(outCallType, outArgs); - LambdaForm lform = new LambdaForm(name + ":VarHandle_invoker" + shortenSignature(basicTypeSignature(mtype)), + String debugName = isExact ? ":VarHandle_exactInvoker" : ":VarHandle_invoker"; + LambdaForm lform = new LambdaForm(name + debugName + shortenSignature(basicTypeSignature(mtype)), ARG_LIMIT, names); lform.prepare(); @@ -511,21 +448,13 @@ class Invokers { /*non-public*/ static @ForceInline - void checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) { - MethodType erasedTarget = handle.vform.methodType_table[ad.type]; - MethodType erasedSymbolic = ad.symbolicMethodTypeErased; - if (erasedTarget != erasedSymbolic) - throw newWrongMethodTypeException(erasedTarget, erasedSymbolic); - } - - /*non-public*/ static - @ForceInline - MemberName getVarHandleMemberName(VarHandle handle, VarHandle.AccessDescriptor ad) { - MemberName mn = handle.vform.memberName_table[ad.mode]; - if (mn == null) { - throw handle.unsupported(); + MethodHandle checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) { + MethodHandle mh = handle.getMethodHandle(ad.mode); + MethodType mt = mh.type(); + if (mt != ad.symbolicMethodTypeInvoker) { + throw newWrongMethodTypeException(mt, ad.symbolicMethodTypeInvoker); } - return mn; + return mh; } /*non-public*/ static @@ -649,8 +578,7 @@ class Invokers { NF_getCallSiteTarget, NF_checkCustomized, NF_checkVarHandleGenericType, - NF_checkVarHandleExactType, - NF_getVarHandleMemberName; + NF_checkVarHandleExactType; static { try { NamedFunction nfs[] = { @@ -666,8 +594,6 @@ class Invokers { .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)), NF_checkVarHandleExactType = new NamedFunction(Invokers.class .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class)), - NF_getVarHandleMemberName = new NamedFunction(Invokers.class - .getDeclaredMethod("getVarHandleMemberName", VarHandle.class, VarHandle.AccessDescriptor.class)) }; // Each nf must be statically invocable or we get tied up in our bootstraps. assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs)); 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 782eff613ae..6f2f35b8773 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 @@ -66,25 +66,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; /// Factory methods to create method handles: - static MethodHandle makeArrayElementAccessor(Class arrayClass, boolean isSetter) { - if (arrayClass == Object[].class) - return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); + static MethodHandle makeArrayElementAccessor(Class arrayClass, ArrayAccess access) { + if (arrayClass == Object[].class) { + return ArrayAccess.objectAccessor(access); + } if (!arrayClass.isArray()) throw newIllegalArgumentException("not an array: "+arrayClass); MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass); - int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX); + int cacheIndex = ArrayAccess.cacheIndex(access); MethodHandle mh = cache[cacheIndex]; if (mh != null) return mh; - mh = ArrayAccessor.getAccessor(arrayClass, isSetter); - MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); + mh = ArrayAccessor.getAccessor(arrayClass, access); + MethodType correctType = ArrayAccessor.correctType(arrayClass, access); if (mh.type() != correctType) { assert(mh.type().parameterType(0) == Object[].class); - assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); - assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); + /* if access == SET */ assert(access != ArrayAccess.SET || mh.type().parameterType(2) == Object.class); + /* if access == GET */ assert(access != ArrayAccess.GET || + (mh.type().returnType() == Object.class && + correctType.parameterType(0).getComponentType() == correctType.returnType())); // safe to view non-strictly, because element type follows from array type mh = mh.viewAsType(correctType, false); } - mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD)); + mh = makeIntrinsic(mh, ArrayAccess.intrinsic(access)); // Atomically update accessor cache. synchronized(cache) { if (cache[cacheIndex] == null) { @@ -97,9 +100,52 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return mh; } + enum ArrayAccess { + GET, SET, LENGTH; + + // As ArrayAccess and ArrayAccessor have a circular dependency, the ArrayAccess properties cannot be stored in + // final fields. + + static String opName(ArrayAccess a) { + switch (a) { + case GET: return "getElement"; + case SET: return "setElement"; + case LENGTH: return "length"; + } + throw new AssertionError(); + } + + static MethodHandle objectAccessor(ArrayAccess a) { + switch (a) { + case GET: return ArrayAccessor.OBJECT_ARRAY_GETTER; + case SET: return ArrayAccessor.OBJECT_ARRAY_SETTER; + case LENGTH: return ArrayAccessor.OBJECT_ARRAY_LENGTH; + } + throw new AssertionError(); + } + + static int cacheIndex(ArrayAccess a) { + switch (a) { + case GET: return ArrayAccessor.GETTER_INDEX; + case SET: return ArrayAccessor.SETTER_INDEX; + case LENGTH: return ArrayAccessor.LENGTH_INDEX; + } + throw new AssertionError(); + } + + static Intrinsic intrinsic(ArrayAccess a) { + switch (a) { + case GET: return Intrinsic.ARRAY_LOAD; + case SET: return Intrinsic.ARRAY_STORE; + case LENGTH: return Intrinsic.ARRAY_LENGTH; + } + throw new AssertionError(); + } + } + static final class ArrayAccessor { - /// Support for array element access - static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; + /// Support for array element and length access + static final int GETTER_INDEX = 0, SETTER_INDEX = 1, LENGTH_INDEX = 2, INDEX_LIMIT = 3; static final ClassValue TYPED_ACCESSORS = new ClassValue() { @Override @@ -107,14 +153,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return new MethodHandle[INDEX_LIMIT]; } }; - static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER; + static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER, OBJECT_ARRAY_LENGTH; static { MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); - cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD); - cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE); + cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.GET), Intrinsic.ARRAY_LOAD); + cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.SET), Intrinsic.ARRAY_STORE); + cache[LENGTH_INDEX] = OBJECT_ARRAY_LENGTH = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.LENGTH), Intrinsic.ARRAY_LENGTH); assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName())); assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName())); + assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_LENGTH.internalMemberName())); } static int getElementI(int[] a, int i) { return a[i]; } @@ -137,31 +185,47 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static void setElementC(char[] a, int i, char x) { a[i] = x; } static void setElementL(Object[] a, int i, Object x) { a[i] = x; } - static String name(Class arrayClass, boolean isSetter) { + static int lengthI(int[] a) { return a.length; } + static int lengthJ(long[] a) { return a.length; } + static int lengthF(float[] a) { return a.length; } + static int lengthD(double[] a) { return a.length; } + static int lengthZ(boolean[] a) { return a.length; } + static int lengthB(byte[] a) { return a.length; } + static int lengthS(short[] a) { return a.length; } + static int lengthC(char[] a) { return a.length; } + static int lengthL(Object[] a) { return a.length; } + + static String name(Class arrayClass, ArrayAccess access) { Class elemClass = arrayClass.getComponentType(); if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); - return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); + return ArrayAccess.opName(access) + Wrapper.basicTypeChar(elemClass); } - static MethodType type(Class arrayClass, boolean isSetter) { + static MethodType type(Class arrayClass, ArrayAccess access) { Class elemClass = arrayClass.getComponentType(); Class arrayArgClass = arrayClass; if (!elemClass.isPrimitive()) { arrayArgClass = Object[].class; elemClass = Object.class; } - return !isSetter ? - MethodType.methodType(elemClass, arrayArgClass, int.class) : - MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); + switch (access) { + case GET: return MethodType.methodType(elemClass, arrayArgClass, int.class); + case SET: return MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); + case LENGTH: return MethodType.methodType(int.class, arrayArgClass); + } + throw new IllegalStateException("should not reach here"); } - static MethodType correctType(Class arrayClass, boolean isSetter) { + static MethodType correctType(Class arrayClass, ArrayAccess access) { Class elemClass = arrayClass.getComponentType(); - return !isSetter ? - MethodType.methodType(elemClass, arrayClass, int.class) : - MethodType.methodType(void.class, arrayClass, int.class, elemClass); + switch (access) { + case GET: return MethodType.methodType(elemClass, arrayClass, int.class); + case SET: return MethodType.methodType(void.class, arrayClass, int.class, elemClass); + case LENGTH: return MethodType.methodType(int.class, arrayClass); + } + throw new IllegalStateException("should not reach here"); } - static MethodHandle getAccessor(Class arrayClass, boolean isSetter) { - String name = name(arrayClass, isSetter); - MethodType type = type(arrayClass, isSetter); + static MethodHandle getAccessor(Class arrayClass, ArrayAccess access) { + String name = name(arrayClass, access); + MethodType type = type(arrayClass, access); try { return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type); } catch (ReflectiveOperationException ex) { @@ -1282,6 +1346,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; NEW_ARRAY, ARRAY_LOAD, ARRAY_STORE, + ARRAY_LENGTH, IDENTITY, ZERO, NONE // no intrinsic associated 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 c3a97a178a3..2be727ffb0f 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 @@ -2244,6 +2244,20 @@ return mh1; return ani.asType(ani.type().changeReturnType(arrayClass)); } + /** + * Produces a method handle returning the length of an array. + * The type of the method handle will have {@code int} as return type, + * and its sole argument will be the array type. + * @param arrayClass an array type + * @return a method handle which can retrieve the length of an array of the given array type + * @throws NullPointerException if the argument is {@code null} + * @throws IllegalArgumentException if arrayClass is not an array type + */ + public static + MethodHandle arrayLength(Class arrayClass) throws IllegalArgumentException { + return MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.LENGTH); + } + /** * Produces a method handle giving read access to elements of an array. * The type of the method handle will have a return type of the array's @@ -2256,7 +2270,7 @@ return mh1; */ public static MethodHandle arrayElementGetter(Class arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.makeArrayElementAccessor(arrayClass, false); + return MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.GET); } /** @@ -2271,7 +2285,7 @@ return mh1; */ public static MethodHandle arrayElementSetter(Class arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true); + return MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.SET); } /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java index 78a75bf05cc..ee7be4096bf 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -26,6 +26,7 @@ package java.lang.invoke; import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; @@ -33,7 +34,6 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; @@ -1475,11 +1475,11 @@ public abstract class VarHandle { TypesAndInvokers tis = getTypesAndInvokers(); MethodHandle mh = tis.methodHandle_table[mode]; if (mh == null) { - mh = tis.methodHandle_table[mode] = getMethodHandleUncached(tis, mode); + mh = tis.methodHandle_table[mode] = getMethodHandleUncached(mode); } return mh; } - private final MethodHandle getMethodHandleUncached(TypesAndInvokers tis, int mode) { + private final MethodHandle getMethodHandleUncached(int mode) { MethodType mt = accessModeType(AccessMode.values()[mode]). insertParameterTypes(0, VarHandle.class); MemberName mn = vform.getMemberName(mode); @@ -1501,7 +1501,7 @@ public abstract class VarHandle { } static final BiFunction, ArrayIndexOutOfBoundsException> - AIOOBE_SUPPLIER = Objects.outOfBoundsExceptionFormatter( + AIOOBE_SUPPLIER = Preconditions.outOfBoundsExceptionFormatter( new Function() { @Override public ArrayIndexOutOfBoundsException apply(String s) { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template index 7a058afedec..ebb6dd31b79 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template +++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template @@ -24,9 +24,11 @@ */ package java.lang.invoke; -import java.util.Objects; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.ForceInline; +import java.util.Objects; + import static java.lang.invoke.MethodHandleStatics.UNSAFE; #warn @@ -163,8 +165,7 @@ final class VarHandle$Type$s { @ForceInline static boolean weakCompareAndSetVolatile(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) { - // TODO defer to strong form until new Unsafe method is added - return UNSAFE.compareAndSwap$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)), + return UNSAFE.weakCompareAndSwap$Type$Volatile(Objects.requireNonNull(handle.receiverType.cast(holder)), handle.fieldOffset, {#if[Object]?handle.fieldType.cast(expected):expected}, {#if[Object]?handle.fieldType.cast(value):value}); @@ -345,8 +346,7 @@ final class VarHandle$Type$s { @ForceInline static boolean weakCompareAndSetVolatile(FieldStaticReadWrite handle, $type$ expected, $type$ value) { - // TODO defer to strong form until new Unsafe method is added - return UNSAFE.compareAndSwap$Type$(handle.base, + return UNSAFE.weakCompareAndSwap$Type$Volatile(handle.base, handle.fieldOffset, {#if[Object]?handle.fieldType.cast(expected):expected}, {#if[Object]?handle.fieldType.cast(value):value}); @@ -447,7 +447,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.get$Type$Volatile(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); } @ForceInline @@ -458,7 +458,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] UNSAFE.put$Type$Volatile(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(value):value}); } @@ -470,7 +470,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.get$Type$Opaque(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); } @ForceInline @@ -481,7 +481,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] UNSAFE.put$Type$Opaque(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(value):value}); } @@ -493,7 +493,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.get$Type$Acquire(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase); } @ForceInline @@ -504,7 +504,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] UNSAFE.put$Type$Release(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(value):value}); } #if[CAS] @@ -517,7 +517,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.compareAndSwap$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -530,7 +530,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.compareAndExchange$Type$Volatile(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -543,7 +543,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.compareAndExchange$Type$Acquire(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -556,7 +556,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.compareAndExchange$Type$Release(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -569,7 +569,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.weakCompareAndSwap$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -581,9 +581,8 @@ final class VarHandle$Type$s { #else[Object] $type$[] array = ($type$[]) oarray; #end[Object] - // TODO defer to strong form until new Unsafe method is added - return UNSAFE.compareAndSwap$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + return UNSAFE.weakCompareAndSwap$Type$Volatile(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -596,7 +595,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.weakCompareAndSwap$Type$Acquire(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -609,7 +608,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.weakCompareAndSwap$Type$Release(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(expected):expected}, {#if[Object]?handle.componentType.cast(value):value}); } @@ -622,7 +621,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.getAndSet$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, {#if[Object]?handle.componentType.cast(value):value}); } #end[CAS] @@ -636,7 +635,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.getAndAdd$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, value); } @@ -648,7 +647,7 @@ final class VarHandle$Type$s { $type$[] array = ($type$[]) oarray; #end[Object] return UNSAFE.getAndAdd$Type$(array, - (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, value) + value; } #end[AtomicAdd] diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template index 8639e0d342e..66bf267476e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template +++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template @@ -25,6 +25,7 @@ package java.lang.invoke; import jdk.internal.misc.Unsafe; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.ForceInline; import java.nio.ByteBuffer; @@ -81,7 +82,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { @ForceInline static int index(byte[] ba, int index) { - return Objects.checkIndex(index, ba.length - ALIGN, null); + return Preconditions.checkIndex(index, ba.length - ALIGN, null); } @ForceInline @@ -233,8 +234,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { @ForceInline static boolean weakCompareAndSetVolatile(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) { byte[] ba = (byte[]) oba; - // TODO defer to strong form until new Unsafe method is added - return UNSAFE.compareAndSwap$RawType$( + return UNSAFE.weakCompareAndSwap$RawType$Volatile( ba, address(ba, index(ba, index)), convEndian(handle.be, expected), convEndian(handle.be, value)); @@ -271,22 +271,33 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { #if[AtomicAdd] @ForceInline - static $type$ getAndAdd(ArrayHandle handle, Object oba, int index, $type$ value) { + static $type$ getAndAdd(ArrayHandle handle, Object oba, int index, $type$ delta) { byte[] ba = (byte[]) oba; - return convEndian(handle.be, - UNSAFE.getAndAdd$RawType$( - ba, - address(ba, index(ba, index)), - convEndian(handle.be, value))); + if (handle.be == BE) { + return UNSAFE.getAndAdd$RawType$( + ba, + address(ba, index(ba, index)), + delta); + } else { + return getAndAddConvEndianWithCAS(ba, index, delta); + } } @ForceInline - static $type$ addAndGet(ArrayHandle handle, Object oba, int index, $type$ value) { - byte[] ba = (byte[]) oba; - return convEndian(handle.be, UNSAFE.getAndAdd$RawType$( - ba, - address(ba, index(ba, index)), - convEndian(handle.be, value))) + value; + static $type$ getAndAddConvEndianWithCAS(byte[] ba, int index, $type$ delta) { + $type$ nativeExpectedValue, expectedValue; + long offset = address(ba, index(ba, index)); + do { + nativeExpectedValue = UNSAFE.get$RawType$Volatile(ba, offset); + expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); + } while (!UNSAFE.weakCompareAndSwap$RawType$Volatile(ba, offset, + nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta))); + return expectedValue; + } + + @ForceInline + static $type$ addAndGet(ArrayHandle handle, Object oba, int index, $type$ delta) { + return getAndAdd(handle, oba, index, delta) + delta; } #end[AtomicAdd] @@ -307,14 +318,14 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { @ForceInline static int index(ByteBuffer bb, int index) { - return Objects.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null); + return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null); } @ForceInline static int indexRO(ByteBuffer bb, int index) { if (UNSAFE.getBoolean(bb, BYTE_BUFFER_IS_READ_ONLY)) throw new ReadOnlyBufferException(); - return Objects.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null); + return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null); } @ForceInline @@ -466,8 +477,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { @ForceInline static boolean weakCompareAndSetVolatile(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) { ByteBuffer bb = (ByteBuffer) obb; - // TODO defer to strong form until new Unsafe method is added - return UNSAFE.compareAndSwap$RawType$( + return UNSAFE.weakCompareAndSwap$RawType$Volatile( UNSAFE.getObject(bb, BYTE_BUFFER_HB), address(bb, indexRO(bb, index)), convEndian(handle.be, expected), convEndian(handle.be, value)); @@ -504,23 +514,34 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { #if[AtomicAdd] @ForceInline - static $type$ getAndAdd(ByteBufferHandle handle, Object obb, int index, $type$ value) { + static $type$ getAndAdd(ByteBufferHandle handle, Object obb, int index, $type$ delta) { ByteBuffer bb = (ByteBuffer) obb; - return convEndian(handle.be, - UNSAFE.getAndAdd$RawType$( - UNSAFE.getObject(bb, BYTE_BUFFER_HB), - address(bb, indexRO(bb, index)), - convEndian(handle.be, value))); + if (handle.be == BE) { + return UNSAFE.getAndAdd$RawType$( + UNSAFE.getObject(bb, BYTE_BUFFER_HB), + address(bb, indexRO(bb, index)), + delta); + } else { + return getAndAddConvEndianWithCAS(bb, index, delta); + } } @ForceInline - static $type$ addAndGet(ByteBufferHandle handle, Object obb, int index, $type$ value) { - ByteBuffer bb = (ByteBuffer) obb; - return convEndian(handle.be, - UNSAFE.getAndAdd$RawType$( - UNSAFE.getObject(bb, BYTE_BUFFER_HB), - address(bb, indexRO(bb, index)), - convEndian(handle.be, value))) + value; + static $type$ getAndAddConvEndianWithCAS(ByteBuffer bb, int index, $type$ delta) { + $type$ nativeExpectedValue, expectedValue; + Object base = UNSAFE.getObject(bb, BYTE_BUFFER_HB); + long offset = address(bb, indexRO(bb, index)); + do { + nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset); + expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); + } while (!UNSAFE.weakCompareAndSwap$RawType$Volatile(base, offset, + nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta))); + return expectedValue; + } + + @ForceInline + static $type$ addAndGet(ByteBufferHandle handle, Object obb, int index, $type$ delta) { + return getAndAdd(handle, obb, index, delta) + delta; } #end[AtomicAdd] diff --git a/jdk/src/java.base/share/classes/java/nio/Buffer.java b/jdk/src/java.base/share/classes/java/nio/Buffer.java index d534fb3ae73..1f6bef17960 100644 --- a/jdk/src/java.base/share/classes/java/nio/Buffer.java +++ b/jdk/src/java.base/share/classes/java/nio/Buffer.java @@ -111,7 +111,7 @@ import java.util.Spliterator; * to zero. * * - *

Clearing, flipping, and rewinding

+ *

Additional operations

* *

In addition to methods for accessing the position, limit, and capacity * values and for marking and resetting, this class also defines the following @@ -131,6 +131,12 @@ import java.util.Spliterator; * it already contains: It leaves the limit unchanged and sets the position * to zero.

* + *
  • {@link #slice} creates a subsequence of a buffer: It leaves the + * limit and the position unchanged.

  • + * + *
  • {@link #duplicate} creates a shallow copy of a buffer: It leaves + * the limit and the position unchanged.

  • + * * * * @@ -567,6 +573,46 @@ public abstract class Buffer { */ public abstract boolean isDirect(); + /** + * Creates a new buffer whose content is a shared subsequence of + * this buffer's content. + * + *

    The content of the new buffer will start at this buffer's current + * position. Changes to this buffer's content will be visible in the new + * buffer, and vice versa; the two buffers' position, limit, and mark + * values will be independent. + * + *

    The new buffer's position will be zero, its capacity and its limit + * will be the number of elements remaining in this buffer, its mark will be + * undefined. The new buffer will be direct if, and only if, this buffer is + * direct, and it will be read-only if, and only if, this buffer is + * read-only.

    + * + * @return The new buffer + * + * @since 9 + */ + public abstract Buffer slice(); + + /** + * Creates a new buffer that shares this buffer's content. + * + *

    The content of the new buffer will be that of this buffer. Changes + * to this buffer's content will be visible in the new buffer, and vice + * versa; the two buffers' position, limit, and mark values will be + * independent. + * + *

    The new buffer's capacity, limit, position and mark values will be + * identical to those of this buffer. The new buffer will be direct if, and + * only if, this buffer is direct, and it will be read-only if, and only if, + * this buffer is read-only.

    + * + * @return The new buffer + * + * @since 9 + */ + public abstract Buffer duplicate(); + // -- Package-private methods for bounds checking, etc. -- diff --git a/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template b/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template index 104f504b551..1292ca458c6 100644 --- a/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -70,8 +70,7 @@ import java.util.stream.$Streamtype$Stream; * #end[byte] * - *
  • Methods for {@link #compact compacting}, {@link - * #duplicate duplicating}, and {@link #slice slicing} + *

  • A method for {@link #compact compacting} * $a$ $type$ buffer.

  • * * @@ -535,6 +534,7 @@ public abstract class $Type$Buffer * @see #alignedSlice(int) #end[byte] */ + @Override public abstract $Type$Buffer slice(); /** @@ -557,6 +557,7 @@ public abstract class $Type$Buffer * * @return The new $type$ buffer */ + @Override public abstract $Type$Buffer duplicate(); /** diff --git a/jdk/src/java.base/share/classes/java/text/MessageFormat.java b/jdk/src/java.base/share/classes/java/text/MessageFormat.java index f907f4f9bb7..134f84661af 100644 --- a/jdk/src/java.base/share/classes/java/text/MessageFormat.java +++ b/jdk/src/java.base/share/classes/java/text/MessageFormat.java @@ -1068,7 +1068,7 @@ public class MessageFormat extends Format { * index information as described above. * @return An Object array parsed from the string. In case of * error, returns null. - * @throws NullPointerException if {@code source} or {@code pos} is null. + * @throws NullPointerException if {@code pos} is null. */ public Object parseObject(String source, ParsePosition pos) { return parse(source, pos); diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 9810a088b48..ec5fd9c8086 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -308,6 +308,7 @@ import java.util.Set; * N nano-of-day number 1234000000 * * V time-zone ID zone-id America/Los_Angeles; Z; -08:30 + * v generic time-zone name zone-name Pacific Time; PT * z time-zone name zone-name Pacific Standard Time; PST * O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00 * X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15 @@ -365,9 +366,17 @@ import java.util.Set; * letters throws {@code IllegalArgumentException}. *

    * Zone names: This outputs the display name of the time-zone ID. If the - * count of letters is one, two or three, then the short name is output. If the - * count of letters is four, then the full name is output. Five or more letters - * throws {@code IllegalArgumentException}. + * pattern letter is 'z' the output is the daylight savings aware zone name. + * If there is insufficient information to determine whether DST applies, + * the name ignoring daylight savings time will be used. + * If the count of letters is one, two or three, then the short name is output. + * If the count of letters is four, then the full name is output. + * Five or more letters throws {@code IllegalArgumentException}. + *

    + * If the pattern letter is 'v' the output provides the zone name ignoring + * daylight savings time. If the count of letters is one, then the short name is output. + * If the count of letters is four, then the full name is output. + * Two, three and five or more letters throw {@code IllegalArgumentException}. *

    * Offset X and x: This formats the offset based on the number of pattern * letters. One letter outputs just the hour, such as '+01', unless the minute 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 17364aef1e4..f3437950fc8 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 @@ -81,9 +81,11 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoChronology; @@ -1157,10 +1159,11 @@ public final class DateTimeFormatterBuilder { * result of {@link ZoneOffset#getId()}. * If the zone is not an offset, the textual name will be looked up * for the locale set in the {@link DateTimeFormatter}. - * If the temporal object being printed represents an instant, then the text - * will be the summer or winter time text as appropriate. + * If the temporal object being printed represents an instant, or if it is a + * local date-time that is not in a daylight saving gap or overlap then + * the text will be the summer or winter time text as appropriate. * If the lookup for text does not find any suitable result, then the - * {@link ZoneId#getId() ID} will be printed instead. + * {@link ZoneId#getId() ID} will be printed. * If the zone cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

    @@ -1177,7 +1180,7 @@ public final class DateTimeFormatterBuilder { * @return this, for chaining, not null */ public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle) { - appendInternal(new ZoneTextPrinterParser(textStyle, null)); + appendInternal(new ZoneTextPrinterParser(textStyle, null, false)); return this; } @@ -1193,10 +1196,11 @@ public final class DateTimeFormatterBuilder { * result of {@link ZoneOffset#getId()}. * If the zone is not an offset, the textual name will be looked up * for the locale set in the {@link DateTimeFormatter}. - * If the temporal object being printed represents an instant, then the text + * If the temporal object being printed represents an instant, or if it is a + * local date-time that is not in a daylight saving gap or overlap, then the text * will be the summer or winter time text as appropriate. * If the lookup for text does not find any suitable result, then the - * {@link ZoneId#getId() ID} will be printed instead. + * {@link ZoneId#getId() ID} will be printed. * If the zone cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

    @@ -1220,7 +1224,70 @@ public final class DateTimeFormatterBuilder { public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle, Set preferredZones) { Objects.requireNonNull(preferredZones, "preferredZones"); - appendInternal(new ZoneTextPrinterParser(textStyle, preferredZones)); + appendInternal(new ZoneTextPrinterParser(textStyle, preferredZones, false)); + return this; + } + //---------------------------------------------------------------------- + /** + * Appends the generic time-zone name, such as 'Pacific Time', to the formatter. + *

    + * This appends an instruction to format/parse the generic textual + * name of the zone to the builder. The generic name is the same throughout the whole + * year, ignoring any daylight saving changes. For example, 'Pacific Time' is the + * generic name, whereas 'Pacific Standard Time' and 'Pacific Daylight Time' are the + * specific names, see {@link #appendZoneText(TextStyle)}. + *

    + * During formatting, the zone is obtained using a mechanism equivalent + * to querying the temporal with {@link TemporalQueries#zoneId()}. + * If the zone is a {@code ZoneOffset} it will be printed using the + * result of {@link ZoneOffset#getId()}. + * If the zone is not an offset, the textual name will be looked up + * for the locale set in the {@link DateTimeFormatter}. + * If the lookup for text does not find any suitable result, then the + * {@link ZoneId#getId() ID} will be printed. + * If the zone cannot be obtained then an exception is thrown unless the + * section of the formatter is optional. + *

    + * During parsing, either the textual zone name, the zone ID or the offset + * is accepted. Many textual zone names are not unique, such as CST can be + * for both "Central Standard Time" and "China Standard Time". In this + * situation, the zone id will be determined by the region information from + * formatter's {@link DateTimeFormatter#getLocale() locale} and the standard + * zone id for that area, for example, America/New_York for the America Eastern zone. + * The {@link #appendGenericZoneText(TextStyle, Set)} may be used + * to specify a set of preferred {@link ZoneId} in this situation. + * + * @param textStyle the text style to use, not null + * @return this, for chaining, not null + */ + public DateTimeFormatterBuilder appendGenericZoneText(TextStyle textStyle) { + appendInternal(new ZoneTextPrinterParser(textStyle, null, true)); + return this; + } + + /** + * Appends the generic time-zone name, such as 'Pacific Time', to the formatter. + *

    + * This appends an instruction to format/parse the generic textual + * name of the zone to the builder. The generic name is the same throughout the whole + * year, ignoring any daylight saving changes. For example, 'Pacific Time' is the + * generic name, whereas 'Pacific Standard Time' and 'Pacific Daylight Time' are the + * specific names, see {@link #appendZoneText(TextStyle)}. + *

    + * This method also allows a set of preferred {@link ZoneId} to be + * specified for parsing. The matched preferred zone id will be used if the + * textural zone name being parsed is not unique. + *

    + * See {@link #appendGenericZoneText(TextStyle)} for details about + * formatting and parsing. + * + * @param textStyle the text style to use, not null + * @param preferredZones the set of preferred zone ids, not null + * @return this, for chaining, not null + */ + public DateTimeFormatterBuilder appendGenericZoneText(TextStyle textStyle, + Set preferredZones) { + appendInternal(new ZoneTextPrinterParser(textStyle, preferredZones, true)); return this; } @@ -1416,6 +1483,7 @@ public final class DateTimeFormatterBuilder { * N nano-of-day number 1234000000 * * V time-zone ID zone-id America/Los_Angeles; Z; -08:30 + * v generic time-zone name zone-name PT, Pacific Time * z time-zone name zone-name Pacific Standard Time; PST * O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00; * X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15 @@ -1537,6 +1605,8 @@ public final class DateTimeFormatterBuilder { * Pattern Count Equivalent builder methods * ------- ----- -------------------------- * VV 2 appendZoneId() + * v 1 appendGenericZoneText(TextStyle.SHORT) + * vvvv 4 appendGenericZoneText(TextStyle.FULL) * z 1 appendZoneText(TextStyle.SHORT) * zz 2 appendZoneText(TextStyle.SHORT) * zzz 3 appendZoneText(TextStyle.SHORT) @@ -1643,6 +1713,14 @@ public final class DateTimeFormatterBuilder { throw new IllegalArgumentException("Pattern letter count must be 2: " + cur); } appendZoneId(); + } else if (cur == 'v') { + if (count == 1) { + appendGenericZoneText(TextStyle.SHORT); + } else if (count == 4) { + appendGenericZoneText(TextStyle.FULL); + } else { + throw new IllegalArgumentException("Wrong number of pattern letters: " + cur); + } } else if (cur == 'Z') { if (count < 4) { appendOffset("+HHMM", "+0000"); @@ -1894,6 +1972,8 @@ public final class DateTimeFormatterBuilder { // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4 // 310 - Z - matches SimpleDateFormat and LDML // 310 - V - time-zone id, matches LDML + // 310 - v - general timezone names, not matching exactly with LDML because LDML specify to fall back + // to 'VVVV' if general-nonlocation unavailable but here it's not falling back because of lack of data // 310 - p - prefix for padding // 310 - X - matches LDML, almost matches SDF for 1, exact match 2&3, extended 4&5 // 310 - x - matches LDML @@ -1901,7 +1981,6 @@ public final class DateTimeFormatterBuilder { // LDML - U - cycle year name, not supported by 310 yet // LDML - l - deprecated // LDML - j - not relevant - // LDML - v,V - extended time-zone names } //----------------------------------------------------------------------- @@ -3723,9 +3802,12 @@ public final class DateTimeFormatterBuilder { /** The preferred zoneid map */ private Set preferredZones; - ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones) { + /** Display in generic time-zone format. True in case of pattern letter 'v' */ + private final boolean isGeneric; + ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones, boolean isGeneric) { super(TemporalQueries.zone(), "ZoneText(" + textStyle + ")"); this.textStyle = Objects.requireNonNull(textStyle, "textStyle"); + this.isGeneric = isGeneric; if (preferredZones != null && preferredZones.size() != 0) { this.preferredZones = new HashSet<>(); for (ZoneId id : preferredZones) { @@ -3788,11 +3870,21 @@ public final class DateTimeFormatterBuilder { String zname = zone.getId(); if (!(zone instanceof ZoneOffset)) { TemporalAccessor dt = context.getTemporal(); - String name = getDisplayName(zname, - dt.isSupported(ChronoField.INSTANT_SECONDS) - ? (zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD) - : GENERIC, - context.getLocale()); + int type = GENERIC; + if (!isGeneric) { + if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { + type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD; + } else if (dt.isSupported(ChronoField.EPOCH_DAY) && + dt.isSupported(ChronoField.NANO_OF_DAY)) { + LocalDate date = LocalDate.ofEpochDay(dt.getLong(ChronoField.EPOCH_DAY)); + LocalTime time = LocalTime.ofNanoOfDay(dt.getLong(ChronoField.NANO_OF_DAY)); + LocalDateTime ldt = date.atTime(time); + if (zone.getRules().getTransition(ldt) == null) { + type = zone.getRules().isDaylightSavings(ldt.atZone(zone).toInstant()) ? DST : STD; + } + } + } + String name = getDisplayName(zname, type, context.getLocale()); if (name != null) { zname = name; } diff --git a/jdk/src/java.base/share/classes/java/time/zone/ZoneRules.java b/jdk/src/java.base/share/classes/java/time/zone/ZoneRules.java index 47190984db1..f6154857b8d 100644 --- a/jdk/src/java.base/share/classes/java/time/zone/ZoneRules.java +++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneRules.java @@ -614,7 +614,7 @@ public final class ZoneRules implements Serializable { * One technique, using this method, would be: *

          *  ZoneOffsetTransition trans = rules.getTransition(localDT);
    -     *  if (trans == null) {
    +     *  if (trans != null) {
          *    // Gap or Overlap: determine what to do from transition
          *  } else {
          *    // Normal case: only one valid offset
    diff --git a/jdk/src/java.base/share/classes/java/util/DualPivotQuicksort.java b/jdk/src/java.base/share/classes/java/util/DualPivotQuicksort.java
    index fbc0359ed37..97a48ae301c 100644
    --- a/jdk/src/java.base/share/classes/java/util/DualPivotQuicksort.java
    +++ b/jdk/src/java.base/share/classes/java/util/DualPivotQuicksort.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2009, 2015, 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
    @@ -146,12 +146,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    @@ -598,12 +612,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    @@ -1086,12 +1114,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    @@ -1574,12 +1616,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    @@ -2158,12 +2214,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    @@ -2701,12 +2771,26 @@ final class DualPivotQuicksort {
                 }
             }
     
    -        // Check special cases
    -        // Implementation note: variable "right" is increased by 1.
    -        if (run[count] == right++) { // The last run contains one element
    -            run[++count] = right;
    -        } else if (count <= 1) { // The array is already sorted
    +        // These invariants should hold true:
    +        //    run[0] = 0
    +        //    run[] = right + 1; (terminator)
    +
    +        if (count == 0) {
    +            // A single equal run
                 return;
    +        } else if (count == 1 && run[count] > right) {
    +            // Either a single ascending or a transformed descending run.
    +            // Always check that a final run is a proper terminator, otherwise
    +            // we have an unterminated trailing run, to handle downstream.
    +            return;
    +        }
    +        right++;
    +        if (run[count] < right) {
    +            // Corner case: the final run is not a terminator. This may happen
    +            // if a final run is an equals run, or there is a single-element run
    +            // at the end. Fix up by adding a proper terminator at the end.
    +            // Note that we terminate with (right + 1), incremented earlier.
    +            run[++count] = right;
             }
     
             // Determine alternation base for merge
    diff --git a/jdk/src/java.base/share/classes/java/util/Objects.java b/jdk/src/java.base/share/classes/java/util/Objects.java
    index 28b39d08969..dad583b9206 100644
    --- a/jdk/src/java.base/share/classes/java/util/Objects.java
    +++ b/jdk/src/java.base/share/classes/java/util/Objects.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2009, 2015, 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
    @@ -25,10 +25,9 @@
     
     package java.util;
     
    -import jdk.internal.HotSpotIntrinsicCandidate;
    +import jdk.internal.util.Preconditions;
    +import jdk.internal.vm.annotation.ForceInline;
     
    -import java.util.function.BiFunction;
    -import java.util.function.Function;
     import java.util.function.Supplier;
     
     /**
    @@ -348,172 +347,6 @@ public final class Objects {
             return obj;
         }
     
    -    /**
    -     * Maps out-of-bounds values to a runtime exception.
    -     *
    -     * @param checkKind the kind of bounds check, whose name may correspond
    -     *        to the name of one of the range check methods, checkIndex,
    -     *        checkFromToIndex, checkFromIndexSize
    -     * @param args the out-of-bounds arguments that failed the range check.
    -     *        If the checkKind corresponds a the name of a range check method
    -     *        then the bounds arguments are those that can be passed in order
    -     *        to the method.
    -     * @param oobef the exception formatter that when applied with a checkKind
    -     *        and a list out-of-bounds arguments returns a runtime exception.
    -     *        If {@code null} then, it is as if an exception formatter was
    -     *        supplied that returns {@link IndexOutOfBoundsException} for any
    -     *        given arguments.
    -     * @return the runtime exception
    -     */
    -    private static RuntimeException outOfBounds(
    -            BiFunction, ? extends RuntimeException> oobef,
    -            String checkKind,
    -            Integer... args) {
    -        List largs = List.of(args);
    -        RuntimeException e = oobef == null
    -                             ? null : oobef.apply(checkKind, largs);
    -        return e == null
    -               ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e;
    -    }
    -
    -    // Specific out-of-bounds exception producing methods that avoid
    -    // the varargs-based code in the critical methods there by reducing their
    -    // the byte code size, and therefore less likely to peturb inlining
    -
    -    private static RuntimeException outOfBoundsCheckIndex(
    -            BiFunction, ? extends RuntimeException> oobe,
    -            int index, int length) {
    -        return outOfBounds(oobe, "checkIndex", index, length);
    -    }
    -
    -    private static RuntimeException outOfBoundsCheckFromToIndex(
    -            BiFunction, ? extends RuntimeException> oobe,
    -            int fromIndex, int toIndex, int length) {
    -        return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
    -    }
    -
    -    private static RuntimeException outOfBoundsCheckFromIndexSize(
    -            BiFunction, ? extends RuntimeException> oobe,
    -            int fromIndex, int size, int length) {
    -        return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
    -    }
    -
    -    /**
    -     * Returns an out-of-bounds exception formatter from an given exception
    -     * factory.  The exception formatter is a function that formats an
    -     * out-of-bounds message from its arguments and applies that message to the
    -     * given exception factory to produce and relay an exception.
    -     *
    -     * 

    The exception formatter accepts two arguments: a {@code String} - * describing the out-of-bounds range check that failed, referred to as the - * check kind; and a {@code List} containing the - * out-of-bound integer values that failed the check. The list of - * out-of-bound values is not modified. - * - *

    Three check kinds are supported {@code checkIndex}, - * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding - * respectively to the specified application of an exception formatter as an - * argument to the out-of-bounds range check methods - * {@link #checkIndex(int, int, BiFunction) checkIndex}, - * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and - * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. - * Thus a supported check kind corresponds to a method name and the - * out-of-bound integer values correspond to method argument values, in - * order, preceding the exception formatter argument (similar in many - * respects to the form of arguments required for a reflective invocation of - * such a range check method). - * - *

    Formatter arguments conforming to such supported check kinds will - * produce specific exception messages describing failed out-of-bounds - * checks. Otherwise, more generic exception messages will be produced in - * any of the following cases: the check kind is supported but fewer - * or more out-of-bounds values are supplied, the check kind is not - * supported, the check kind is {@code null}, or the list of out-of-bound - * values is {@code null}. - * - * @apiNote - * This method produces an out-of-bounds exception formatter that can be - * passed as an argument to any of the supported out-of-bounds range check - * methods declared by {@code Objects}. For example, a formatter producing - * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a - * {@code static final} field as follows: - *

    {@code
    -     * static final
    -     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
    -     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
    -     * }
    - * The formatter instance {@code AIOOBEF} may be passed as an argument to an - * out-of-bounds range check method, such as checking if an {@code index} - * is within the bounds of a {@code limit}: - *
    {@code
    -     * checkIndex(index, limit, AIOOBEF);
    -     * }
    - * If the bounds check fails then the range check method will throw an - * {@code ArrayIndexOutOfBoundsException} with an appropriate exception - * message that is a produced from {@code AIOOBEF} as follows: - *
    {@code
    -     * AIOOBEF.apply("checkIndex", List.of(index, limit));
    -     * }
    - * - * @param f the exception factory, that produces an exception from a message - * where the message is produced and formatted by the returned - * exception formatter. If this factory is stateless and side-effect - * free then so is the returned formatter. - * Exceptions thrown by the factory are relayed to the caller - * of the returned formatter. - * @param the type of runtime exception to be returned by the given - * exception factory and relayed by the exception formatter - * @return the out-of-bounds exception formatter - */ - public static - BiFunction, X> outOfBoundsExceptionFormatter(Function f) { - // Use anonymous class to avoid bootstrap issues if this method is - // used early in startup - return new BiFunction, X>() { - @Override - public X apply(String checkKind, List args) { - return f.apply(outOfBoundsMessage(checkKind, args)); - } - }; - } - - private static String outOfBoundsMessage(String checkKind, List args) { - if (checkKind == null && args == null) { - return String.format("Range check failed"); - } else if (checkKind == null) { - return String.format("Range check failed: %s", args); - } else if (args == null) { - return String.format("Range check failed: %s", checkKind); - } - - int argSize = 0; - switch (checkKind) { - case "checkIndex": - argSize = 2; - break; - case "checkFromToIndex": - case "checkFromIndexSize": - argSize = 3; - break; - default: - } - - // Switch to default if fewer or more arguments than required are supplied - switch ((args.size() != argSize) ? "" : checkKind) { - case "checkIndex": - return String.format("Index %d out-of-bounds for length %d", - args.get(0), args.get(1)); - case "checkFromToIndex": - return String.format("Range [%d, %d) out-of-bounds for length %d", - args.get(0), args.get(1), args.get(2)); - case "checkFromIndexSize": - return String.format("Range [%d, %{@code length < 0}, which is implied from the former inequalities * * - *

    This method behaves as if {@link #checkIndex(int, int, BiFunction)} - * was called with same out-of-bounds arguments and an exception formatter - * argument produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may - * be more efficient). - * * @param index the index * @param length the upper-bound (exclusive) of the range * @return {@code index} if it is within bounds of the range * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds * @since 9 */ + @ForceInline public static int checkIndex(int index, int length) { - return checkIndex(index, length, null); - } - - /** - * Checks if the {@code index} is within the bounds of the range from - * {@code 0} (inclusive) to {@code length} (exclusive). - * - *

    The {@code index} is defined to be out-of-bounds if any of the - * following inequalities is true: - *

      - *
    • {@code index < 0}
    • - *
    • {@code index >= length}
    • - *
    • {@code length < 0}, which is implied from the former inequalities
    • - *
    - * - *

    If the {@code index} is out-of-bounds, then a runtime exception is - * thrown that is the result of applying the following arguments to the - * exception formatter: the name of this method, {@code checkIndex}; - * and an unmodifiable list integers whose values are, in order, the - * out-of-bounds arguments {@code index} and {@code length}. - * - * @param the type of runtime exception to throw if the arguments are - * out-of-bounds - * @param index the index - * @param length the upper-bound (exclusive) of the range - * @param oobef the exception formatter that when applied with this - * method name and out-of-bounds arguments returns a runtime - * exception. If {@code null} or returns {@code null} then, it is as - * if an exception formatter produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used - * instead (though it may be more efficient). - * Exceptions thrown by the formatter are relayed to the caller. - * @return {@code index} if it is within bounds of the range - * @throws X if the {@code index} is out-of-bounds and the exception - * formatter is non-{@code null} - * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds - * and the exception formatter is {@code null} - * @since 9 - * - * @implNote - * This method is made intrinsic in optimizing compilers to guide them to - * perform unsigned comparisons of the index and length when it is known the - * length is a non-negative value (such as that of an array length or from - * the upper bound of a loop) - */ - @HotSpotIntrinsicCandidate - public static - int checkIndex(int index, int length, - BiFunction, X> oobef) { - if (index < 0 || index >= length) - throw outOfBoundsCheckIndex(oobef, index, length); - return index; + return Preconditions.checkIndex(index, length, null); } /** @@ -608,12 +385,6 @@ public final class Objects { *

  • {@code length < 0}, which is implied from the former inequalities
  • * * - *

    This method behaves as if {@link #checkFromToIndex(int, int, int, BiFunction)} - * was called with same out-of-bounds arguments and an exception formatter - * argument produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may - * be more efficient). - * * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range @@ -623,54 +394,7 @@ public final class Objects { */ public static int checkFromToIndex(int fromIndex, int toIndex, int length) { - return checkFromToIndex(fromIndex, toIndex, length, null); - } - - /** - * Checks if the sub-range from {@code fromIndex} (inclusive) to - * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} - * (inclusive) to {@code length} (exclusive). - * - *

    The sub-range is defined to be out-of-bounds if any of the following - * inequalities is true: - *

      - *
    • {@code fromIndex < 0}
    • - *
    • {@code fromIndex > toIndex}
    • - *
    • {@code toIndex > length}
    • - *
    • {@code length < 0}, which is implied from the former inequalities
    • - *
    - * - *

    If the sub-range is out-of-bounds, then a runtime exception is - * thrown that is the result of applying the following arguments to the - * exception formatter: the name of this method, {@code checkFromToIndex}; - * and an unmodifiable list integers whose values are, in order, the - * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. - * - * @param the type of runtime exception to throw if the arguments are - * out-of-bounds - * @param fromIndex the lower-bound (inclusive) of the sub-range - * @param toIndex the upper-bound (exclusive) of the sub-range - * @param length the upper-bound (exclusive) the range - * @param oobef the exception formatter that when applied with this - * method name and out-of-bounds arguments returns a runtime - * exception. If {@code null} or returns {@code null} then, it is as - * if an exception formatter produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used - * instead (though it may be more efficient). - * Exceptions thrown by the formatter are relayed to the caller. - * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws X if the sub-range is out-of-bounds and the exception factory - * function is non-{@code null} - * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and - * the exception factory function is {@code null} - * @since 9 - */ - public static - int checkFromToIndex(int fromIndex, int toIndex, int length, - BiFunction, X> oobef) { - if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) - throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); - return fromIndex; + return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null); } /** @@ -687,12 +411,6 @@ public final class Objects { *

  • {@code length < 0}, which is implied from the former inequalities
  • * * - *

    This method behaves as if {@link #checkFromIndexSize(int, int, int, BiFunction)} - * was called with same out-of-bounds arguments and an exception formatter - * argument produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may - * be more efficient). - * * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range @@ -702,54 +420,7 @@ public final class Objects { */ public static int checkFromIndexSize(int fromIndex, int size, int length) { - return checkFromIndexSize(fromIndex, size, length, null); + return Preconditions.checkFromIndexSize(fromIndex, size, length, null); } - /** - * Checks if the sub-range from {@code fromIndex} (inclusive) to - * {@code fromIndex + size} (exclusive) is within the bounds of range from - * {@code 0} (inclusive) to {@code length} (exclusive). - * - *

    The sub-range is defined to be out-of-bounds if any of the following - * inequalities is true: - *

      - *
    • {@code fromIndex < 0}
    • - *
    • {@code size < 0}
    • - *
    • {@code fromIndex + size > length}, taking into account integer overflow
    • - *
    • {@code length < 0}, which is implied from the former inequalities
    • - *
    - * - *

    If the sub-range is out-of-bounds, then a runtime exception is - * thrown that is the result of applying the following arguments to the - * exception formatter: the name of this method, {@code checkFromIndexSize}; - * and an unmodifiable list integers whose values are, in order, the - * out-of-bounds arguments {@code fromIndex}, {@code size}, and - * {@code length}. - * - * @param the type of runtime exception to throw if the arguments are - * out-of-bounds - * @param fromIndex the lower-bound (inclusive) of the sub-interval - * @param size the size of the sub-range - * @param length the upper-bound (exclusive) of the range - * @param oobef the exception formatter that when applied with this - * method name and out-of-bounds arguments returns a runtime - * exception. If {@code null} or returns {@code null} then, it is as - * if an exception formatter produced from an invocation of - * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used - * instead (though it may be more efficient). - * Exceptions thrown by the formatter are relayed to the caller. - * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws X if the sub-range is out-of-bounds and the exception factory - * function is non-{@code null} - * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and - * the exception factory function is {@code null} - * @since 9 - */ - public static - int checkFromIndexSize(int fromIndex, int size, int length, - BiFunction, X> oobef) { - if ((length | fromIndex | size) < 0 || size > length - fromIndex) - throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); - return fromIndex; - } } diff --git a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java index 1cba038d6e5..b97d0cf68c6 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -462,9 +462,13 @@ class ZipFile implements ZipConstants, Closeable { private class ZipEntryIterator implements Enumeration, Iterator { private int i = 0; + private final int entryCount; public ZipEntryIterator() { - ensureOpen(); + synchronized (ZipFile.this) { + ensureOpen(); + this.entryCount = zsrc.total; + } } public boolean hasMoreElements() { @@ -472,10 +476,7 @@ class ZipFile implements ZipConstants, Closeable { } public boolean hasNext() { - synchronized (ZipFile.this) { - ensureOpen(); - return i < zsrc.total; - } + return i < entryCount; } public ZipEntry nextElement() { @@ -485,7 +486,7 @@ class ZipFile implements ZipConstants, Closeable { public ZipEntry next() { synchronized (ZipFile.this) { ensureOpen(); - if (i >= zsrc.total) { + if (!hasNext()) { throw new NoSuchElementException(); } // each "entry" has 3 ints in table entries @@ -526,34 +527,34 @@ class ZipFile implements ZipConstants, Closeable { /* Checks ensureOpen() before invoke this method */ private ZipEntry getZipEntry(String name, int pos) { byte[] cen = zsrc.cen; - ZipEntry e = new ZipEntry(); int nlen = CENNAM(cen, pos); int elen = CENEXT(cen, pos); int clen = CENCOM(cen, pos); - e.flag = CENFLG(cen, pos); // get the flag first - if (name != null) { - e.name = name; - } else { - if (!zc.isUTF8() && (e.flag & EFS) != 0) { - e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen); + int flag = CENFLG(cen, pos); + if (name == null) { + if (!zc.isUTF8() && (flag & EFS) != 0) { + name = zc.toStringUTF8(cen, pos + CENHDR, nlen); } else { - e.name = zc.toString(cen, pos + CENHDR, nlen); + name = zc.toString(cen, pos + CENHDR, nlen); } } + ZipEntry e = new ZipEntry(name); + e.flag = flag; e.xdostime = CENTIM(cen, pos); e.crc = CENCRC(cen, pos); e.size = CENLEN(cen, pos); e.csize = CENSIZ(cen, pos); e.method = CENHOW(cen, pos); if (elen != 0) { - e.setExtra0(Arrays.copyOfRange(cen, pos + CENHDR + nlen, - pos + CENHDR + nlen + elen), true); + int start = pos + CENHDR + nlen; + e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true); } if (clen != 0) { - if (!zc.isUTF8() && (e.flag & EFS) != 0) { - e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen); + int start = pos + CENHDR + nlen + elen; + if (!zc.isUTF8() && (flag & EFS) != 0) { + e.comment = zc.toStringUTF8(cen, start, clen); } else { - e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen); + e.comment = zc.toString(cen, start, clen); } } return e; @@ -817,7 +818,7 @@ class ZipFile implements ZipConstants, Closeable { ); } - /* + /** * Returns an array of strings representing the names of all entries * that begin with "META-INF/" (case ignored). This method is used * in JarFile, via SharedSecrets, as an optimization when looking up @@ -827,14 +828,14 @@ class ZipFile implements ZipConstants, Closeable { private String[] getMetaInfEntryNames() { synchronized (this) { ensureOpen(); - if (zsrc.metanames.size() == 0) { + if (zsrc.metanames == null) { return null; } - String[] names = new String[zsrc.metanames.size()]; + String[] names = new String[zsrc.metanames.length]; byte[] cen = zsrc.cen; for (int i = 0; i < names.length; i++) { - int pos = zsrc.metanames.get(i); - names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos), + int pos = zsrc.metanames[i]; + names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos), StandardCharsets.UTF_8); } return names; @@ -850,7 +851,7 @@ class ZipFile implements ZipConstants, Closeable { private long locpos; // position of first LOC header (usually 0) private byte[] comment; // zip file comment // list of meta entries in META-INF dir - private ArrayList metanames = new ArrayList<>(); + private int[] metanames; private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true) // A Hashmap for all entries. @@ -1159,7 +1160,7 @@ class ZipFile implements ZipConstants, Closeable { int next = -1; // list for all meta entries - metanames = new ArrayList<>(); + ArrayList metanamesList = null; // Iterate through the entries in the central directory int i = 0; @@ -1194,13 +1195,21 @@ class ZipFile implements ZipConstants, Closeable { idx = addEntry(idx, hash, next, pos); // Adds name to metanames. if (isMetaName(cen, pos + CENHDR, nlen)) { - metanames.add(pos); + if (metanamesList == null) + metanamesList = new ArrayList<>(4); + metanamesList.add(pos); } // skip ext and comment pos += (CENHDR + nlen + elen + clen); i++; } total = i; + if (metanamesList != null) { + metanames = new int[metanamesList.size()]; + for (int j = 0, len = metanames.length; j < len; j++) { + metanames[j] = metanamesList.get(j); + } + } if (pos + ENDHDR != cen.length) { zerror("invalid CEN header (bad header size)"); } @@ -1265,30 +1274,23 @@ class ZipFile implements ZipConstants, Closeable { } } - private static byte[] metainf = new byte[] { - 'M', 'E', 'T', 'A', '-', 'I' , 'N', 'F', '/', - }; - - /* - * Returns true if the specified entry's name begins with the string - * "META-INF/" irrespective of case. + /** + * Returns true if the bytes represent a non-directory name + * beginning with "META-INF/", disregarding ASCII case. */ - private static boolean isMetaName(byte[] name, int off, int len) { - if (len < 9 || (name[off] != 'M' && name[off] != 'm')) { // sizeof("META-INF/") - 1 - return false; - } - off++; - for (int i = 1; i < metainf.length; i++) { - byte c = name[off++]; - // Avoid toupper; it's locale-dependent - if (c >= 'a' && c <= 'z') { - c += 'A' - 'a'; - } - if (metainf[i] != c) { - return false; - } - } - return true; + private static boolean isMetaName(byte[] name, int off, int len) { + // Use the "oldest ASCII trick in the book" + return len > 9 // "META-INF/".length() + && name[off + len - 1] != '/' // non-directory + && (name[off++] | 0x20) == 'm' + && (name[off++] | 0x20) == 'e' + && (name[off++] | 0x20) == 't' + && (name[off++] | 0x20) == 'a' + && (name[off++] ) == '-' + && (name[off++] | 0x20) == 'i' + && (name[off++] | 0x20) == 'n' + && (name[off++] | 0x20) == 'f' + && (name[off] ) == '/'; } /* diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java index 7a946099fdf..bc2396f10c3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -68,13 +68,14 @@ public class ClassLoaders { if (s != null && s.length() > 0) bcp = toURLClassPath(s); - // we have a class path if -cp is specified or -m is not specified + // we have a class path if -cp is specified or -m is not specified. + // If neither is specified then default to -cp . URLClassPath ucp = null; String mainMid = System.getProperty("jdk.module.main"); String cp = System.getProperty("java.class.path"); - if (mainMid == null && (cp == null || cp.length() == 0)) - cp = "."; - if (cp != null && cp.length() > 0) + if (mainMid == null && cp == null) + cp = ""; + if (cp != null) ucp = toURLClassPath(cp); @@ -197,7 +198,7 @@ public class ClassLoaders { * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch */ void appendToClassPathForInstrumentation(String path) { - appendToUCP(path, ucp); + addClassPathToUCP(path, ucp); } /** @@ -224,7 +225,7 @@ public class ClassLoaders { */ private static URLClassPath toURLClassPath(String cp) { URLClassPath ucp = new URLClassPath(new URL[0]); - appendToUCP(cp, ucp); + addClassPathToUCP(cp, ucp); return ucp; } @@ -232,20 +233,28 @@ public class ClassLoaders { * Converts the elements in the given class path to file URLs and adds * them to the given URLClassPath. */ - private static void appendToUCP(String cp, URLClassPath ucp) { - String[] elements = cp.split(File.pathSeparator); - if (elements.length == 0) { - // contains path separator(s) only, default to current directory - // to be compatible with long standing behavior - elements = new String[] { "" }; + private static void addClassPathToUCP(String cp, URLClassPath ucp) { + int off = 0; + int next; + while ((next = cp.indexOf(File.pathSeparator, off)) != -1) { + addURLToUCP(cp.substring(off, next), ucp); + off = next + 1; } - for (String s: elements) { - try { - URL url = Paths.get(s).toRealPath().toUri().toURL(); - ucp.addURL(url); - } catch (InvalidPathException | IOException ignore) { - // malformed path string or class path element does not exist - } + + // remaining + addURLToUCP(cp.substring(off), ucp); + } + + /** + * Attempts to convert to the given string to a file URL and adds it + * to the given URLClassPath. + */ + private static void addURLToUCP(String s, URLClassPath ucp) { + try { + URL url = Paths.get(s).toRealPath().toUri().toURL(); + ucp.addURL(url); + } catch (InvalidPathException | IOException ignore) { + // malformed path string or class path element does not exist } } 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 735d1b86143..bc7aaa5a6f3 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 @@ -33,6 +33,7 @@ import jdk.internal.reflect.Reflection; import jdk.internal.misc.VM; import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.vm.annotation.ForceInline; /** @@ -209,46 +210,103 @@ public final class Unsafe { /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native boolean getBoolean(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putBoolean(Object o, long offset, boolean x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native byte getByte(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putByte(Object o, long offset, byte x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native short getShort(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putShort(Object o, long offset, short x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native char getChar(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putChar(Object o, long offset, char x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native long getLong(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putLong(Object o, long offset, long x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native float getFloat(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putFloat(Object o, long offset, float x); + /** @see #getInt(Object, long) */ @HotSpotIntrinsicCandidate public native double getDouble(Object o, long offset); + /** @see #putInt(Object, long, int) */ @HotSpotIntrinsicCandidate public native void putDouble(Object o, long offset, double x); + /** + * Fetches a native pointer from a given memory address. If the address is + * zero, or does not point into a block obtained from {@link + * #allocateMemory}, the results are undefined. + * + *

    If the native pointer is less than 64 bits wide, it is extended as + * an unsigned number to a Java long. The pointer may be indexed by any + * given byte offset, simply by adding that offset (as a simple integer) to + * the long representing the pointer. The number of bytes actually read + * from the target address may be determined by consulting {@link + * #addressSize}. + * + * @see #allocateMemory + * @see #getInt(Object, long) + */ + @ForceInline + public long getAddress(Object o, long offset) { + if (ADDRESS_SIZE == 4) { + return Integer.toUnsignedLong(getInt(o, offset)); + } else { + return getLong(o, offset); + } + } + + /** + * Stores a native pointer into a given memory address. If the address is + * zero, or does not point into a block obtained from {@link + * #allocateMemory}, the results are undefined. + * + *

    The number of bytes actually written at the target address may be + * determined by consulting {@link #addressSize}. + * + * @see #allocateMemory + * @see #putInt(Object, long, int) + */ + @ForceInline + public void putAddress(Object o, long offset, long x) { + if (ADDRESS_SIZE == 4) { + putInt(o, offset, (int)x); + } else { + putLong(o, offset, x); + } + } + // These read VM internal data. /** @@ -287,8 +345,10 @@ public final class Unsafe { * * @see #allocateMemory */ - @HotSpotIntrinsicCandidate - public native byte getByte(long address); + @ForceInline + public byte getByte(long address) { + return getByte(null, address); + } /** * Stores a value into a given memory address. If the address is zero, or @@ -297,75 +357,94 @@ public final class Unsafe { * * @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native void putByte(long address, byte x); + @ForceInline + public void putByte(long address, byte x) { + putByte(null, address, x); + } /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native short getShort(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putShort(long address, short x); - /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native char getChar(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putChar(long address, char x); - /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native int getInt(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putInt(long address, int x); - /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native long getLong(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putLong(long address, long x); - /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native float getFloat(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putFloat(long address, float x); - /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native double getDouble(long address); - /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putDouble(long address, double x); + @ForceInline + public short getShort(long address) { + return getShort(null, address); + } - /** - * Fetches a native pointer from a given memory address. If the address is - * zero, or does not point into a block obtained from {@link - * #allocateMemory}, the results are undefined. - * - *

    If the native pointer is less than 64 bits wide, it is extended as - * an unsigned number to a Java long. The pointer may be indexed by any - * given byte offset, simply by adding that offset (as a simple integer) to - * the long representing the pointer. The number of bytes actually read - * from the target address may be determined by consulting {@link - * #addressSize}. - * - * @see #allocateMemory - */ - @HotSpotIntrinsicCandidate - public native long getAddress(long address); + /** @see #putByte(long, byte) */ + @ForceInline + public void putShort(long address, short x) { + putShort(null, address, x); + } - /** - * Stores a native pointer into a given memory address. If the address is - * zero, or does not point into a block obtained from {@link - * #allocateMemory}, the results are undefined. - * - *

    The number of bytes actually written at the target address may be - * determined by consulting {@link #addressSize}. - * - * @see #getAddress(long) - */ - @HotSpotIntrinsicCandidate - public native void putAddress(long address, long x); + /** @see #getByte(long) */ + @ForceInline + public char getChar(long address) { + return getChar(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putChar(long address, char x) { + putChar(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public int getInt(long address) { + return getInt(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putInt(long address, int x) { + putInt(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public long getLong(long address) { + return getLong(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putLong(long address, long x) { + putLong(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public float getFloat(long address) { + return getFloat(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putFloat(long address, float x) { + putFloat(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public double getDouble(long address) { + return getDouble(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putDouble(long address, double x) { + putDouble(null, address, x); + } + + /** @see #getAddress(Object, long) */ + @ForceInline + public long getAddress(long address) { + return getAddress(null, address); + } + + /** @see #putAddress(Object, long, long) */ + @ForceInline + public void putAddress(long address, long x) { + putAddress(null, address, x); + } @@ -1271,6 +1350,13 @@ public final class Unsafe { return compareAndSwapObject(o, offset, expected, x); } + @HotSpotIntrinsicCandidate + public final boolean weakCompareAndSwapObjectVolatile(Object o, long offset, + Object expected, + Object x) { + return compareAndSwapObject(o, offset, expected, x); + } + /** * Atomically updates Java variable to {@code x} if it is currently * holding {@code expected}. @@ -1325,6 +1411,13 @@ public final class Unsafe { return compareAndSwapInt(o, offset, expected, x); } + @HotSpotIntrinsicCandidate + public final boolean weakCompareAndSwapIntVolatile(Object o, long offset, + int expected, + int x) { + return compareAndSwapInt(o, offset, expected, x); + } + /** * Atomically updates Java variable to {@code x} if it is currently * holding {@code expected}. @@ -1379,6 +1472,13 @@ public final class Unsafe { return compareAndSwapLong(o, offset, expected, x); } + @HotSpotIntrinsicCandidate + public final boolean weakCompareAndSwapLongVolatile(Object o, long offset, + long expected, + long x) { + return compareAndSwapLong(o, offset, expected, x); + } + /** * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java b/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java index e49d17b0830..af8d3253a22 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java @@ -390,10 +390,25 @@ public class VM { private static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; /* - * Returns the first non-null class loader up the execution stack, - * or null if only code from the null class loader is on the stack. + * Returns the first user-defined class loader up the execution stack, + * or the platform class loader if only code from the platform or + * bootstrap class loader is on the stack. */ - public static native ClassLoader latestUserDefinedLoader(); + public static ClassLoader latestUserDefinedLoader() { + ClassLoader loader = latestUserDefinedLoader0(); + return loader != null ? loader : ClassLoader.getPlatformClassLoader(); + } + + /* + * Returns the first user-defined class loader up the execution stack, + * or null if only code from the platform or bootstrap class loader is + * on the stack. VM does not keep a reference of platform loader and so + * it returns null. + * + * This method should be replaced with StackWalker::walk and then we can + * remove the logic in the VM. + */ + private static native ClassLoader latestUserDefinedLoader0(); /** * Returns {@code true} if we are in a set UID program. diff --git a/jdk/src/java.base/share/classes/jdk/internal/util/Preconditions.java b/jdk/src/java.base/share/classes/jdk/internal/util/Preconditions.java new file mode 100644 index 00000000000..cb1b748f620 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/util/Preconditions.java @@ -0,0 +1,346 @@ +/* + * 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.util; + +import jdk.internal.HotSpotIntrinsicCandidate; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Utility methods to check if state or arguments are correct. + * + */ +public class Preconditions { + + /** + * Maps out-of-bounds values to a runtime exception. + * + * @param checkKind the kind of bounds check, whose name may correspond + * to the name of one of the range check methods, checkIndex, + * checkFromToIndex, checkFromIndexSize + * @param args the out-of-bounds arguments that failed the range check. + * If the checkKind corresponds a the name of a range check method + * then the bounds arguments are those that can be passed in order + * to the method. + * @param oobef the exception formatter that when applied with a checkKind + * and a list out-of-bounds arguments returns a runtime exception. + * If {@code null} then, it is as if an exception formatter was + * supplied that returns {@link IndexOutOfBoundsException} for any + * given arguments. + * @return the runtime exception + */ + private static RuntimeException outOfBounds( + BiFunction, ? extends RuntimeException> oobef, + String checkKind, + Integer... args) { + List largs = List.of(args); + RuntimeException e = oobef == null + ? null : oobef.apply(checkKind, largs); + return e == null + ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e; + } + + private static RuntimeException outOfBoundsCheckIndex( + BiFunction, ? extends RuntimeException> oobe, + int index, int length) { + return outOfBounds(oobe, "checkIndex", index, length); + } + + private static RuntimeException outOfBoundsCheckFromToIndex( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int toIndex, int length) { + return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); + } + + private static RuntimeException outOfBoundsCheckFromIndexSize( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int size, int length) { + return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); + } + + /** + * Returns an out-of-bounds exception formatter from an given exception + * factory. The exception formatter is a function that formats an + * out-of-bounds message from its arguments and applies that message to the + * given exception factory to produce and relay an exception. + * + *

    The exception formatter accepts two arguments: a {@code String} + * describing the out-of-bounds range check that failed, referred to as the + * check kind; and a {@code List} containing the + * out-of-bound integer values that failed the check. The list of + * out-of-bound values is not modified. + * + *

    Three check kinds are supported {@code checkIndex}, + * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding + * respectively to the specified application of an exception formatter as an + * argument to the out-of-bounds range check methods + * {@link #checkIndex(int, int, BiFunction) checkIndex}, + * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and + * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. + * Thus a supported check kind corresponds to a method name and the + * out-of-bound integer values correspond to method argument values, in + * order, preceding the exception formatter argument (similar in many + * respects to the form of arguments required for a reflective invocation of + * such a range check method). + * + *

    Formatter arguments conforming to such supported check kinds will + * produce specific exception messages describing failed out-of-bounds + * checks. Otherwise, more generic exception messages will be produced in + * any of the following cases: the check kind is supported but fewer + * or more out-of-bounds values are supplied, the check kind is not + * supported, the check kind is {@code null}, or the list of out-of-bound + * values is {@code null}. + * + * @apiNote + * This method produces an out-of-bounds exception formatter that can be + * passed as an argument to any of the supported out-of-bounds range check + * methods declared by {@code Objects}. For example, a formatter producing + * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a + * {@code static final} field as follows: + *

    {@code
    +     * static final
    +     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
    +     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
    +     * }
    + * The formatter instance {@code AIOOBEF} may be passed as an argument to an + * out-of-bounds range check method, such as checking if an {@code index} + * is within the bounds of a {@code limit}: + *
    {@code
    +     * checkIndex(index, limit, AIOOBEF);
    +     * }
    + * If the bounds check fails then the range check method will throw an + * {@code ArrayIndexOutOfBoundsException} with an appropriate exception + * message that is a produced from {@code AIOOBEF} as follows: + *
    {@code
    +     * AIOOBEF.apply("checkIndex", List.of(index, limit));
    +     * }
    + * + * @param f the exception factory, that produces an exception from a message + * where the message is produced and formatted by the returned + * exception formatter. If this factory is stateless and side-effect + * free then so is the returned formatter. + * Exceptions thrown by the factory are relayed to the caller + * of the returned formatter. + * @param the type of runtime exception to be returned by the given + * exception factory and relayed by the exception formatter + * @return the out-of-bounds exception formatter + */ + public static + BiFunction, X> outOfBoundsExceptionFormatter(Function f) { + // Use anonymous class to avoid bootstrap issues if this method is + // used early in startup + return new BiFunction, X>() { + @Override + public X apply(String checkKind, List args) { + return f.apply(outOfBoundsMessage(checkKind, args)); + } + }; + } + + private static String outOfBoundsMessage(String checkKind, List args) { + if (checkKind == null && args == null) { + return String.format("Range check failed"); + } else if (checkKind == null) { + return String.format("Range check failed: %s", args); + } else if (args == null) { + return String.format("Range check failed: %s", checkKind); + } + + int argSize = 0; + switch (checkKind) { + case "checkIndex": + argSize = 2; + break; + case "checkFromToIndex": + case "checkFromIndexSize": + argSize = 3; + break; + default: + } + + // Switch to default if fewer or more arguments than required are supplied + switch ((args.size() != argSize) ? "" : checkKind) { + case "checkIndex": + return String.format("Index %d out-of-bounds for length %d", + args.get(0), args.get(1)); + case "checkFromToIndex": + return String.format("Range [%d, %d) out-of-bounds for length %d", + args.get(0), args.get(1), args.get(2)); + case "checkFromIndexSize": + return String.format("Range [%d, %The {@code index} is defined to be out-of-bounds if any of the + * following inequalities is true: + *
      + *
    • {@code index < 0}
    • + *
    • {@code index >= length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + *

    If the {@code index} is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code index} and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code index} if it is within bounds of the range + * @throws X if the {@code index} is out-of-bounds and the exception + * formatter is non-{@code null} + * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds + * and the exception formatter is {@code null} + * @since 9 + * + * @implNote + * This method is made intrinsic in optimizing compilers to guide them to + * perform unsigned comparisons of the index and length when it is known the + * length is a non-negative value (such as that of an array length or from + * the upper bound of a loop) + */ + @HotSpotIntrinsicCandidate + public static + int checkIndex(int index, int length, + BiFunction, X> oobef) { + if (index < 0 || index >= length) + throw outOfBoundsCheckIndex(oobef, index, length); + return index; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out-of-bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code fromIndex > toIndex}
    • + *
    • {@code toIndex > length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + *

    If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromToIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length, + BiFunction, X> oobef) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) + throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); + return fromIndex; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out-of-bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code size < 0}
    • + *
    • {@code fromIndex + size > length}, taking into account integer overflow
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + *

    If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromIndexSize}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code size}, and + * {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length, + BiFunction, X> oobef) { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); + return fromIndex; + } +} diff --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties index 6390b9792d4..32aa8ec65b3 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -100,7 +100,6 @@ java.launcher.X.usage=\ \ -Xdiag show additional diagnostic messages\n\ \ -Xdiag:resolver show resolver diagnostic messages\n\ \ -Xnoclassgc disable class garbage collection\n\ -\ -Xincgc enable incremental garbage collection\n\ \ -Xloggc: log GC status to a file with time stamps\n\ \ -Xbatch disable background compilation\n\ \ -Xms set initial Java heap size\n\ diff --git a/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java b/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java index 64f1c9da9fe..ea4b77535b2 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java @@ -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 @@ -441,17 +441,89 @@ final class ByteArrayAccess { (outOfs < 0) || ((out.length - outOfs) < len)) { throw new ArrayIndexOutOfBoundsException(); } - len += outOfs; - while (outOfs < len) { - long i = in[inOfs++]; - out[outOfs++] = (byte)(i >> 56); - out[outOfs++] = (byte)(i >> 48); - out[outOfs++] = (byte)(i >> 40); - out[outOfs++] = (byte)(i >> 32); - out[outOfs++] = (byte)(i >> 24); - out[outOfs++] = (byte)(i >> 16); - out[outOfs++] = (byte)(i >> 8); - out[outOfs++] = (byte)(i ); + if (littleEndianUnaligned) { + outOfs += byteArrayOfs; + len += outOfs; + while (outOfs < len) { + unsafe.putLong(out, (long)outOfs, reverseBytes(in[inOfs++])); + outOfs += 8; + } + } else { + len += outOfs; + while (outOfs < len) { + long i = in[inOfs++]; + out[outOfs++] = (byte)(i >> 56); + out[outOfs++] = (byte)(i >> 48); + out[outOfs++] = (byte)(i >> 40); + out[outOfs++] = (byte)(i >> 32); + out[outOfs++] = (byte)(i >> 24); + out[outOfs++] = (byte)(i >> 16); + out[outOfs++] = (byte)(i >> 8); + out[outOfs++] = (byte)(i ); + } + } + } + + /** + * byte[] to long[] conversion, little endian byte order + */ + static void b2lLittle(byte[] in, int inOfs, long[] out, int outOfs, int len) { + if ((inOfs < 0) || ((in.length - inOfs) < len) || + ((outOfs < 0) || (out.length - outOfs) < len/8)) { + throw new ArrayIndexOutOfBoundsException(); + } + if (littleEndianUnaligned) { + inOfs += byteArrayOfs; + len += inOfs; + while (inOfs < len) { + out[outOfs++] = unsafe.getLong(in, (long)inOfs); + inOfs += 8; + } + } else { + len += inOfs; + while (inOfs < len) { + out[outOfs++] = ((in[inOfs ] & 0xffL) + | ((in[inOfs + 1] & 0xffL) << 8) + | ((in[inOfs + 2] & 0xffL) << 16) + | ((in[inOfs + 3] & 0xffL) << 24) + | ((in[inOfs + 4] & 0xffL) << 32) + | ((in[inOfs + 5] & 0xffL) << 40) + | ((in[inOfs + 6] & 0xffL) << 48) + | ((in[inOfs + 7] & 0xffL) << 56)); + inOfs += 8; + } + } + } + + + /** + * long[] to byte[] conversion, little endian byte order + */ + static void l2bLittle(long[] in, int inOfs, byte[] out, int outOfs, int len) { + if ((inOfs < 0) || ((in.length - inOfs) < len/8) || + (outOfs < 0) || ((out.length - outOfs) < len)) { + throw new ArrayIndexOutOfBoundsException(); + } + if (littleEndianUnaligned) { + outOfs += byteArrayOfs; + len += outOfs; + while (outOfs < len) { + unsafe.putLong(out, (long)outOfs, in[inOfs++]); + outOfs += 8; + } + } else { + len += outOfs; + while (outOfs < len) { + long i = in[inOfs++]; + out[outOfs++] = (byte)(i ); + out[outOfs++] = (byte)(i >> 8); + out[outOfs++] = (byte)(i >> 16); + out[outOfs++] = (byte)(i >> 24); + out[outOfs++] = (byte)(i >> 32); + out[outOfs++] = (byte)(i >> 40); + out[outOfs++] = (byte)(i >> 48); + out[outOfs++] = (byte)(i >> 56); + } } } } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java index 5861b6c7a85..861fa692471 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.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 @@ -259,14 +259,10 @@ public class PolicyFile extends java.security.Policy { private static final Debug debug = Debug.getInstance("policy"); - private static final String NONE = "NONE"; - private static final String P11KEYSTORE = "PKCS11"; - private static final String SELF = "${{self}}"; private static final String X500PRINCIPAL = "javax.security.auth.x500.X500Principal"; private static final String POLICY = "java.security.policy"; - private static final String SECURITY_MANAGER = "java.security.manager"; private static final String POLICY_URL = "policy.url."; private static final String AUTH_POLICY = "java.security.auth.policy"; private static final String AUTH_POLICY_URL = "auth.policy.url."; @@ -287,6 +283,17 @@ public class PolicyFile extends java.security.Policy { private static final Class[] PARAMS1 = { String.class }; private static final Class[] PARAMS2 = { String.class, String.class }; + /** + * When a policy file has a syntax error, the exception code may generate + * another permission check and this can cause the policy file to be parsed + * repeatedly, leading to a StackOverflowError or ClassCircularityError. + * To avoid this, this set is populated with policy files that have been + * previously parsed and have syntax errors, so that they can be + * subsequently ignored. + */ + private static AtomicReference> badPolicyURLs = + new AtomicReference<>(new HashSet<>()); + /** * Initializes the Policy object and reads the default policy * configuration file(s) into the Policy object. @@ -580,6 +587,16 @@ public class PolicyFile extends java.security.Policy { * @param policyFile the policy Reader object. */ private boolean init(URL policy, PolicyInfo newInfo) { + + // skip parsing policy file if it has been previously parsed and + // has syntax errors + if (badPolicyURLs.get().contains(policy)) { + if (debug != null) { + debug.println("skipping bad policy file: " + policy); + } + return false; + } + boolean success = false; PolicyParser pp = new PolicyParser(expandProperties); InputStreamReader isr = null; @@ -622,13 +639,18 @@ public class PolicyFile extends java.security.Policy { addGrantEntry(ge, keyStore, newInfo); } } catch (PolicyParser.ParsingException pe) { + // record bad policy file to avoid later reparsing it + badPolicyURLs.updateAndGet(k -> { + k.add(policy); + return k; + }); MessageFormat form = new MessageFormat(ResourcesMgr.getString (POLICY + ".error.parsing.policy.message")); Object[] source = {policy, pe.getLocalizedMessage()}; System.err.println(form.format(source)); - if (debug != null) + if (debug != null) { pe.printStackTrace(); - + } } catch (Exception e) { if (debug != null) { debug.println("error parsing "+policy); diff --git a/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java b/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java index ba8ed750254..f8aa620fc77 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.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 @@ -213,7 +213,9 @@ public class PolicyParser { new MessageFormat(ResourcesMgr.getString( "duplicate.keystore.domain.name")); Object[] source = {domainName}; - throw new ParsingException(form.format(source)); + String msg = "duplicate keystore domain name: " + + domainName; + throw new ParsingException(msg, form, source); } } } else { @@ -743,7 +745,8 @@ public class PolicyParser { ResourcesMgr.getString ("expected.expect.read.end.of.file.")); Object[] source = {expect}; - throw new ParsingException(form.format(source)); + String msg = "expected [" + expect + "], read [end of file]"; + throw new ParsingException(msg, form, source); case StreamTokenizer.TT_WORD: if (expect.equalsIgnoreCase(st.sval)) { lookahead = st.nextToken(); @@ -1244,7 +1247,8 @@ public class PolicyParser { MessageFormat form = new MessageFormat(ResourcesMgr.getString( "duplicate.keystore.name")); Object[] source = {keystoreName}; - throw new ParsingException(form.format(source)); + String msg = "duplicate keystore name: " + keystoreName; + throw new ParsingException(msg, form, source); } } @@ -1316,6 +1320,8 @@ public class PolicyParser { private static final long serialVersionUID = -4330692689482574072L; private String i18nMessage; + private MessageFormat form; + private Object[] source; /** * Constructs a ParsingException with the specified @@ -1330,26 +1336,34 @@ public class PolicyParser { i18nMessage = msg; } + public ParsingException(String msg, MessageFormat form, + Object[] source) { + super(msg); + this.form = form; + this.source = source; + } + public ParsingException(int line, String msg) { super("line " + line + ": " + msg); - MessageFormat form = new MessageFormat - (ResourcesMgr.getString("line.number.msg")); - Object[] source = {line, msg}; - i18nMessage = form.format(source); + // don't call form.format unless getLocalizedMessage is called + // to avoid unnecessary permission checks + form = new MessageFormat(ResourcesMgr.getString("line.number.msg")); + source = new Object[] {line, msg}; } public ParsingException(int line, String expect, String actual) { super("line " + line + ": expected [" + expect + "], found [" + actual + "]"); - MessageFormat form = new MessageFormat(ResourcesMgr.getString + // don't call form.format unless getLocalizedMessage is called + // to avoid unnecessary permission checks + form = new MessageFormat(ResourcesMgr.getString ("line.number.expected.expect.found.actual.")); - Object[] source = {line, expect, actual}; - i18nMessage = form.format(source); + source = new Object[] {line, expect, actual}; } @Override public String getLocalizedMessage() { - return i18nMessage; + return i18nMessage != null ? i18nMessage : form.format(source); } } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/SHA3.java b/jdk/src/java.base/share/classes/sun/security/provider/SHA3.java new file mode 100644 index 00000000000..1751c5b9fbb --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.provider; + +import static sun.security.provider.ByteArrayAccess.*; +import java.nio.*; +import java.util.*; +import java.security.*; + +/** + * This class implements the Secure Hash Algorithm SHA-3 developed by + * the National Institute of Standards and Technology along with the + * National Security Agency as defined in FIPS PUB 202. + * + *

    It implements java.security.MessageDigestSpi, and can be used + * through Java Cryptography Architecture (JCA), as a pluggable + * MessageDigest implementation. + * + * @since 9 + * @author Valerie Peng + */ +abstract class SHA3 extends DigestBase { + + private static final int WIDTH = 200; // in bytes, e.g. 1600 bits + private static final int DM = 5; // dimension of lanes + + private static final int NR = 24; // number of rounds + + // precomputed round constants needed by the step mapping Iota + private static final long[] RC_CONSTANTS = { + 0x01L, 0x8082L, 0x800000000000808aL, + 0x8000000080008000L, 0x808bL, 0x80000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x8aL, + 0x88L, 0x80008009L, 0x8000000aL, + 0x8000808bL, 0x800000000000008bL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x800aL, 0x800000008000000aL, 0x8000000080008081L, + 0x8000000000008080L, 0x80000001L, 0x8000000080008008L, + }; + + private byte[] state; + + /** + * Creates a new SHA-3 object. + */ + SHA3(String name, int digestLength) { + super(name, digestLength, (WIDTH - (2 * digestLength))); + implReset(); + } + + /** + * Core compression function. Processes blockSize bytes at a time + * and updates the state of this object. + */ + void implCompress(byte[] b, int ofs) { + for (int i = 0; i < buffer.length; i++) { + state[i] ^= b[ofs++]; + } + state = keccak(state); + } + + /** + * Return the digest. Subclasses do not need to reset() themselves, + * DigestBase calls implReset() when necessary. + */ + void implDigest(byte[] out, int ofs) { + int numOfPadding = + setPaddingBytes(buffer, (int)(bytesProcessed % buffer.length)); + if (numOfPadding < 1) { + throw new ProviderException("Incorrect pad size: " + numOfPadding); + } + for (int i = 0; i < buffer.length; i++) { + state[i] ^= buffer[i]; + } + state = keccak(state); + System.arraycopy(state, 0, out, ofs, engineGetDigestLength()); + } + + /** + * Resets the internal state to start a new hash. + */ + void implReset() { + state = new byte[WIDTH]; + } + + /** + * Utility function for circular shift the specified long + * value to the left for n bits. + */ + private static long circularShiftLeft(long lane, int n) { + return ((lane << n) | (lane >>> (64 - n))); + } + + /** + * Utility function for padding the specified data based on the + * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required + * for SHA-3 hash (section 6.1). + */ + private static int setPaddingBytes(byte[] in, int len) { + if (len != in.length) { + // erase leftover values + Arrays.fill(in, len, in.length, (byte)0); + // directly store the padding bytes into the input + // as the specified buffer is allocated w/ size = rateR + in[len] |= (byte) 0x06; + in[in.length - 1] |= (byte) 0x80; + } + return (in.length - len); + } + + /** + * Utility function for transforming the specified state from + * the byte array format into array of lanes as defined in + * section 3.1.2. + */ + private static long[][] bytes2Lanes(byte[] s) { + if (s.length != WIDTH) { + throw new ProviderException("Error: incorrect input size " + + s.length); + } + // The conversion traverses along x-axis before y-axis. So, y is the + // first dimension and x is the second dimension. + long[][] s2 = new long[DM][DM]; + int sOfs = 0; + for (int y = 0; y < DM; y++, sOfs += 40) { + b2lLittle(s, sOfs, s2[y], 0, 40); + } + return s2; + } + + /** + * Utility function for transforming the specified arrays of + * lanes into a byte array as defined in section 3.1.3. + */ + private static byte[] lanes2Bytes(long[][] m) { + byte[] s = new byte[WIDTH]; + int sOfs = 0; + // The conversion traverses along x-axis before y-axis. So, y is the + // first dimension and x is the second dimension. + for (int y = 0; y < DM; y++, sOfs += 40) { + l2bLittle(m[y], 0, s, sOfs, 40); + } + return s; + } + + /** + * Step mapping Theta as defined in section 3.2.1 . + */ + private static long[][] smTheta(long[][] a) { + long[] c = new long[DM]; + for (int i = 0; i < DM; i++) { + c[i] = a[0][i]^a[1][i]^a[2][i]^a[3][i]^a[4][i]; + } + long[] d = new long[DM]; + for (int i = 0; i < DM; i++) { + long c1 = c[(i + 4) % DM]; + // left shift and wrap the leftmost bit into the rightmost bit + long c2 = circularShiftLeft(c[(i + 1) % DM], 1); + d[i] = c1^c2; + } + for (int y = 0; y < DM; y++) { + for (int x = 0; x < DM; x++) { + a[y][x] ^= d[x]; + } + } + return a; + } + + /** + * Step mapping Rho as defined in section 3.2.2. + */ + private static long[][] smRho(long[][] a) { + long[][] a2 = new long[DM][DM]; + a2[0][0] = a[0][0]; + int xNext, yNext; + for (int t = 0, x = 1, y = 0; t <= 23; t++, x = xNext, y = yNext) { + int numberOfShift = ((t + 1)*(t + 2)/2) % 64; + a2[y][x] = circularShiftLeft(a[y][x], numberOfShift); + xNext = y; + yNext = (2 * x + 3 * y) % DM; + } + return a2; + } + + /** + * Step mapping Pi as defined in section 3.2.3. + */ + private static long[][] smPi(long[][] a) { + long[][] a2 = new long[DM][DM]; + for (int y = 0; y < DM; y++) { + for (int x = 0; x < DM; x++) { + a2[y][x] = a[x][(x + 3 * y) % DM]; + } + } + return a2; + } + + /** + * Step mapping Chi as defined in section 3.2.4. + */ + private static long[][] smChi(long[][] a) { + long[][] a2 = new long[DM][DM]; + for (int y = 0; y < DM; y++) { + for (int x = 0; x < DM; x++) { + a2[y][x] = a[y][x] ^ + ((a[y][(x + 1) % DM] ^ 0xFFFFFFFFFFFFFFFFL) & + a[y][(x + 2) % DM]); + } + } + return a2; + } + + /** + * Step mapping Iota as defined in section 3.2.5. + * + * @return the processed state array + * @param state the state array to be processed + */ + private static long[][] smIota(long[][] a, int rndIndex) { + a[0][0] ^= RC_CONSTANTS[rndIndex]; + return a; + } + + /** + * The function Keccak as defined in section 5.2 with + * rate r = 1600 and capacity c = (digest length x 2). + */ + private static byte[] keccak(byte[] state) { + long[][] lanes = bytes2Lanes(state); + for (int ir = 0; ir < NR; ir++) { + lanes = smIota(smChi(smPi(smRho(smTheta(lanes)))), ir); + } + return lanes2Bytes(lanes); + } + + public Object clone() throws CloneNotSupportedException { + SHA3 copy = (SHA3) super.clone(); + copy.state = copy.state.clone(); + return copy; + } + + /** + * SHA3-224 implementation class. + */ + public static final class SHA224 extends SHA3 { + public SHA224() { + super("SHA3-224", 28); + } + } + + /** + * SHA3-256 implementation class. + */ + public static final class SHA256 extends SHA3 { + public SHA256() { + super("SHA3-256", 32); + } + } + + /** + * SHAs-384 implementation class. + */ + public static final class SHA384 extends SHA3 { + public SHA384() { + super("SHA3-384", 48); + } + } + + /** + * SHA3-512 implementation class. + */ + public static final class SHA512 extends SHA3 { + public SHA512() { + super("SHA3-512", 64); + } + } +} diff --git a/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java b/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java index 0ff50002713..ea090fa6898 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java @@ -211,6 +211,25 @@ final class SunEntries { map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6", "SHA-512/256"); + map.put("MessageDigest.SHA3-224", "sun.security.provider.SHA3$SHA224"); + map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.7", "SHA3-224"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.7", + "SHA3-224"); + + map.put("MessageDigest.SHA3-256", "sun.security.provider.SHA3$SHA256"); + map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.8", "SHA3-256"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.8", + "SHA3-256"); + map.put("MessageDigest.SHA3-384", "sun.security.provider.SHA3$SHA384"); + map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.9", "SHA3-384"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.9", + "SHA3-384"); + map.put("MessageDigest.SHA3-512", "sun.security.provider.SHA3$SHA512"); + map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.10", "SHA3-512"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.10", + "SHA3-512"); + + /* * Algorithm Parameter Generator engines */ diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java index 4a32fdf902e..2a3775da7df 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, 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 @@ -108,7 +108,7 @@ final class HandshakeHash { * a hash for the certificate verify message is required. */ HandshakeHash(boolean needCertificateVerify) { - clonesNeeded = needCertificateVerify ? 3 : 2; + clonesNeeded = needCertificateVerify ? 4 : 3; } void reserve(ByteBuffer input) { diff --git a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 20e66d561fb..0bf5fcbe1fc 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -145,11 +145,10 @@ public class SignatureFileVerifier { */ public static boolean isBlockOrSF(String s) { // we currently only support DSA and RSA PKCS7 blocks - if (s.endsWith(".SF") || s.endsWith(".DSA") || - s.endsWith(".RSA") || s.endsWith(".EC")) { - return true; - } - return false; + return s.endsWith(".SF") + || s.endsWith(".DSA") + || s.endsWith(".RSA") + || s.endsWith(".EC"); } /** diff --git a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java index 60b0b922190..3ff90bf483a 100644 --- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java +++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java @@ -552,58 +552,61 @@ public class AlgorithmId implements Serializable, DerEncoder { return AlgorithmId.sha512WithECDSA_oid; } - // See if any of the installed providers supply a mapping from - // the given algorithm name to an OID string - String oidString; - if (!initOidTable) { - Provider[] provs = Security.getProviders(); - for (int i=0; i enum_ = provs[i].keys(); - enum_.hasMoreElements(); ) { - String alias = (String)enum_.nextElement(); - String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH); - int index; - if (upperCaseAlias.startsWith("ALG.ALIAS") && - (index=upperCaseAlias.indexOf("OID.", 0)) != -1) { - index += "OID.".length(); - if (index == alias.length()) { - // invalid alias entry - break; - } - if (oidTable == null) { - oidTable = new HashMap<>(); - } - oidString = alias.substring(index); - String stdAlgName = provs[i].getProperty(alias); - if (stdAlgName != null) { - stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH); - } - if (stdAlgName != null && - oidTable.get(stdAlgName) == null) { - oidTable.put(stdAlgName, - new ObjectIdentifier(oidString)); - } - } - } - } - - if (oidTable == null) { - oidTable = Collections.emptyMap(); - } - initOidTable = true; - } - - return oidTable.get(name.toUpperCase(Locale.ENGLISH)); + return oidTable().get(name.toUpperCase(Locale.ENGLISH)); } private static ObjectIdentifier oid(int ... values) { return ObjectIdentifier.newInternal(values); } - private static boolean initOidTable = false; - private static Map oidTable; + private static volatile Map oidTable; private static final Map nameTable; + /** Returns the oidTable, lazily initializing it on first access. */ + private static Map oidTable() + throws IOException { + // Double checked locking; safe because oidTable is volatile + Map tab; + if ((tab = oidTable) == null) { + synchronized (AlgorithmId.class) { + if ((tab = oidTable) == null) + oidTable = tab = computeOidTable(); + } + } + return tab; + } + + /** Collects the algorithm names from the installed providers. */ + private static HashMap computeOidTable() + throws IOException { + HashMap tab = new HashMap<>(); + for (Provider provider : Security.getProviders()) { + for (Object key : provider.keySet()) { + String alias = (String)key; + String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH); + int index; + if (upperCaseAlias.startsWith("ALG.ALIAS") && + (index=upperCaseAlias.indexOf("OID.", 0)) != -1) { + index += "OID.".length(); + if (index == alias.length()) { + // invalid alias entry + break; + } + String oidString = alias.substring(index); + String stdAlgName = provider.getProperty(alias); + if (stdAlgName != null) { + stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH); + } + if (stdAlgName != null && + tab.get(stdAlgName) == null) { + tab.put(stdAlgName, new ObjectIdentifier(oidString)); + } + } + } + } + return tab; + } + /*****************************************************************/ /* diff --git a/jdk/src/java.base/share/conf/security/java.policy b/jdk/src/java.base/share/conf/security/java.policy index 0400ebfd546..32d31472394 100644 --- a/jdk/src/java.base/share/conf/security/java.policy +++ b/jdk/src/java.base/share/conf/security/java.policy @@ -80,6 +80,10 @@ grant codeBase "jrt:/jdk.naming.dns" { permission java.security.AllPermission; }; +grant codeBase "jrt:/java.scripting" { + permission java.security.AllPermission; +}; + grant codeBase "jrt:/jdk.scripting.nashorn" { permission java.security.AllPermission; }; diff --git a/jdk/src/java.base/share/native/include/jvmti.h b/jdk/src/java.base/share/native/include/jvmti.h index 684fd2d7046..5f8835c0baa 100644 --- a/jdk/src/java.base/share/native/include/jvmti.h +++ b/jdk/src/java.base/share/native/include/jvmti.h @@ -704,7 +704,8 @@ typedef struct { unsigned int can_generate_resource_exhaustion_heap_events : 1; unsigned int can_generate_resource_exhaustion_threads_events : 1; unsigned int can_generate_early_vmstart : 1; - unsigned int : 6; + unsigned int can_generate_early_class_hook_events : 1; + unsigned int : 5; unsigned int : 16; unsigned int : 16; unsigned int : 16; diff --git a/jdk/src/java.base/share/native/libjava/VM.c b/jdk/src/java.base/share/native/libjava/VM.c index 61bae65f815..53837efc518 100644 --- a/jdk/src/java.base/share/native/libjava/VM.c +++ b/jdk/src/java.base/share/native/libjava/VM.c @@ -36,7 +36,7 @@ static JNINativeMethod methods[] = { }; JNIEXPORT jobject JNICALL -Java_jdk_internal_misc_VM_latestUserDefinedLoader(JNIEnv *env, jclass cls) { +Java_jdk_internal_misc_VM_latestUserDefinedLoader0(JNIEnv *env, jclass cls) { return JVM_LatestUserDefinedLoader(env); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java index b3ff5c311e4..ae0d19c6cde 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java @@ -26,7 +26,6 @@ package java.net.http; import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.LinkedList; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; @@ -557,25 +556,37 @@ public class AsyncSSLDelegate implements Closeable, AsyncConnection { } static void logParams(SSLParameters p) { - if (!Log.ssl()) + if (!Log.ssl()) { return; + } + Log.logSSL("SSLParameters:"); if (p == null) { Log.logSSL("Null params"); return; } - for (String cipher : p.getCipherSuites()) { - Log.logSSL("cipher: {0}\n", cipher); + + if (p.getCipherSuites() != null) { + for (String cipher : p.getCipherSuites()) { + Log.logSSL("cipher: {0}\n", cipher); + } } + + // SSLParameters.getApplicationProtocols() can't return null for (String approto : p.getApplicationProtocols()) { Log.logSSL("application protocol: {0}\n", approto); } - for (String protocol : p.getProtocols()) { - Log.logSSL("protocol: {0}\n", protocol); + + if (p.getProtocols() != null) { + for (String protocol : p.getProtocols()) { + Log.logSSL("protocol: {0}\n", protocol); + } } - if (p.getServerNames() != null) + + if (p.getServerNames() != null) { for (SNIServerName sname : p.getServerNames()) { Log.logSSL("server name: {0}\n", sname.toString()); + } } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java index 446987d6b5d..226cee95c55 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java @@ -35,6 +35,7 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Iterator; @@ -155,6 +156,15 @@ class HttpClientImpl extends HttpClient implements BufferHandler { selmgr.register(exchange); } + /** + * Only used from RawChannel to disconnect the channel from + * the selector + */ + void cancelRegistration(SocketChannel s) { + selmgr.cancel(s); + } + + Http2ClientImpl client2() { return client2; } @@ -220,6 +230,13 @@ class HttpClientImpl extends HttpClient implements BufferHandler { selector.wakeup(); } + synchronized void cancel(SocketChannel e) { + SelectionKey key = e.keyFor(selector); + if (key != null) + key.cancel(); + selector.wakeup(); + } + void wakeupSelector() { selector.wakeup(); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java index 10758d6db99..dcbfbdb8f1a 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java @@ -176,7 +176,7 @@ class HttpResponseImpl extends HttpResponse { * * @return */ - RawChannel rawChannel() { + RawChannel rawChannel() throws IOException { if (rawchan == null) { rawchan = new RawChannel(request.client(), connection); } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java index 991edfefa6c..51e5ce9633e 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java @@ -88,7 +88,7 @@ abstract class Log implements System.Logger { logging |= TRACE; break; case "all": - logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE; + logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE|SSL; break; } if (val.startsWith("frames")) { diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java index e4dc3b00b8d..5f6fb4df6c0 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java @@ -29,6 +29,7 @@ import java.nio.channels.ByteChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; // // Used to implement WebSocket. Each RawChannel corresponds to a TCP connection @@ -56,9 +57,21 @@ final class RawChannel implements ByteChannel, GatheringByteChannel { interface NonBlockingEvent extends RawEvent { } - RawChannel(HttpClientImpl client, HttpConnection connection) { + RawChannel(HttpClientImpl client, HttpConnection connection) + throws IOException { this.client = client; this.connection = connection; + SocketChannel chan = connection.channel(); + client.cancelRegistration(chan); + chan.configureBlocking(false); + } + + SocketChannel socketChannel() { + return connection.channel(); + } + + ByteBuffer getRemaining() { + return connection.getRemaining(); } private class RawAsyncEvent extends AsyncEvent { diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java index cea95c8f2f6..91252c93b88 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java @@ -32,6 +32,9 @@ import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.LongConsumer; @@ -409,13 +412,20 @@ class Stream extends ExchangeImpl { @Override HttpResponseImpl getResponse() throws IOException { try { - return getResponseAsync(null).join(); - } catch (Throwable e) { + if (request.timeval() > 0) { + return getResponseAsync(null).get( + request.timeval(), TimeUnit.MILLISECONDS); + } else { + return getResponseAsync(null).join(); + } + } catch (TimeoutException e) { + throw new HttpTimeoutException("Response timed out"); + } catch (InterruptedException | ExecutionException e) { Throwable t = e.getCause(); if (t instanceof IOException) { throw (IOException)t; } - throw e; + throw new IOException(e); } } diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java b/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java index 6a7ddaa882c..d3cc7da3520 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java @@ -24,6 +24,8 @@ */ package java.net.http; +import java.io.UncheckedIOException; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -126,6 +128,8 @@ final class WSOpeningHandshake { return CompletableFuture.completedFuture(result); } catch (WebSocketHandshakeException e) { return CompletableFuture.failedFuture(e); + } catch (UncheckedIOException ee) { + return CompletableFuture.failedFuture(ee.getCause()); } }); } @@ -149,7 +153,12 @@ final class WSOpeningHandshake { checkAccept(response, h); checkExtensions(response, h); String subprotocol = checkAndReturnSubprotocol(response, h); - RawChannel channel = ((HttpResponseImpl) response).rawChannel(); + RawChannel channel = null; + try { + channel = ((HttpResponseImpl) response).rawChannel(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } return new Result(subprotocol, channel); } diff --git a/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c b/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c index 0c57f8b289d..a74b2b725ba 100644 --- a/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c +++ b/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c @@ -518,18 +518,22 @@ static void splitPathList(const char* str, int* pathCount, char*** paths) { int count = 0; char** segments = NULL; + char** new_segments; char* c = (char*) str; while (*c != '\0') { while (*c == ' ') c++; /* skip leading spaces */ if (*c == '\0') { break; } - if (segments == NULL) { - segments = (char**)malloc( sizeof(char**) ); - } else { - segments = (char**)realloc( segments, (count+1)*sizeof(char**) ); + new_segments = (char**)realloc(segments, (count+1)*sizeof(char*)); + if (new_segments == NULL) { + jplis_assert(0); + free(segments); + count = 0; + segments = NULL; + break; } - jplis_assert(segments != (char**)NULL); + segments = new_segments; segments[count++] = c; c = strchr(c, ' '); if (c == NULL) { 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 bc06286e8da..f429452419e 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 @@ -2506,15 +2506,12 @@ public class LogManager { } } - // Management Support - private static LoggingMXBean loggingMXBean = null; /** * String representation of the * {@link javax.management.ObjectName} for the management interface * for the logging facility. * * @see java.lang.management.PlatformLoggingMXBean - * @see java.util.logging.LoggingMXBean * * @since 1.5 */ @@ -2523,24 +2520,21 @@ public class LogManager { /** * Returns {@code LoggingMXBean} for managing loggers. - * An alternative way to manage loggers is through the - * {@link java.lang.management.PlatformLoggingMXBean} interface - * that can be obtained by calling: - *

    -     *     PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
    -     *         ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class);
    -     * 
    * * @return a {@link LoggingMXBean} object. * + * @deprecated {@code java.util.logging.LoggingMXBean} is deprecated and + * replaced with {@code java.lang.management.PlatformLoggingMXBean}. Use + * {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) + * ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class) + * instead. + * * @see java.lang.management.PlatformLoggingMXBean * @since 1.5 */ + @Deprecated(since="9") public static synchronized LoggingMXBean getLoggingMXBean() { - if (loggingMXBean == null) { - loggingMXBean = new Logging(); - } - return loggingMXBean; + return Logging.getInstance(); } /** diff --git a/jdk/src/java.logging/share/classes/java/util/logging/Logging.java b/jdk/src/java.logging/share/classes/java/util/logging/Logging.java index 70c59503e4e..716e8bc150d 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Logging.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logging.java @@ -44,16 +44,18 @@ import java.util.ArrayList; * @see Logger * @see LogManager */ -class Logging implements LoggingMXBean { +@SuppressWarnings("deprecation") // implements LoggingMXBean +final class Logging implements LoggingMXBean { private static LogManager logManager = LogManager.getLogManager(); /** Constructor of Logging which is the implementation class * of LoggingMXBean. */ - Logging() { + private Logging() { } + @Override public List getLoggerNames() { Enumeration loggers = logManager.getLoggerNames(); ArrayList array = new ArrayList<>(); @@ -65,6 +67,7 @@ class Logging implements LoggingMXBean { } private static String EMPTY_STRING = ""; + @Override public String getLoggerLevel(String loggerName) { Logger l = logManager.getLogger(loggerName); if (l == null) { @@ -79,6 +82,7 @@ class Logging implements LoggingMXBean { } } + @Override public void setLoggerLevel(String loggerName, String levelName) { if (loggerName == null) { throw new NullPointerException("loggerName is null"); @@ -102,6 +106,7 @@ class Logging implements LoggingMXBean { logger.setLevel(level); } + @Override public String getParentLoggerName( String loggerName ) { Logger l = logManager.getLogger( loggerName ); if (l == null) { @@ -116,4 +121,11 @@ class Logging implements LoggingMXBean { return p.getName(); } } + + static Logging getInstance() { + return INSTANCE; + } + + private static final Logging INSTANCE = new Logging(); + } diff --git a/jdk/src/java.logging/share/classes/java/util/logging/LoggingMXBean.java b/jdk/src/java.logging/share/classes/java/util/logging/LoggingMXBean.java index 9d545d8d28d..812eb36622d 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LoggingMXBean.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LoggingMXBean.java @@ -27,30 +27,23 @@ package java.util.logging; /** - * The management interface for the logging facility. It is recommended - * to use the {@link java.lang.management.PlatformLoggingMXBean} management - * interface that implements all attributes defined in this - * {@code LoggingMXBean}. The - * {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) - * ManagementFactory.getPlatformMXBean} method can be used to obtain - * the {@code PlatformLoggingMXBean} object representing the management - * interface for logging. + * The management interface for the logging facility. * - *

    There is a single global instance of the {@code LoggingMXBean}. - * This instance is an {@link javax.management.MXBean MXBean} that - * can be obtained by calling the {@link LogManager#getLoggingMXBean} - * method or from the - * {@linkplain java.lang.management.ManagementFactory#getPlatformMBeanServer + * {@link java.lang.management.PlatformLoggingMXBean + * java.lang.management.PlatformLoggingMXBean} is the management interface + * for logging facility registered in the {@link + * java.lang.management.ManagementFactory#getPlatformMBeanServer() * platform MBeanServer}. - *

    - * The {@link javax.management.ObjectName ObjectName} that uniquely identifies - * the management interface for logging within the {@code MBeanServer} is: - *

    - *    {@link LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging}
    - * 
    - *

    - * The instance registered in the platform {@code MBeanServer} - * is also a {@link java.lang.management.PlatformLoggingMXBean}. + * It is recommended to use the {@code PlatformLoggingMXBean} obtained via + * the {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) + * ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class)} method. + * + * @deprecated {@code LoggingMXBean} is no longer a {@link + * java.lang.management.PlatformManagedObject platform MXBean} and is replaced + * with {@link java.lang.management.PlatformLoggingMXBean}. + * It will not register in the platform {@code MBeanServer}. + * Use {@code ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class)} + * instead. * * @author Ron Mann * @author Mandy Chung @@ -58,6 +51,7 @@ package java.util.logging; * * @see java.lang.management.PlatformLoggingMXBean */ +@Deprecated(since="9") public interface LoggingMXBean { /** diff --git a/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java b/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java index 8d0083ff807..9a6252add85 100644 --- a/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java +++ b/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java @@ -598,9 +598,8 @@ public class ManagementFactory { try { final ObjectName objName = new ObjectName(mxbeanName); - // skip the isInstanceOf check for LoggingMXBean String intfName = mxbeanInterface.getName(); - if (!connection.isInstanceOf(objName, intfName)) { + if (!isInstanceOf(connection, objName, intfName)) { throw new IllegalArgumentException(mxbeanName + " is not an instance of " + mxbeanInterface); } @@ -616,6 +615,33 @@ public class ManagementFactory { } } + // This makes it possible to obtain an instance of LoggingMXBean + // using newPlatformMXBeanProxy(mbs, on, LoggingMXBean.class) + // even though the underlying MXBean no longer implements + // java.util.logging.LoggingMXBean. + // Altough java.util.logging.LoggingMXBean is deprecated, an application + // that uses newPlatformMXBeanProxy(mbs, on, LoggingMXBean.class) will + // continue to work. + // + private static boolean isInstanceOf(MBeanServerConnection connection, + ObjectName objName, String intfName) + throws InstanceNotFoundException, IOException + { + // special case for java.util.logging.LoggingMXBean. + // java.util.logging.LoggingMXBean is deprecated and + // replaced with java.lang.management.PlatformLoggingMXBean, + // so we will consider that any MBean implementing + // java.lang.management.PlatformLoggingMXBean also implements + // java.util.logging.LoggingMXBean. + if ("java.util.logging.LoggingMXBean".equals(intfName)) { + if (connection.isInstanceOf(objName, + PlatformLoggingMXBean.class.getName())) { + return true; + } + } + return connection.isInstanceOf(objName, intfName); + } + /** * Returns the platform MXBean implementing * the given {@code mxbeanInterface} which is specified diff --git a/jdk/src/java.management/share/classes/java/lang/management/PlatformLoggingMXBean.java b/jdk/src/java.management/share/classes/java/lang/management/PlatformLoggingMXBean.java index d18d0b30c40..80595dd75d6 100644 --- a/jdk/src/java.management/share/classes/java/lang/management/PlatformLoggingMXBean.java +++ b/jdk/src/java.management/share/classes/java/lang/management/PlatformLoggingMXBean.java @@ -44,10 +44,6 @@ package java.lang.management; * {@link java.util.logging.LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging} *

    * - *

    The instance registered in the platform {@code MBeanServer} with - * this {@code ObjectName} implements all attributes defined by - * {@link java.util.logging.LoggingMXBean}. - * * @since 1.7 */ public interface PlatformLoggingMXBean extends PlatformManagedObject { diff --git a/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java b/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java index 44682b29971..4eb5742b2ba 100644 --- a/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java +++ b/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java @@ -26,6 +26,8 @@ package sun.management; import java.lang.management.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; @@ -43,9 +45,13 @@ import jdk.internal.misc.SharedSecrets; import java.util.ArrayList; import java.util.List; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Module; +import java.lang.reflect.UndeclaredThrowableException; import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; /** * ManagementFactoryHelper provides static factory methods to create @@ -66,6 +72,7 @@ public class ManagementFactoryHelper { return jvm; } + static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; private static ClassLoadingImpl classMBean = null; private static MemoryImpl memoryMBean = null; private static ThreadImpl threadMBean = null; @@ -145,74 +152,138 @@ public class ManagementFactoryHelper { } public static PlatformLoggingMXBean getPlatformLoggingMXBean() { - if (LoggingMXBeanSupport.isAvailable()) { - return PlatformLoggingImpl.instance; + if (LoggingMXBeanAccess.isAvailable()) { + return PlatformLoggingImpl.MBEAN; } else { return null; } } public static boolean isPlatformLoggingMXBeanAvailable() { - return LoggingMXBeanSupport.isAvailable(); + return LoggingMXBeanAccess.isAvailable(); } - /** - * The logging MXBean object is an instance of - * PlatformLoggingMXBean and java.util.logging.LoggingMXBean - * but it can't directly implement two MXBean interfaces - * as a compliant MXBean implements exactly one MXBean interface, - * or if it implements one interface that is a subinterface of - * all the others; otherwise, it is a non-compliant MXBean - * and MBeanServer will throw NotCompliantMBeanException. - * See the Definition of an MXBean section in javax.management.MXBean spec. - * - * To create a compliant logging MXBean, define a LoggingMXBean interface - * that extend PlatformLoggingMXBean and j.u.l.LoggingMXBean - */ - public interface LoggingMXBean - extends PlatformLoggingMXBean, java.util.logging.LoggingMXBean { - } - - // This is a trick: if java.util.logging is not present then - // attempting to access something that implements - // java.util.logging.LoggingMXBean will trigger a CNFE. - // So we cannot directly call any static method or access any static field - // on PlatformLoggingImpl, as we would risk raising a CNFE. - // Instead we use this intermediate LoggingMXBeanSupport class to determine + // The LoggingMXBeanAccess class uses reflection to determine // whether java.util.logging is present, and load the actual LoggingMXBean // implementation. // - static final class LoggingMXBeanSupport { - final static Object loggingImpl = - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - try { - // create a LoggingProxyImpl instance when - // java.util.logging classes exist - Class c = Class.forName("java.util.logging.Logging", true, null); - Constructor cons = c.getDeclaredConstructor(); - cons.setAccessible(true); - return cons.newInstance(); - } catch (ClassNotFoundException cnf) { - return null; - } catch (NoSuchMethodException | InstantiationException - | IllegalAccessException | InvocationTargetException e) { - throw new AssertionError(e); - } - }}); + static final class LoggingMXBeanAccess { + + final static String LOG_MANAGER_CLASS_NAME = "java.util.logging.LogManager"; + final static String LOGGING_MXBEAN_CLASS_NAME = "java.util.logging.LoggingMXBean"; + final static Class LOG_MANAGER_CLASS = loadLoggingClass(LOG_MANAGER_CLASS_NAME); static boolean isAvailable() { - return loggingImpl != null; + return LOG_MANAGER_CLASS != null; } + + private static Class loadLoggingClass(String className) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public Class run() { + Optional logging = java.lang.reflect.Layer.boot() + .findModule("java.logging"); + if (logging.isPresent()) { + return Class.forName(logging.get(), className); + } + return null; + } + }); + } + + private Map initMethodMap(Object impl) { + if (impl == null) { + return Collections.emptyMap(); + } + Class intfClass = loadLoggingClass(LOGGING_MXBEAN_CLASS_NAME); + final Map methodsMap = new HashMap<>(); + for (Method m : intfClass.getMethods()) { + try { + // Sanity checking: all public methods present in + // java.util.logging.LoggingMXBean should + // also be in PlatformLoggingMXBean + Method specMethod = PlatformLoggingMXBean.class + .getMethod(m.getName(), m.getParameterTypes()); + if (specMethod.getReturnType().isAssignableFrom(m.getReturnType())) { + if (methodsMap.putIfAbsent(m.getName(), m) != null) { + throw new RuntimeException("unexpected polymorphic method: " + + m.getName()); + } + } + } catch (NoSuchMethodException x) { + // All methods in java.util.logging.LoggingMXBean should + // also be in PlatformLoggingMXBean + throw new InternalError(x); + } + } + return Collections.unmodifiableMap(methodsMap); + } + + private static Object getMXBeanImplementation() { + if (!isAvailable()) { + // should not happen + throw new NoClassDefFoundError(LOG_MANAGER_CLASS_NAME); + } + try { + final Method m = LOG_MANAGER_CLASS.getMethod("getLoggingMXBean"); + return m.invoke(null); + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException x) { + throw new ExceptionInInitializerError(x); + } + } + + // The implementation object, which will be invoked through + // reflection. The implementation does not need to implement + // PlatformLoggingMXBean, but must declare the same methods + // with same signatures, and they must be public, with one + // exception: + // getObjectName will not be called on the implementation object, + // so the implementation object does not need to declare such + // a method. + final Object impl = getMXBeanImplementation(); + final Map methods = initMethodMap(impl); + + LoggingMXBeanAccess() { + } + + T invoke(String methodName, Object... args) { + Method m = methods.get(methodName); + if (m == null) { + throw new UnsupportedOperationException(methodName); + } + try { + @SuppressWarnings("unchecked") + T result = (T) m.invoke(impl, args); + return result; + } catch (IllegalAccessException ex) { + throw new UnsupportedOperationException(ex); + } catch (InvocationTargetException ex) { + throw unwrap(ex); + } + } + + private static RuntimeException unwrap(InvocationTargetException x) { + Throwable t = x.getCause(); + if (t instanceof RuntimeException) { + return (RuntimeException)t; + } + if (t instanceof Error) { + throw (Error)t; + } + return new UndeclaredThrowableException(t == null ? x : t); + } + + } - static class PlatformLoggingImpl implements LoggingMXBean - { - final static java.util.logging.LoggingMXBean impl = - (java.util.logging.LoggingMXBean) LoggingMXBeanSupport.loggingImpl; - final static PlatformLoggingMXBean instance = new PlatformLoggingImpl(); - final static String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; + static final class PlatformLoggingImpl implements PlatformLoggingMXBean { + + private final LoggingMXBeanAccess loggingAccess; + private PlatformLoggingImpl(LoggingMXBeanAccess loggingAccess) { + this.loggingAccess = loggingAccess; + } private volatile ObjectName objname; // created lazily @Override @@ -232,23 +303,29 @@ public class ManagementFactoryHelper { @Override public java.util.List getLoggerNames() { - return impl.getLoggerNames(); + return loggingAccess.invoke("getLoggerNames"); } @Override public String getLoggerLevel(String loggerName) { - return impl.getLoggerLevel(loggerName); + return loggingAccess.invoke("getLoggerLevel", loggerName); } @Override public void setLoggerLevel(String loggerName, String levelName) { - impl.setLoggerLevel(loggerName, levelName); + loggingAccess.invoke("setLoggerLevel", loggerName, levelName); } @Override public String getParentLoggerName(String loggerName) { - return impl.getParentLoggerName(loggerName); + return loggingAccess.invoke("getParentLoggerName", loggerName); } + + private static PlatformLoggingImpl getInstance() { + return new PlatformLoggingImpl(new LoggingMXBeanAccess()); + } + + static final PlatformLoggingMXBean MBEAN = getInstance(); } private static List bufferPools = null; 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 59c0be3360e..2944e5d0f13 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 @@ -194,7 +194,7 @@ public class MarshalInputStream extends ObjectInputStream { /* * Unless we were told to skip this consideration, choose the * "default loader" to simulate the default ObjectInputStream - * resolveClass mechanism (that is, choose the first non-null + * resolveClass mechanism (that is, choose the first non-platform * loader on the execution stack) to maximize the likelihood of * type compatibility with calling code. (This consideration * is skipped during server parameter unmarshalling using the 1.2 @@ -268,8 +268,9 @@ public class MarshalInputStream extends ObjectInputStream { } /* - * Returns the first non-null class loader up the execution stack, or null - * if only code from the null class loader is on the stack. + * Returns the first non-platform class loader up the execution stack, + * or platform class loader if only code from the platform class loader or null + * is on the stack. */ private static ClassLoader latestUserDefinedLoader() { return jdk.internal.misc.VM.latestUserDefinedLoader(); diff --git a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java index 4a9562b069f..a5e965e5ec3 100644 --- a/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java +++ b/jdk/src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java @@ -258,7 +258,7 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine { /* * Convenience method for simple commands */ - private InputStream executeCommand(String cmd, Object ... args) throws IOException { + public InputStream executeCommand(String cmd, Object ... args) throws IOException { try { return execute(cmd, args); } catch (AgentLoadException x) { diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java new file mode 100644 index 00000000000..b2f2b569859 --- /dev/null +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.security.ucrypto; + +/** + * Enum for representing the ucrypto mechanisms. + * + * @since 9 + */ +public enum LibMDMech { + + MD5(new ServiceDesc[] + { sd("MessageDigest", "MD5", "com.oracle.security.ucrypto.NativeDigestMD$MD5") + }), + SHA_1(new ServiceDesc[] + { sd("MessageDigest", "SHA", "com.oracle.security.ucrypto.NativeDigestMD$SHA1", + "SHA-1", "SHA1") + }), + SHA_256(new ServiceDesc[] + { sd("MessageDigest", "SHA-256", "com.oracle.security.ucrypto.NativeDigestMD$SHA256", + "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1") + }), + SHA_384(new ServiceDesc[] + { sd("MessageDigest", "SHA-384", "com.oracle.security.ucrypto.NativeDigestMD$SHA384", + "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2") + }), + SHA_512(new ServiceDesc[] + { sd("MessageDigest", "SHA-512", "com.oracle.security.ucrypto.NativeDigestMD$SHA512", + "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3") + }); + + ServiceDesc[] serviceDescs; + + private static ServiceDesc sd(String type, String algo, String cn, String... aliases) { + return new ServiceDesc(type, algo, cn, aliases); + } + + LibMDMech(ServiceDesc[] serviceDescs) { + this.serviceDescs = serviceDescs; + } + + public ServiceDesc[] getServiceDescriptions() { return serviceDescs; } +} diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java index 9c0929a95b2..98292eb5561 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.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 @@ -33,23 +33,67 @@ import java.util.concurrent.ConcurrentSkipListSet; import java.security.*; /** - * MessageDigest implementation class. This class currently supports - * MD5, SHA1, SHA256, SHA384, and SHA512 + * MessageDigest implementation class using native Ucrypto API. + * This class currently supports: MD5, SHA-2 (224, 256, 384, 512) + * and SHA-3 (224, 256, 384, 512) digests * * @since 9 */ -public abstract class NativeDigest extends MessageDigestSpi - implements Cloneable { +abstract class NativeDigest extends MessageDigestSpi { - private static final int MECH_MD5 = 1; - private static final int MECH_SHA1 = 2; - private static final int MECH_SHA256 = 3; - private static final int MECH_SHA224 = 4; - private static final int MECH_SHA384 = 5; - private static final int MECH_SHA512 = 6; + public static final class MD5 extends NativeDigest { + public MD5() { + super(UcryptoMech.CRYPTO_MD5, 16); + } + } + public static final class SHA1 extends NativeDigest { + public SHA1() { + super(UcryptoMech.CRYPTO_SHA1, 20); + } + } + public static final class SHA224 extends NativeDigest { + public SHA224() { + super(UcryptoMech.CRYPTO_SHA224, 28); + } + } + public static final class SHA256 extends NativeDigest { + public SHA256() { + super(UcryptoMech.CRYPTO_SHA256, 32); + } + } + public static final class SHA384 extends NativeDigest { + public SHA384() { + super(UcryptoMech.CRYPTO_SHA384, 48); + } + } + public static final class SHA512 extends NativeDigest { + public SHA512() { + super(UcryptoMech.CRYPTO_SHA512, 64); + } + } + public static final class SHA3_224 extends NativeDigest { + public SHA3_224() { + super(UcryptoMech.CRYPTO_SHA3_224, 28); + } + } + public static final class SHA3_256 extends NativeDigest { + public SHA3_256() { + super(UcryptoMech.CRYPTO_SHA3_256, 32); + } + } + public static final class SHA3_384 extends NativeDigest { + public SHA3_384() { + super(UcryptoMech.CRYPTO_SHA3_384, 48); + } + } + public static final class SHA3_512 extends NativeDigest { + public SHA3_512() { + super(UcryptoMech.CRYPTO_SHA3_512, 64); + } + } private final int digestLen; - private final int mech; + private final UcryptoMech mech; // field for ensuring native memory is freed private DigestContextRef pCtxt = null; @@ -64,10 +108,9 @@ public abstract class NativeDigest extends MessageDigestSpi // referents are GC'ed so we can do post-mortem processing private static Set refList = new ConcurrentSkipListSet(); - // Collections.synchronizedSortedSet(new TreeSet()); private final long id; - private final int mech; + private final UcryptoMech mech; private static void drainRefQueueBounded() { while (true) { @@ -77,7 +120,7 @@ public abstract class NativeDigest extends MessageDigestSpi } } - DigestContextRef(NativeDigest nc, long id, int mech) { + DigestContextRef(NativeDigest nc, long id, UcryptoMech mech) { super(nc, refQueue); this.id = id; this.mech = mech; @@ -98,18 +141,22 @@ public abstract class NativeDigest extends MessageDigestSpi refList.remove(this); try { if (needFree) { - UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id); - NativeDigest.nativeFree(mech, id); - } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id); + UcryptoProvider.debug("Resource: free Digest Ctxt " + + this.id); + NativeDigest.nativeFree(mech.value(), id); + } else { + UcryptoProvider.debug("Resource: discard Digest Ctxt " + + this.id); + } } finally { this.clear(); } } } - NativeDigest(int mech, int digestLen) { - this.digestLen = digestLen; + NativeDigest(UcryptoMech mech, int digestLen) { this.mech = mech; + this.digestLen = digestLen; } // see JCA spec @@ -153,10 +200,10 @@ public abstract class NativeDigest extends MessageDigestSpi } if (pCtxt == null) { - pCtxt = new DigestContextRef(this, nativeInit(mech), mech); + pCtxt = new DigestContextRef(this, nativeInit(mech.value()), mech); } try { - int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen); + int status = nativeDigest(mech.value(), pCtxt.id, out, ofs, digestLen); if (status != 0) { throw new DigestException("Internal error: " + status); } @@ -183,64 +230,24 @@ public abstract class NativeDigest extends MessageDigestSpi + len + ". in.length: " + in.length); } if (pCtxt == null) { - pCtxt = new DigestContextRef(this, nativeInit(mech), mech); + pCtxt = new DigestContextRef(this, nativeInit(mech.value()), mech); } - nativeUpdate(mech, pCtxt.id, in, ofs, len); + nativeUpdate(mech.value(), pCtxt.id, in, ofs, len); } /** * Clone this digest. */ public synchronized Object clone() throws CloneNotSupportedException { - NativeDigest copy = (NativeDigest) super.clone(); - // re-work the fields that cannot be copied over - if (pCtxt != null) { - copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech); - } - return copy; + throw new CloneNotSupportedException("Clone is not supported"); } // return pointer to the context - protected static native long nativeInit(int mech); + protected static final native long nativeInit(int mech); // return status code; always 0 - protected static native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen); + protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen); // return status code; always 0 - protected static native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen); - // return pointer to the duplicated context - protected static native long nativeClone(int mech, long pCtxt); + protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen); // free the specified context - private native static void nativeFree(int mech, long id); - - - public static final class MD5 extends NativeDigest { - public MD5() { - super(MECH_MD5, 16); - } - } - - public static final class SHA1 extends NativeDigest { - public SHA1() { - super(MECH_SHA1, 20); - } - } - - public static final class SHA256 extends NativeDigest { - public SHA256() { - super(MECH_SHA256, 32); - } - } - - - public static final class SHA384 extends NativeDigest { - public SHA384() { - super(MECH_SHA384, 48); - } - } - - - public static final class SHA512 extends NativeDigest { - public SHA512() { - super(MECH_SHA512, 64); - } - } + private static final native void nativeFree(int mech, long id); } diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java new file mode 100644 index 00000000000..132fcafa9b4 --- /dev/null +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.security.ucrypto; + +import java.lang.ref.*; + +import java.io.ByteArrayOutputStream; +import java.util.*; +import java.util.concurrent.ConcurrentSkipListSet; +import java.security.*; + +/** + * MessageDigest implementation class for libMD API. This class currently supports + * MD5, SHA1, SHA256, SHA384, and SHA512 + * + * @since 9 + */ +public abstract class NativeDigestMD extends MessageDigestSpi + implements Cloneable { + + private static final int MECH_MD5 = 1; + private static final int MECH_SHA1 = 2; + private static final int MECH_SHA256 = 3; + private static final int MECH_SHA224 = 4; + private static final int MECH_SHA384 = 5; + private static final int MECH_SHA512 = 6; + + private final int digestLen; + private final int mech; + + // field for ensuring native memory is freed + private DigestContextRef pCtxt = null; + + private static class DigestContextRef extends PhantomReference + implements Comparable { + + private static ReferenceQueue refQueue = + new ReferenceQueue(); + + // Needed to keep these references from being GC'ed until when their + // referents are GC'ed so we can do post-mortem processing + private static Set refList = + new ConcurrentSkipListSet(); + // Collections.synchronizedSortedSet(new TreeSet()); + + private final long id; + private final int mech; + + private static void drainRefQueueBounded() { + while (true) { + DigestContextRef next = (DigestContextRef) refQueue.poll(); + if (next == null) break; + next.dispose(true); + } + } + + DigestContextRef(NativeDigestMD nc, long id, int mech) { + super(nc, refQueue); + this.id = id; + this.mech = mech; + refList.add(this); + UcryptoProvider.debug("Resource: track Digest Ctxt " + this.id); + drainRefQueueBounded(); + } + + public int compareTo(DigestContextRef other) { + if (this.id == other.id) { + return 0; + } else { + return (this.id < other.id) ? -1 : 1; + } + } + + void dispose(boolean needFree) { + refList.remove(this); + try { + if (needFree) { + UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id); + NativeDigestMD.nativeFree(mech, id); + } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id); + } finally { + this.clear(); + } + } + } + + NativeDigestMD(int mech, int digestLen) { + this.digestLen = digestLen; + this.mech = mech; + } + + // see JCA spec + protected int engineGetDigestLength() { + return digestLen; + } + + // see JCA spec + protected synchronized void engineReset() { + if (pCtxt != null) { + pCtxt.dispose(true); + pCtxt = null; + } + } + + // see JCA spec + protected synchronized byte[] engineDigest() { + byte[] digest = new byte[digestLen]; + try { + int len = engineDigest(digest, 0, digestLen); + if (len != digestLen) { + throw new UcryptoException("Digest length mismatch." + + " Len: " + len + ". digestLen: " + digestLen); + } + return digest; + } catch (DigestException de) { + throw new UcryptoException("Internal error", de); + } + } + + // see JCA spec + protected synchronized int engineDigest(byte[] out, int ofs, int len) + throws DigestException { + if (len < digestLen) { + throw new DigestException("Output buffer must be at least " + + digestLen + " bytes long. Got: " + len); + } + if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) { + throw new DigestException("Buffer too short to store digest. " + + "ofs: " + ofs + ". len: " + len + ". out.length: " + out.length); + } + + if (pCtxt == null) { + pCtxt = new DigestContextRef(this, nativeInit(mech), mech); + } + try { + int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen); + if (status != 0) { + throw new DigestException("Internal error: " + status); + } + } finally { + pCtxt.dispose(false); + pCtxt = null; + } + return digestLen; + } + + // see JCA spec + protected synchronized void engineUpdate(byte in) { + byte[] temp = { in }; + engineUpdate(temp, 0, 1); + } + + // see JCA spec + protected synchronized void engineUpdate(byte[] in, int ofs, int len) { + if (len == 0) { + return; + } + if ((ofs < 0) || (len < 0) || (ofs > in.length - len)) { + throw new ArrayIndexOutOfBoundsException("ofs: " + ofs + ". len: " + + len + ". in.length: " + in.length); + } + if (pCtxt == null) { + pCtxt = new DigestContextRef(this, nativeInit(mech), mech); + } + nativeUpdate(mech, pCtxt.id, in, ofs, len); + } + + /** + * Clone this digest. + */ + public synchronized Object clone() throws CloneNotSupportedException { + NativeDigestMD copy = (NativeDigestMD) super.clone(); + // re-work the fields that cannot be copied over + if (pCtxt != null) { + copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech); + } + return copy; + } + + // return pointer to the context + protected static final native long nativeInit(int mech); + // return status code; always 0 + protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen); + // return status code; always 0 + protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen); + // return pointer to the duplicated context + protected static final native long nativeClone(int mech, long pCtxt); + // free the specified context + private static final native void nativeFree(int mech, long id); + + + public static final class MD5 extends NativeDigestMD { + public MD5() { + super(MECH_MD5, 16); + } + } + + public static final class SHA1 extends NativeDigestMD { + public SHA1() { + super(MECH_SHA1, 20); + } + } + + public static final class SHA256 extends NativeDigestMD { + public SHA256() { + super(MECH_SHA256, 32); + } + } + + + public static final class SHA384 extends NativeDigestMD { + public SHA384() { + super(MECH_SHA384, 48); + } + } + + + public static final class SHA512 extends NativeDigestMD { + public SHA512() { + super(MECH_SHA512, 64); + } + } +} diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java index cb6b4ffe597..ebc436a52c8 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.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 @@ -25,8 +25,6 @@ package com.oracle.security.ucrypto; -import java.util.HashMap; - /** * Enum for representing the ucrypto mechanisms. * @@ -35,78 +33,126 @@ import java.util.HashMap; // Check /usr/include/libsoftcrypto.h for updates public enum UcryptoMech { - CRYPTO_AES_ECB(1, new ServiceDesc[] + CRYPTO_AES_ECB(new ServiceDesc[] { sd("Cipher", "AES/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding"), sd("Cipher", "AES/ECB/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesEcbPKCS5", "AES"), - sd("Cipher", "AES_128/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes128EcbNoPadding", + sd("Cipher", "AES_128/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding", "2.16.840.1.101.3.4.1.1", "OID.2.16.840.1.101.3.4.1.1"), - sd("Cipher", "AES_192/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes192EcbNoPadding", + sd("Cipher", "AES_192/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding", "2.16.840.1.101.3.4.1.21", "OID.2.16.840.1.101.3.4.1.21"), - sd("Cipher", "AES_256/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes256EcbNoPadding", + sd("Cipher", "AES_256/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding", "2.16.840.1.101.3.4.1.41", "OID.2.16.840.1.101.3.4.1.41") }), - CRYPTO_AES_CBC(2, new ServiceDesc[] + CRYPTO_AES_CBC(new ServiceDesc[] { sd("Cipher", "AES/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding"), sd("Cipher", "AES/CBC/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCbcPKCS5"), - sd("Cipher", "AES_128/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes128CbcNoPadding", + sd("Cipher", "AES_128/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding", "2.16.840.1.101.3.4.1.2", "OID.2.16.840.1.101.3.4.1.2"), - sd("Cipher", "AES_192/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes192CbcNoPadding", + sd("Cipher", "AES_192/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding", "2.16.840.1.101.3.4.1.22", "OID.2.16.840.1.101.3.4.1.22"), - sd("Cipher", "AES_256/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes256CbcNoPadding", + sd("Cipher", "AES_256/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding", "2.16.840.1.101.3.4.1.42", "OID.2.16.840.1.101.3.4.1.42") }), - CRYPTO_AES_CBC_PAD(3, null), // No support from Solaris yet - CRYPTO_AES_CTR(4, new ServiceDesc[] +// CRYPTO_AES_CBC_PAD(null), // Support added since S11.1; however we still use CRYPTO_AES_CBC due to known bug + CRYPTO_AES_CTR(new ServiceDesc[] { sd("Cipher", "AES/CTR/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCtrNoPadding") }), - CRYPTO_AES_CCM(5, null), // Cannot support due to lack of Java API which corresponds to CK_AES_CCM_PARAMS - CRYPTO_AES_GCM(6, new ServiceDesc[] +// CRYPTO_AES_CCM(null), // Need Java API for CK_AES_CCM_PARAMS + CRYPTO_AES_GCM(new ServiceDesc[] { sd("Cipher", "AES/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding"), - sd("Cipher", "AES_128/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes128GcmNoPadding", + sd("Cipher", "AES_128/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding", "2.16.840.1.101.3.4.1.6", "OID.2.16.840.1.101.3.4.1.6"), - sd("Cipher", "AES_192/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes192GcmNoPadding", + sd("Cipher", "AES_192/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding", "2.16.840.1.101.3.4.1.26", "OID.2.16.840.1.101.3.4.1.26"), - sd("Cipher", "AES_256/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes256GcmNoPadding", + sd("Cipher", "AES_256/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding", "2.16.840.1.101.3.4.1.46", "OID.2.16.840.1.101.3.4.1.46") }), - CRYPTO_AES_GMAC(7, null), // No support from Solaris yet - CRYPTO_AES_CFB128(8, new ServiceDesc[] +// CRYPTO_AES_GMAC(null), // No support from Solaris + CRYPTO_AES_CFB128(new ServiceDesc[] { sd("Cipher", "AES/CFB128/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCfb128NoPadding"), - sd("Cipher", "AES/CFB128/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCfb128PKCS5") }), - CRYPTO_RSA_PKCS(31, new ServiceDesc[] + sd("Cipher", "AES/CFB128/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCfb128PKCS5") + }), + + CRYPTO_RSA_PKCS(new ServiceDesc[] { sd("Cipher", "RSA/ECB/PKCS1Padding", "com.oracle.security.ucrypto.NativeRSACipher$PKCS1Padding", - "RSA") }), - CRYPTO_RSA_X_509(32, new ServiceDesc[] + "RSA") + }), + CRYPTO_RSA_X_509(new ServiceDesc[] { sd("Cipher", "RSA/ECB/NoPadding", "com.oracle.security.ucrypto.NativeRSACipher$NoPadding") }), - CRYPTO_MD5_RSA_PKCS(33, new ServiceDesc[] + CRYPTO_MD5_RSA_PKCS(new ServiceDesc[] { sd("Signature", "MD5withRSA", "com.oracle.security.ucrypto.NativeRSASignature$MD5", - "1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4") }), - CRYPTO_SHA1_RSA_PKCS(34, new ServiceDesc[] + "1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4") + }), + CRYPTO_SHA1_RSA_PKCS(new ServiceDesc[] { sd("Signature", "SHA1withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA1", "1.2.840.113549.1.1.5", "OID.1.2.840.113549.1.1.5", - "1.3.14.3.2.29") }), - CRYPTO_SHA256_RSA_PKCS(35, new ServiceDesc[] + "1.3.14.3.2.29") + }), + CRYPTO_SHA256_RSA_PKCS(new ServiceDesc[] { sd("Signature", "SHA256withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA256", - "1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11") }), - CRYPTO_SHA384_RSA_PKCS(36, new ServiceDesc[] + "1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11") + }), + CRYPTO_SHA384_RSA_PKCS(new ServiceDesc[] { sd("Signature", "SHA384withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA384", - "1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12") }), - CRYPTO_SHA512_RSA_PKCS(37, new ServiceDesc[] + "1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12") + }), + CRYPTO_SHA512_RSA_PKCS(new ServiceDesc[] { sd("Signature", "SHA512withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA512", - "1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13") }); + "1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13") + }), - private final int mech; + CRYPTO_MD5(new ServiceDesc[] + { sd("MessageDigest", "MD5", "com.oracle.security.ucrypto.NativeDigest$MD5") }), + CRYPTO_SHA1(new ServiceDesc[] + { sd("MessageDigest", "SHA", "com.oracle.security.ucrypto.NativeDigest$SHA1", "SHA-1", "SHA1") }), + CRYPTO_SHA224(new ServiceDesc[] + { sd("MessageDigest", "SHA-224", "com.oracle.security.ucrypto.NativeDigest$SHA224", + "2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4") + }), + CRYPTO_SHA256(new ServiceDesc[] + { sd("MessageDigest", "SHA-256", "com.oracle.security.ucrypto.NativeDigest$SHA256", + "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1") + }), + CRYPTO_SHA384(new ServiceDesc[] + { sd("MessageDigest", "SHA-384", "com.oracle.security.ucrypto.NativeDigest$SHA384", + "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2") + }), + CRYPTO_SHA512(new ServiceDesc[] + { sd("MessageDigest", "SHA-512", "com.oracle.security.ucrypto.NativeDigest$SHA512", + "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3") + }), + CRYPTO_SHA3_224(new ServiceDesc[] + { sd("MessageDigest", "SHA3-224", "com.oracle.security.ucrypto.NativeDigest$SHA3_224", + "2.16.840.1.101.3.4.2.7", "OID.2.16.840.1.101.3.4.2.7") + }), + CRYPTO_SHA3_256(new ServiceDesc[] + { sd("MessageDigest", "SHA3-256", "com.oracle.security.ucrypto.NativeDigest$SHA3_256", + "2.16.840.1.101.3.4.2.8", "OID.2.16.840.1.101.3.4.2.8") + }), + CRYPTO_SHA3_384(new ServiceDesc[] + { sd("MessageDigest", "SHA3-384", "com.oracle.security.ucrypto.NativeDigest$SHA3_384", + "2.16.840.1.101.3.4.2.9", "OID.2.16.840.1.101.3.4.2.9") + }), + CRYPTO_SHA3_512(new ServiceDesc[] + { sd("MessageDigest", "SHA3-512", "com.oracle.security.ucrypto.NativeDigest$SHA3_512", + "2.16.840.1.101.3.4.2.10", "OID.2.16.840.1.101.3.4.2.10") + }); + + private int mech = 0; private final ServiceDesc[] serviceDescs; private static ServiceDesc sd(String type, String algo, String cn, String... aliases) { return new ServiceDesc(type, algo, cn, aliases); } - UcryptoMech(int mech, ServiceDesc[] serviceDescs) { - this.mech = mech; + UcryptoMech(ServiceDesc[] serviceDescs) { this.serviceDescs = serviceDescs; } + public void setValue(int nativeMechValue) { + this.mech = nativeMechValue; + } + public int value() { return mech; } public ServiceDesc[] getServiceDescriptions() { return serviceDescs; } } diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java index e3595359019..35cceda0757 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.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 @@ -27,6 +27,7 @@ package com.oracle.security.ucrypto; import java.io.IOException; import java.io.File; +import java.lang.reflect.Constructor; import java.util.*; import java.security.*; @@ -74,48 +75,52 @@ public final class UcryptoProvider extends Provider { if (provProp != null) { boolean[] result = loadLibraries(); if (result.length == 2) { - if (result[0]) { // successfully loaded libmd - provProp.put("MessageDigest.MD5", - sd("MessageDigest", "MD5", - "com.oracle.security.ucrypto.NativeDigest$MD5")); - provProp.put("MessageDigest.SHA", - sd("MessageDigest", "SHA", - "com.oracle.security.ucrypto.NativeDigest$SHA1", - "SHA-1", "SHA1")); - provProp.put("MessageDigest.SHA-256", - sd("MessageDigest", "SHA-256", - "com.oracle.security.ucrypto.NativeDigest$SHA256", - "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1")); - - provProp.put("MessageDigest.SHA-384", - sd("MessageDigest", "SHA-384", - "com.oracle.security.ucrypto.NativeDigest$SHA384", - "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2")); - - provProp.put("MessageDigest.SHA-512", - sd("MessageDigest", "SHA-512", - "com.oracle.security.ucrypto.NativeDigest$SHA512", - "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3")); - }; - if (result[1]) { // successfully loaded libsoftcrypto + // true when libsoftcrypto or libucrypto(S12) has been successfully loaded + if (result[1]) { String supportedMechs = getMechList(); debug("Prov: supported mechs = " + supportedMechs); - for (UcryptoMech m : UcryptoMech.values()) { - if (supportedMechs.indexOf(m.name() + ",") != -1) { + StringTokenizer st = new StringTokenizer(supportedMechs, ":,;"); + // format: numOfSupportedMechs:[mechName,mechValue;]+ + // skip the first one which is numberOfSupportedMechs + st.nextToken(); + while (st.hasMoreTokens()) { + String mechName = st.nextToken(); + int nativeMechVal = Integer.parseInt(st.nextToken()); + try { + UcryptoMech m = Enum.valueOf(UcryptoMech.class, mechName); + m.setValue(nativeMechVal); ServiceDesc[] services = m.getServiceDescriptions(); - // skip unsupported UcryptoMech - if (services == null || services.length == 0) continue; + // defined in UcryptoMech as unsupported + if (services == null || services.length == 0) { + debug("Skip Unsupported Algorithm: " + mechName); + continue; + } for (int p = 0; p < services.length; p++) { ServiceDesc entry = services[p]; provProp.put(entry.getType() + "." + entry.getAlgorithm(), entry); } + } catch (IllegalArgumentException iae) { + // not defined in UcryptoMech + debug("Skip Unrecognized Algorithm: " + mechName); } } // NOTE: GCM support is only available since jdk 7 provProp.put("AlgorithmParameters.GCM", - sd("AlgorithmParameters", "GCM", "com.oracle.security.ucrypto.GCMParameters")); + sd("AlgorithmParameters", "GCM", + "com.oracle.security.ucrypto.GCMParameters")); } + // true when libmd is needed and has been successfully loaded + if (result[0]) { + for (LibMDMech m : LibMDMech.values()) { + ServiceDesc[] services = m.getServiceDescriptions(); + for (ServiceDesc entry : services) { + String sKey = entry.getType() + "." + entry.getAlgorithm(); + // only register if none has been registered + provProp.putIfAbsent(sKey, entry); + } + } + }; } else { debug("Prov: unexpected ucrypto library loading error, got " + result.length); } @@ -138,6 +143,7 @@ public final class UcryptoProvider extends Provider { sd.getAliases(), null); } + @SuppressWarnings("deprecation") @Override public Object newInstance(Object ctrParamObj) throws NoSuchAlgorithmException { @@ -152,53 +158,19 @@ public final class UcryptoProvider extends Provider { int keySize = -1; if (algo.charAt(3) == '_') { keySize = Integer.parseInt(algo.substring(4, 7))/8; - algo = algo.substring(0, 3) + algo.substring(7); } - if (algo.equals("AES/ECB/NoPadding")) { - return new NativeCipher.AesEcbNoPadding(keySize); - } else if (algo.equals("AES/ECB/PKCS5Padding")) { - return new NativeCipherWithJavaPadding.AesEcbPKCS5(); - } else if (algo.equals("AES/CBC/NoPadding")) { - return new NativeCipher.AesCbcNoPadding(keySize); - } else if (algo.equals("AES/CBC/PKCS5Padding")) { - return new NativeCipherWithJavaPadding.AesCbcPKCS5(); - } else if (algo.equals("AES/CTR/NoPadding")) { - return new NativeCipher.AesCtrNoPadding(); - } else if (algo.equals("AES/GCM/NoPadding")) { - return new NativeGCMCipher.AesGcmNoPadding(keySize); - } else if (algo.equals("AES/CFB128/NoPadding")) { - return new NativeCipher.AesCfb128NoPadding(); - } else if (algo.equals("AES/CFB128/PKCS5Padding")) { - return new NativeCipherWithJavaPadding.AesCfb128PKCS5(); - } else if (algo.equals("RSA/ECB/NoPadding")) { - return new NativeRSACipher.NoPadding(); - } else if (algo.equals("RSA/ECB/PKCS1Padding")) { - return new NativeRSACipher.PKCS1Padding(); - } - } else if (type.equals("Signature")) { - if (algo.equals("SHA1withRSA")) { - return new NativeRSASignature.SHA1(); - } else if (algo.equals("SHA256withRSA")) { - return new NativeRSASignature.SHA256(); - } else if (algo.equals("SHA384withRSA")) { - return new NativeRSASignature.SHA384(); - } else if (algo.equals("SHA512withRSA")) { - return new NativeRSASignature.SHA512(); - } else if (algo.equals("MD5withRSA")) { - return new NativeRSASignature.MD5(); - } - } else if (type.equals("MessageDigest")) { - if (algo.equals("SHA")) { - return new NativeDigest.SHA1(); - } else if (algo.equals("SHA-256")) { - return new NativeDigest.SHA256(); - } else if (algo.equals("SHA-384")) { - return new NativeDigest.SHA384(); - } else if (algo.equals("SHA-512")) { - return new NativeDigest.SHA512(); - } else if (algo.equals("MD5")) { - return new NativeDigest.MD5(); + String implClass = getClassName(); + Class clz = Class.forName(implClass); + if (keySize != -1) { + Constructor ctr = clz.getConstructor(int.class); + return ctr.newInstance(keySize); + } else { + return clz.newInstance(); } + } else if (type.equals("Signature") || type.equals("MessageDigest")) { + String implClass = getClassName(); + Class clz = Class.forName(implClass); + return clz.newInstance(); } else if (type.equals("AlgorithmParameters")) { if (algo.equals("GCM")) { return new GCMParameters(); diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/libsoftcrypto.h b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/libsoftcrypto.h deleted file mode 100644 index 17c38557dc5..00000000000 --- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/libsoftcrypto.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _LIBSOFTCRYPTO_H -#define _LIBSOFTCRYPTO_H - -#include -#include -#include -#include -#include -#include - -typedef enum ucrypto_mech { - CRYPTO_AES_ECB = 1, - CRYPTO_AES_CBC, - CRYPTO_AES_CBC_PAD, - CRYPTO_AES_CTR, - CRYPTO_AES_CCM, - CRYPTO_AES_GCM, - CRYPTO_AES_GMAC, - CRYPTO_AES_CFB128, - CRYPTO_RSA_PKCS = 31, - CRYPTO_RSA_X_509, - CRYPTO_MD5_RSA_PKCS, - CRYPTO_SHA1_RSA_PKCS, - CRYPTO_SHA256_RSA_PKCS, - CRYPTO_SHA384_RSA_PKCS, - CRYPTO_SHA512_RSA_PKCS -} ucrypto_mech_t; - -typedef struct crypto_ctx { - void *cc_provider; - uint_t cc_session; - void *cc_provider_private; /* owned by provider */ - void *cc_framework_private; /* owned by framework */ - uint32_t cc_flags; /* flags */ - void *cc_opstate; /* state */ -} crypto_ctx_t; - -extern int ucrypto_encrypt_init(crypto_ctx_t *context, - ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, - void *iv, size_t iv_len); - -extern int ucrypto_encrypt_update(crypto_ctx_t *context, uchar_t *in, - size_t in_len, uchar_t *out, size_t *out_len); - -extern int ucrypto_encrypt_final(crypto_ctx_t *context, uchar_t *out, - size_t *out_len); - -/* Encrypt atomic */ -extern int ucrypto_encrypt(ucrypto_mech_t mech_type, uchar_t *key_str, - size_t key_len, void *iv, size_t iv_len, uchar_t *in, - size_t in_len, uchar_t *out, size_t *out_len); - -/* Decrypt multi-part */ -extern int ucrypto_decrypt_init(crypto_ctx_t *context, - ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, - void *iv, size_t iv_len); - -extern int ucrypto_decrypt_update(crypto_ctx_t *context, uchar_t *in, - size_t in_len, uchar_t *out, size_t *out_len); - -extern int ucrypto_decrypt_final(crypto_ctx_t *context, uchar_t *out, - size_t *out_len); - -/* Decrypt atomic */ -extern int ucrypto_decrypt(ucrypto_mech_t mech_type, uchar_t *key_str, - size_t key_len, void *iv, size_t iv_len, uchar_t *in, - size_t in_len, uchar_t *out, size_t *out_len); - -/* Sign multi-part */ -extern int ucrypto_sign_init(crypto_ctx_t *context, ucrypto_mech_t mech_type, - uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - -extern int ucrypto_sign_update(crypto_ctx_t *context, - uchar_t *data_str, size_t data_len); - -extern int ucrypto_sign_final(crypto_ctx_t *context, - uchar_t *sig_str, size_t *sig_len); - -/* Sign atomic */ -extern int ucrypto_sign(ucrypto_mech_t mech_type, - uchar_t *key_str, size_t key_len, void *iv, size_t iv_len, - uchar_t *data_str, size_t data_len, uchar_t *sig_str, size_t *sig_len); - -/* Verify multi-part */ -extern int ucrypto_verify_init(crypto_ctx_t *context, ucrypto_mech_t mech_type, - uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - -extern int ucrypto_verify_update(crypto_ctx_t *context, - uchar_t *data_str, size_t data_len); - -extern int ucrypto_verify_final(crypto_ctx_t *context, - uchar_t *sig_str, size_t *sig_len); - -/* Verify atomic */ -extern int ucrypto_verify(ucrypto_mech_t mech_type, - uchar_t *key_str, size_t key_len, void *iv, size_t iv_len, - uchar_t *data_str, size_t data_len, uchar_t *sig, size_t *sig_len); - -extern int ucrypto_get_mechlist(char *str); - -extern const char *ucrypto_id2mech(ucrypto_mech_t mech_type); - -extern ucrypto_mech_t ucrypto_mech2id(const char *str); - -extern int ucrypto_version(); - -typedef struct CK_AES_CTR_PARAMS { - ulong_t ulCounterBits; - uint8_t cb[16]; -} CK_AES_CTR_PARAMS; - -typedef struct CK_AES_GCM_PARAMS { - uchar_t *pIv; - ulong_t ulIvLen; - ulong_t ulIvBits; - uchar_t *pAAD; - ulong_t ulAADLen; - ulong_t ulTagBits; -} CK_AES_GCM_PARAMS; - -typedef struct crypto_object_attribute { - uint64_t oa_type; /* attribute type */ - caddr_t oa_value; /* attribute value */ - ssize_t oa_value_len; /* length of attribute value */ -} crypto_object_attribute_t; - -/* Attribute types to use for passing a RSA public key or a private key. */ -#define SUN_CKA_MODULUS 0x00000120 -#define SUN_CKA_MODULUS_BITS 0x00000121 -#define SUN_CKA_PUBLIC_EXPONENT 0x00000122 -#define SUN_CKA_PRIVATE_EXPONENT 0x00000123 -#define SUN_CKA_PRIME_1 0x00000124 -#define SUN_CKA_PRIME_2 0x00000125 -#define SUN_CKA_EXPONENT_1 0x00000126 -#define SUN_CKA_EXPONENT_2 0x00000127 -#define SUN_CKA_COEFFICIENT 0x00000128 -#define SUN_CKA_PRIME 0x00000130 -#define SUN_CKA_SUBPRIME 0x00000131 -#define SUN_CKA_BASE 0x00000132 - -#define CKK_EC 0x00000003 -#define CKK_GENERIC_SECRET 0x00000010 -#define CKK_RC4 0x00000012 -#define CKK_AES 0x0000001F -#define CKK_DES 0x00000013 -#define CKK_DES2 0x00000014 -#define CKK_DES3 0x00000015 - -#define CKO_PUBLIC_KEY 0x00000002 -#define CKO_PRIVATE_KEY 0x00000003 -#define CKA_CLASS 0x00000000 -#define CKA_VALUE 0x00000011 -#define CKA_KEY_TYPE 0x00000100 -#define CKA_VALUE_LEN 0x00000161 -#define CKA_EC_PARAMS 0x00000180 -#define CKA_EC_POINT 0x00000181 - -#endif /* _LIBSOFTCRYPTO_H */ diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c index 6ddbdc2bed2..126da6d37bd 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c +++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c @@ -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 @@ -32,6 +32,22 @@ #include "nativeCrypto.h" #include "nativeFunc.h" +/* + * Dumps out byte array in hex with and name and length info + */ +void printError(char* header, int mech, int rv) { + if (mech != -1) { + printf("%s, mech = %d, rv = 0x%0x\n", header, mech, rv); + } else { + printf("%s, rv = 0x%0x\n", header, rv); + } + if (*ftab->ucryptoStrerror != NULL) { + char * reason = (*ftab->ucryptoStrerror)(rv); + printf("\tcause = %s\n", reason); + free(reason); + } +} + /* * Dumps out byte array in hex with and name and length info */ @@ -60,6 +76,16 @@ void throwOutOfMemoryError(JNIEnv *env, const char *msg) (*env)->DeleteLocalRef(env, jExClass); } +/* + * De-allocates all memory associated with crypto_ctx_t + */ +void freeContext(crypto_ctx_t *context) { + if (ftab->ucryptoFreeContext != NULL) { + (*ftab->ucryptoFreeContext)(context); + } + free(context); +} + JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_VERSION_1_4; } @@ -203,10 +229,10 @@ CipherInit(crypto_ctx_t *context, int encrypt, ucrypto_mech_t mech, } if (encrypt) { rv = (*ftab->ucryptoEncryptInit)(context, mech, jKey, (size_t)jKeyLen, iv, ivLen); - if (rv != 0 && DEBUG) printf("ucryptoEncryptInit: ret = 0x%x\n", rv); + if (rv != 0 && DEBUG) printError("ucryptoEncryptInit", mech, rv); } else { rv =(*ftab->ucryptoDecryptInit)(context, mech, jKey, (size_t)jKeyLen, iv, ivLen); - if (rv != 0 && DEBUG) printf("ucryptoDecryptInit: ret = 0x%x\n", rv); + if (rv != 0 && DEBUG) printError("ucryptoDecryptInit", mech, rv); } if (iv != jIv) { @@ -234,15 +260,15 @@ CipherUpdate(crypto_ctx_t *context, int encrypt, unsigned char *bufIn, int inOfs } if (encrypt) { rv = (*ftab->ucryptoEncryptUpdate)(context, (unsigned char*)(bufIn+inOfs), (size_t)inLen, (unsigned char*)(bufOut+outOfs), &outLength); - if (rv != 0) { - if (DEBUG) printf("ucryptoEncryptUpdate: ret = 0x%x\n", rv); + if (rv) { + if (DEBUG) printError("ucryptoEncryptUpdate", -1, rv); } else { *outLen = (int)outLength; } } else { rv = (*ftab->ucryptoDecryptUpdate)(context, (unsigned char*)(bufIn+inOfs), (size_t)inLen, (unsigned char*)(bufOut+outOfs), &outLength); - if (rv != 0) { - if (DEBUG) printf("ucryptoDecryptUpdate: ret = 0x%x\n", rv); + if (rv) { + if (DEBUG) printError("ucryptoDecryptUpdate", -1, rv); } else { if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength); *outLen = (int)outLength; @@ -263,16 +289,16 @@ CipherFinal(crypto_ctx_t *context, int encrypt, unsigned char *bufOut, int outOf if (DEBUG) printf("CipherFinal: OutOfs %i, outLen %i\n", outOfs, *outLen); if (encrypt) { rv = (*ftab->ucryptoEncryptFinal)(context, (unsigned char*)(bufOut+outOfs), &outLength); - if (rv != 0) { - if (DEBUG) printf("ucryptoDecryptFinal: ret = 0x%x\n", rv); + if (rv) { + if (DEBUG) printError("ucryptoDecryptFinal", -1, rv); } else { if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength); *outLen = (int)outLength; } } else { rv = (*ftab->ucryptoDecryptFinal)(context, (unsigned char*)(bufOut+outOfs), &outLength); - if (rv != 0) { - if (DEBUG) printf("ucryptoDecryptFinal: ret = 0x%x\n", rv); + if (rv) { + if (DEBUG) printError("ucryptoDecryptFinal", -1, rv); } else { if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength); *outLen = (int)outLength; @@ -285,102 +311,61 @@ CipherFinal(crypto_ctx_t *context, int encrypt, unsigned char *bufOut, int outOf // SPECIAL ENTRIES FOR JVM JNI-BYPASSING OPTIMIZATION //////////////////////////////////////////////////////// jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit(jint mech) { - void *pContext = NULL; + crypto_ctx_t *context = NULL; + int rv; - switch (mech) { - case com_oracle_security_ucrypto_NativeDigest_MECH_SHA1: - pContext = (SHA1_CTX *) malloc(sizeof(SHA1_CTX)); - if (pContext != NULL) { - (*ftab->sha1Init)((SHA1_CTX *)pContext); + context = malloc(sizeof(crypto_ctx_t)); + if (context != NULL) { + rv = (*ftab->ucryptoDigestInit)(context, (ucrypto_mech_t) mech, NULL, 0); + if (rv) { + freeContext(context); + if (DEBUG) printError("ucryptoDigestInit", mech, rv); + return 0L; } - break; - case com_oracle_security_ucrypto_NativeDigest_MECH_MD5: - pContext = (MD5_CTX *) malloc(sizeof(MD5_CTX)); - if (pContext != NULL) { - (*ftab->md5Init)((MD5_CTX *)pContext); - } - break; - case com_oracle_security_ucrypto_NativeDigest_MECH_SHA256: - pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX)); - if (pContext != NULL) { - (*ftab->sha2Init)(SHA256, (SHA2_CTX *)pContext); - } - break; - case com_oracle_security_ucrypto_NativeDigest_MECH_SHA384: - pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX)); - if (pContext != NULL) { - (*ftab->sha2Init)(SHA384, (SHA2_CTX *)pContext); - } - break; - case com_oracle_security_ucrypto_NativeDigest_MECH_SHA512: - pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX)); - if (pContext != NULL) { - (*ftab->sha2Init)(SHA512, (SHA2_CTX *)pContext); - } - break; - default: - if (DEBUG) printf("ERROR: Unsupported mech %i\n", mech); } - return (jlong) pContext; + return (jlong) context; } jint JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate (jint mech, jlong pContext, int notUsed, unsigned char* in, jint ofs, jint len) { - if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) { - (*ftab->sha1Update)((SHA1_CTX*)pContext, (unsigned char*)(in+ofs), len); - } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) { - (*ftab->md5Update)((MD5_CTX*)pContext, (unsigned char*)(in+ofs), len); - } else { // SHA-2 family - (*ftab->sha2Update)((SHA2_CTX*)pContext, (unsigned char*)(in+ofs), len); + crypto_ctx_t *context; + jint rv = 0; + + context = (crypto_ctx_t *) pContext; + rv = (*ftab->ucryptoDigestUpdate)(context, (const unsigned char*)(in + ofs), + (size_t) len); + + if (rv) { + freeContext(context); + if (DEBUG) printError("ucryptoDigestUpdate", mech, rv); } - return 0; + + return -rv; // use negative value to indicate error } -// Do digest and free the context immediately jint JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest (jint mech, jlong pContext, int notUsed, unsigned char* out, jint ofs, jint digestLen) { + crypto_ctx_t *context; + jint rv = 0; + size_t digest_len = digestLen; - if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) { - (*ftab->sha1Final)((unsigned char*)(out + ofs), (SHA1_CTX *)pContext); - free((SHA1_CTX *)pContext); - } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) { - (*ftab->md5Final)((unsigned char*)(out + ofs), (MD5_CTX *)pContext); - free((MD5_CTX *)pContext); - } else { // SHA-2 family - (*ftab->sha2Final)((unsigned char*)(out + ofs), (SHA2_CTX *)pContext); - free((SHA2_CTX *)pContext); + context = (crypto_ctx_t *) pContext; + rv = (*ftab->ucryptoDigestFinal)(context, (unsigned char*)(out + ofs), + &digest_len); + if (rv) { + freeContext(context); + if (DEBUG) printError("ucryptoDigestFinal", mech, rv); } - return 0; -} -jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone - (jint mech, jlong pContext) { - void *copy = NULL; - size_t len = 0; - - if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) { - len = sizeof(SHA1_CTX); - } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) { - len = sizeof(MD5_CTX); - } else { // SHA-2 family - len = sizeof(SHA2_CTX); - } - copy = (void*) malloc(len); - if (copy != NULL) { - bcopy((void *)pContext, copy, len); - } - return (jlong) copy; + return -rv; // use negative value to indicate error } void JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeFree (jint mech, jlong pContext) { - if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) { - free((SHA1_CTX*) pContext); - } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) { - free((MD5_CTX*) pContext); - } else { // SHA-2 family - free((SHA2_CTX*) pContext); - } + crypto_ctx_t *context; + + context = (crypto_ctx_t *) pContext; + freeContext(context); } // AES @@ -395,7 +380,7 @@ jlong JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeInit rv = CipherInit(context, encrypt, (ucrypto_mech_t) mech, bufKey, keyLen, bufIv, ivLen, tagLen, bufAad, aadLen); if (rv) { - free(context); + freeContext(context); return 0L; } } @@ -417,8 +402,7 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate context = (crypto_ctx_t *) pContext; rv = CipherUpdate(context, encrypt, (unsigned char*)bufIn, inOfs, inLen, (unsigned char*)bufOut, outOfs, &outLen); if (rv) { - free(context); - context = 0; + freeContext(context); return -rv; // use negative value to indicate error! } @@ -443,7 +427,7 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeFinal outLen = 0; } rv = CipherFinal(context, encrypt, bufOut, outOfs, &outLen); - free(context); + freeContext(context); if (rv) { return -rv; // use negative value to indicate error! } @@ -451,8 +435,6 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeFinal return outLen; } - - /* * Class: com_oracle_security_ucrypto_NativeDigest * Method: nativeInit @@ -475,13 +457,15 @@ JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeInit JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeUpdate (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jIn, jint jOfs, jint jLen) { unsigned char *bufIn; + jint rv = 0; + bufIn = (unsigned char *) getBytes(env, jIn, jOfs, jLen); if (!(*env)->ExceptionCheck(env)) { - JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen); + rv = JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen); free(bufIn); } - return 0; + return rv; } /* @@ -492,6 +476,7 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeUpdat JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeDigest (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jOut, jint jOutOfs, jint digestLen) { unsigned char *bufOut; + jint rv = 0; bufOut = (unsigned char *) malloc(digestLen); if (bufOut == NULL) { @@ -499,21 +484,12 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeDiges return 0; } - JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen); - - (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut); + rv = JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen); + if (rv == 0) { + (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut); + } free(bufOut); - return 0; -} - -/* - * Class: com_oracle_security_ucrypto_NativeDigest - * Method: nativeClone - * Signature: (IJ)J - */ -JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeClone - (JNIEnv *env, jclass jcls, jint mech, jlong pContext) { - return JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone(mech, pContext); + return rv; } /* @@ -582,7 +558,7 @@ JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeInit cleanup: if ((result == 0L) && (context != NULL)) { - free(context); + freeContext(context); } if (bufKey != NULL) { (*env)->ReleaseByteArrayElements(env, jKey, (jbyte *)bufKey, 0); @@ -626,7 +602,7 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdat rv = CipherUpdate(context, encrypt, bufIn, 0, inLen, bufOut, 0, &outLen); if (rv) { - free(context); + freeContext(context); free(bufIn); free(bufOut); return -rv; @@ -683,6 +659,7 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal return rc; } + /* * Class: com_oracle_security_ucrypto_NativeKey * Method: nativeFree @@ -984,9 +961,9 @@ jlong JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeIn } if (DEBUG) { - printf("RSAPublicKey Init: keyValue=%ld, keyLen=2\n", pKey); - printBytes("RSA PublicKey mod: ", (unsigned char*) mod, modLen); - printBytes("RSA PublicKey pubExp: ", (unsigned char*) pub, pubLen); + printf("RSAPublicKey.nativeInit: keyValue=%ld, keyLen=2\n", pKey); + printBytes("\tmod: ", (unsigned char*) mod, modLen); + printBytes("\tpubExp: ", (unsigned char*) pub, pubLen); } pKey[0].oa_type = SUN_CKA_MODULUS; @@ -1062,7 +1039,7 @@ SignatureInit(crypto_ctx_t *context, jint mechVal, jboolean sign, if (DEBUG) { printf("SignatureInit: context=%ld, mech=%d, sign=%d, keyValue=%ld, keyLength=%d\n", context, mech, sign, pKey, keyLength); - printf("SignatureInit, ret => 0x%x\n", rv); + printError("SignatureInit", mech, rv); } return rv; } @@ -1083,7 +1060,7 @@ jlong JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit pKey = (uchar_t *) jKey; rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength); if (rv) { - free(context); + freeContext(context); return 0L; } } @@ -1105,7 +1082,7 @@ JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeRSASignature_nati pKey = (uchar_t *) jKey; rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength); if (rv) { - free(context); + freeContext(context); throwUCExceptionUsingRV(env, rv); return 0L; } @@ -1125,7 +1102,7 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__J context = (crypto_ctx_t *) pCtxt; if (DEBUG) { - printf("Signature update: context=%ld, sign=%d, jIn=%ld, jInOfs=%d, jInLen=%d\n", + printf("NativeRSASignature.nativeUpdate: context=%ld, sign=%d, jIn=%ld, jInOfs=%d, jInLen=%d\n", context, sign, jIn, jInOfs, jInLen); } if (sign) { @@ -1133,9 +1110,9 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__J } else { rv = (*ftab->ucryptoVerifyUpdate)(context, (uchar_t *) (jIn + jInOfs), (size_t) jInLen); } - if (DEBUG) printf("Signature update, ret => 0x%x\n", rv); if (rv) { - free(context); + freeContext(context); + if (DEBUG) printError("NativeRSASignature.nativeUpdate", -1, rv); return -rv; // use negative value to indicate error! } @@ -1194,9 +1171,9 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal context = (crypto_ctx_t *) pCtxt; if (DEBUG) { - printf("Signature final: context=%ld, sign=%d, bufSig=%ld, sigOfs=%d, sigLen=%d\n", + printf("NativeRSASignature.nativeFinal: context=%ld, sign=%d, bufSig=%ld, sigOfs=%d, sigLen=%d\n", context, sign, bufSig, sigOfs, jSigLen); - printBytes("Before Final: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen); + printBytes("Before: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen); } if (sign) { rv = (*ftab->ucryptoSignFinal)(context, (uchar_t *) (bufSig + sigOfs), &sigLength); @@ -1204,18 +1181,17 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal rv = (*ftab->ucryptoVerifyFinal)(context, (uchar_t *) (bufSig + sigOfs), &sigLength); } - if (DEBUG) { - printf("Signature nativeFinal, ret => 0x%x\n", rv); - if (sigLength != jSigLen) { - printf("SIG actual output len=%d\n", sigLength); - } - if (sign) { - printBytes("After nativeFinal: ", (unsigned char*) (bufSig + sigOfs), jSigLen); - } - } - - free(context); + freeContext(context); if (rv) { + if (DEBUG) { + printError("NativeRSASignature.nativeFinal", -1, rv); + if (sigLength != jSigLen) { + printf("NativeRSASignature.nativeFinal out sig len=%d\n", sigLength); + } + if (sign) { + printBytes("After: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen); + } + } return -rv; } else return 0; } @@ -1273,10 +1249,10 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic pKey = (uchar_t *) keyValue; if (DEBUG) { - printf("Cipher nativeAtomic: mech=%d, encrypt=%d, pKey=%ld, keyLength=%d\n", + printf("NativeRSACipher.nativeAtomic: mech=%d, encrypt=%d, pKey=%ld, keyLength=%d\n", mech, encrypt, pKey, keyLength); - printBytes("Before nativeAtomic: in: ", (unsigned char*) bufIn, jInLen); - printBytes("Before nativeAtomic: out: ", (unsigned char*) (bufOut + jOutOfs), jOutLen); + printBytes("Before: in = ", (unsigned char*) bufIn, jInLen); + printBytes("Before: out = ", (unsigned char*) (bufOut + jOutOfs), jOutLen); } if (encrypt) { @@ -1289,11 +1265,11 @@ jint JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic (uchar_t *)(bufOut + jOutOfs), &outLength); } if (DEBUG) { - printf("Cipher nativeAtomic, ret => 0x%x\n", rv); + printError("NativeRSACipher.nativeAtomic", mech, rv); if (outLength != jOutLen) { - printf("CIP actual output len=%d\n", outLength); + printf("NativeRSACipher.nativeAtomic out len=%d\n", outLength); } - printBytes("After nativeAtomic: ", (unsigned char*) (bufOut + jOutOfs), outLength); + printBytes("After: ", (unsigned char*) (bufOut + jOutOfs), outLength); } if (rv) { diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h index 9ad3891d0d0..a3ea195387e 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h +++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h @@ -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 @@ -29,18 +29,18 @@ extern "C" { #endif -#undef com_oracle_security_ucrypto_NativeDigest_MECH_MD5 -#define com_oracle_security_ucrypto_NativeDigest_MECH_MD5 1L -#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA1 -#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA1 2L -#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA256 -#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA256 3L -#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA224 -#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA224 4L -#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA384 -#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA384 5L -#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA512 -#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA512 6L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5 1L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1 2L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256 3L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA224 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA224 4L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384 5L +#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512 +#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512 6L #define DEBUG 0 diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCryptoMD.c b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCryptoMD.c new file mode 100644 index 00000000000..df60ce3613a --- /dev/null +++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCryptoMD.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include "jni_util.h" +#include +#include "nativeCrypto.h" +#include "nativeFunc.h" + + +extern void throwOutOfMemoryError(JNIEnv *env, const char *msg); +extern jbyte* getBytes(JNIEnv *env, jbyteArray bytes, int offset, int len); + +/////////////////////////////////////////////////////// +// SPECIAL ENTRIES FOR JVM JNI-BYPASSING OPTIMIZATION +//////////////////////////////////////////////////////// +jlong JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit(jint mech) { + void *pContext = NULL; + + switch (mech) { + case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1: + pContext = malloc(sizeof(SHA1_CTX)); + if (pContext != NULL) { + (*ftab->sha1Init)((SHA1_CTX *)pContext); + } + break; + case com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5: + pContext = malloc(sizeof(MD5_CTX)); + if (pContext != NULL) { + (*ftab->md5Init)((MD5_CTX *)pContext); + } + break; + case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256: + pContext = malloc(sizeof(SHA2_CTX)); + if (pContext != NULL) { + (*ftab->sha2Init)(SHA256, (SHA2_CTX *)pContext); + } + break; + case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384: + pContext = malloc(sizeof(SHA2_CTX)); + if (pContext != NULL) { + (*ftab->sha2Init)(SHA384, (SHA2_CTX *)pContext); + } + break; + case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512: + pContext = malloc(sizeof(SHA2_CTX)); + if (pContext != NULL) { + (*ftab->sha2Init)(SHA512, (SHA2_CTX *)pContext); + } + break; + default: + if (DEBUG) printf("ERROR: Unsupported mech %i\n", mech); + } + return (jlong) pContext; +} + +jint JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate + (jint mech, jlong pContext, int notUsed, unsigned char* in, jint ofs, jint len) { + if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) { + (*ftab->sha1Update)((SHA1_CTX*)pContext, (unsigned char*)(in+ofs), len); + } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) { + (*ftab->md5Update)((MD5_CTX*)pContext, (unsigned char*)(in+ofs), len); + } else { // SHA-2 family + (*ftab->sha2Update)((SHA2_CTX*)pContext, (unsigned char*)(in+ofs), len); + } + return 0; +} + +// Do digest and free the context immediately +jint JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest + (jint mech, jlong pContext, int notUsed, unsigned char* out, jint ofs, jint digestLen) { + + if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) { + (*ftab->sha1Final)((unsigned char*)(out + ofs), (SHA1_CTX *)pContext); + free((SHA1_CTX *)pContext); + } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) { + (*ftab->md5Final)((unsigned char*)(out + ofs), (MD5_CTX *)pContext); + free((MD5_CTX *)pContext); + } else { // SHA-2 family + (*ftab->sha2Final)((unsigned char*)(out + ofs), (SHA2_CTX *)pContext); + free((SHA2_CTX *)pContext); + } + return 0; +} + +jlong JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone + (jint mech, jlong pContext) { + void *copy = NULL; + size_t len = 0; + + if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) { + len = sizeof(SHA1_CTX); + } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) { + len = sizeof(MD5_CTX); + } else { // SHA-2 family + len = sizeof(SHA2_CTX); + } + copy = malloc(len); + if (copy != NULL) { + bcopy((void *)pContext, copy, len); + } + return (jlong) copy; +} + +void JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree + (jint mech, jlong pContext) { + if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) { + free((SHA1_CTX*) pContext); + } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) { + free((MD5_CTX*) pContext); + } else { // SHA-2 family + free((SHA2_CTX*) pContext); + } +} + + +/* + * Class: com_oracle_security_ucrypto_NativeDigestMD + * Method: nativeInit + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeInit + (JNIEnv *env, jclass jcls, jint mech) { + jlong result = JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit(mech); + if (result == NULL) { + throwOutOfMemoryError(env, NULL); + } + return result; +} + +/* + * Class: com_oracle_security_ucrypto_NativeDigestMD + * Method: nativeUpdate + * Signature: (IJ[BII)I + */ +JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate + (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jIn, jint jOfs, jint jLen) { + unsigned char *bufIn; + + bufIn = (unsigned char *) getBytes(env, jIn, jOfs, jLen); + if (!(*env)->ExceptionCheck(env)) { + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen); + free(bufIn); + } + return 0; +} + +/* + * Class: com_oracle_security_ucrypto_NativeDigestMD + * Method: nativeDigest + * Signature: (IJ[BII)I + */ +JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest + (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jOut, jint jOutOfs, jint digestLen) { + unsigned char *bufOut; + + bufOut = (unsigned char *) malloc(digestLen); + if (bufOut == NULL) { + throwOutOfMemoryError(env, NULL); + return 0; + } + + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen); + + (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut); + free(bufOut); + return 0; +} + +/* + * Class: com_oracle_security_ucrypto_NativeDigestMD + * Method: nativeClone + * Signature: (IJ)J + */ +JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeClone + (JNIEnv *env, jclass jcls, jint mech, jlong pContext) { + return JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone(mech, pContext); +} + +/* + * Class: com_oracle_security_ucrypto_NativeDigestMD + * Method: nativeFree + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeFree + (JNIEnv *env, jclass jcls, jint mech, jlong pContext) { + JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree(mech, pContext); +} + diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c index c1ee9027e92..2756977d09c 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c +++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c @@ -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 @@ -42,21 +42,33 @@ static const char SHA2_UPDATE[] = "SHA2Update"; static const char SHA2_FINAL[] = "SHA2Final"; static const char UCRYPTO_VERSION[] = "ucrypto_version"; static const char UCRYPTO_GET_MECHLIST[] = "ucrypto_get_mechlist"; + static const char UCRYPTO_ENCRYPT_INIT[] = "ucrypto_encrypt_init"; static const char UCRYPTO_ENCRYPT_UPDATE[] = "ucrypto_encrypt_update"; static const char UCRYPTO_ENCRYPT_FINAL[] = "ucrypto_encrypt_final"; static const char UCRYPTO_ENCRYPT[] = "ucrypto_encrypt"; + static const char UCRYPTO_DECRYPT_INIT[] = "ucrypto_decrypt_init"; static const char UCRYPTO_DECRYPT_UPDATE[] = "ucrypto_decrypt_update"; static const char UCRYPTO_DECRYPT_FINAL[] = "ucrypto_decrypt_final"; static const char UCRYPTO_DECRYPT[] = "ucrypto_decrypt"; + static const char UCRYPTO_SIGN_INIT[] = "ucrypto_sign_init"; static const char UCRYPTO_SIGN_UPDATE[] = "ucrypto_sign_update"; static const char UCRYPTO_SIGN_FINAL[] = "ucrypto_sign_final"; + static const char UCRYPTO_VERIFY_INIT[] = "ucrypto_verify_init"; static const char UCRYPTO_VERIFY_UPDATE[] = "ucrypto_verify_update"; static const char UCRYPTO_VERIFY_FINAL[] = "ucrypto_verify_final"; +static const char UCRYPTO_DIGEST_INIT[] = "ucrypto_digest_init"; +static const char UCRYPTO_DIGEST_UPDATE[] = "ucrypto_digest_update"; +static const char UCRYPTO_DIGEST_FINAL[] = "ucrypto_digest_final"; + +static const char UCRYPTO_FREE_CONTEXT[] = "ucrypto_free_context"; + +static const char UCRYPTO_STRERROR[] = "ucrypto_strerror"; + /** * Initialize native T4 crypto function pointers */ @@ -73,28 +85,6 @@ jboolean* loadNative() { return NULL; } - lib = dlopen("libmd.so", RTLD_NOW); - if (lib != NULL) { - ftab->md5Init = (MD5INIT_FN_PTR) dlsym(lib, MD5_INIT); - ftab->md5Update = (MD5UPDATE_FN_PTR) dlsym(lib, MD5_UPDATE); - ftab->md5Final = (MD5FINAL_FN_PTR) dlsym(lib, MD5_FINAL); - ftab->sha1Init = (SHA1INIT_FN_PTR) dlsym(lib, SHA1_INIT); - ftab->sha1Update = (SHA1UPDATE_FN_PTR) dlsym(lib, SHA1_UPDATE); - ftab->sha1Final = (SHA1FINAL_FN_PTR) dlsym(lib, SHA1_FINAL); - ftab->sha2Init = (SHA2INIT_FN_PTR) dlsym(lib, SHA2_INIT); - ftab->sha2Update = (SHA2UPDATE_FN_PTR) dlsym(lib, SHA2_UPDATE); - ftab->sha2Final = (SHA2FINAL_FN_PTR) dlsym(lib, SHA2_FINAL); - if (ftab->md5Init != NULL && ftab->md5Update != NULL && - ftab->md5Final != NULL && ftab->sha1Init != NULL && - ftab->sha1Update != NULL && ftab->sha1Final != NULL && - ftab->sha2Init != NULL && ftab->sha2Update != NULL && - ftab->sha2Final != NULL) { - buf[0] = JNI_TRUE; - } else { - dlclose(lib); - } - } - lib = dlopen("libsoftcrypto.so", RTLD_NOW); if (lib != NULL) { // These APIs aren't available for v0 lib on Solaris 10 @@ -102,7 +92,6 @@ jboolean* loadNative() { dlsym(lib, UCRYPTO_VERSION); ftab->ucryptoGetMechList = (UCRYPTO_GET_MECHLIST_FN_PTR) dlsym(lib, UCRYPTO_GET_MECHLIST); - //?? ftab->ucryptoSignInit = (UCRYPTO_SIGN_INIT_FN_PTR) dlsym(lib, UCRYPTO_SIGN_INIT); ftab->ucryptoSignUpdate = (UCRYPTO_SIGN_UPDATE_FN_PTR) @@ -116,6 +105,21 @@ jboolean* loadNative() { ftab->ucryptoVerifyFinal = (UCRYPTO_VERIFY_FINAL_FN_PTR) dlsym(lib, UCRYPTO_VERIFY_FINAL); + // These APS are added starting S12 + ftab->ucryptoDigestInit = (UCRYPTO_DIGEST_INIT_FN_PTR) + dlsym(lib, UCRYPTO_DIGEST_INIT); + ftab->ucryptoDigestUpdate = (UCRYPTO_DIGEST_UPDATE_FN_PTR) + dlsym(lib, UCRYPTO_DIGEST_UPDATE); + ftab->ucryptoDigestFinal = (UCRYPTO_DIGEST_FINAL_FN_PTR) + dlsym(lib, UCRYPTO_DIGEST_FINAL); + + ftab->ucryptoFreeContext = (UCRYPTO_FREE_CONTEXT_FN_PTR) + dlsym(lib, UCRYPTO_FREE_CONTEXT); + + ftab->ucryptoStrerror = (UCRYPTO_STRERROR_FN_PTR) + dlsym(lib, UCRYPTO_STRERROR); + + // These should be avilable for all libsoftcrypto libs ftab->ucryptoEncryptInit = (UCRYPTO_ENCRYPT_INIT_FN_PTR) dlsym(lib, UCRYPTO_ENCRYPT_INIT); @@ -147,6 +151,34 @@ jboolean* loadNative() { } else { dlclose(lib); } + + // proceed with libmd when libucrypto does not support digest operations + if (ftab->ucryptoDigestInit == NULL || + ftab->ucryptoDigestUpdate == NULL || + ftab->ucryptoDigestFinal == NULL) { + + lib = dlopen("libmd.so", RTLD_NOW); + if (lib != NULL) { + ftab->md5Init = (MD5INIT_FN_PTR) dlsym(lib, MD5_INIT); + ftab->md5Update = (MD5UPDATE_FN_PTR) dlsym(lib, MD5_UPDATE); + ftab->md5Final = (MD5FINAL_FN_PTR) dlsym(lib, MD5_FINAL); + ftab->sha1Init = (SHA1INIT_FN_PTR) dlsym(lib, SHA1_INIT); + ftab->sha1Update = (SHA1UPDATE_FN_PTR) dlsym(lib, SHA1_UPDATE); + ftab->sha1Final = (SHA1FINAL_FN_PTR) dlsym(lib, SHA1_FINAL); + ftab->sha2Init = (SHA2INIT_FN_PTR) dlsym(lib, SHA2_INIT); + ftab->sha2Update = (SHA2UPDATE_FN_PTR) dlsym(lib, SHA2_UPDATE); + ftab->sha2Final = (SHA2FINAL_FN_PTR) dlsym(lib, SHA2_FINAL); + if (ftab->md5Init != NULL && ftab->md5Update != NULL && + ftab->md5Final != NULL && ftab->sha1Init != NULL && + ftab->sha1Update != NULL && ftab->sha1Final != NULL && + ftab->sha2Init != NULL && ftab->sha2Update != NULL && + ftab->sha2Final != NULL) { + buf[0] = JNI_TRUE; + } else { + dlclose(lib); + } + } + } } return buf; diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h index d45272f9bab..5f3a9ba87e3 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h +++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h @@ -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 @@ -69,15 +69,12 @@ typedef int (*UCRYPTO_ENCRYPT_INIT_FN_PTR) (crypto_ctx_t *context, ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - typedef int (*UCRYPTO_ENCRYPT_UPDATE_FN_PTR) (crypto_ctx_t *context, uchar_t *in, size_t in_len, uchar_t *out, size_t *out_len); - typedef int (*UCRYPTO_ENCRYPT_FINAL_FN_PTR) (crypto_ctx_t *context, uchar_t *out, size_t *out_len); - typedef int (*UCRYPTO_ENCRYPT_FN_PTR) (ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len, uchar_t *in, @@ -87,15 +84,12 @@ typedef int (*UCRYPTO_DECRYPT_INIT_FN_PTR) (crypto_ctx_t *context, ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - typedef int (*UCRYPTO_DECRYPT_UPDATE_FN_PTR) (crypto_ctx_t *context, uchar_t *in, size_t in_len, uchar_t *out, size_t *out_len); - typedef int (*UCRYPTO_DECRYPT_FINAL_FN_PTR) (crypto_ctx_t *context, uchar_t *out, size_t *out_len); - typedef int (*UCRYPTO_DECRYPT_FN_PTR) (ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len, uchar_t *in, @@ -105,10 +99,8 @@ typedef int (*UCRYPTO_SIGN_INIT_FN_PTR) (crypto_ctx_t *context, ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - typedef int (*UCRYPTO_SIGN_UPDATE_FN_PTR) (crypto_ctx_t *context, uchar_t *data_str, size_t data_len); - typedef int (*UCRYPTO_SIGN_FINAL_FN_PTR) (crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len); @@ -116,13 +108,24 @@ typedef int (*UCRYPTO_VERIFY_INIT_FN_PTR) (crypto_ctx_t *context, ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len, void *iv, size_t iv_len); - typedef int (*UCRYPTO_VERIFY_UPDATE_FN_PTR) (crypto_ctx_t *context, uchar_t *data_str, size_t data_len); - typedef int (*UCRYPTO_VERIFY_FINAL_FN_PTR) (crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len); +typedef int (*UCRYPTO_DIGEST_INIT_FN_PTR) + (crypto_ctx_t *context, ucrypto_mech_t mech_type, + void *param, size_t param_len); +typedef int (*UCRYPTO_DIGEST_UPDATE_FN_PTR) + (crypto_ctx_t *context, const uchar_t *data, size_t data_len); +typedef int (*UCRYPTO_DIGEST_FINAL_FN_PTR) + (crypto_ctx_t *context, uchar_t *digest, size_t *digest_len); + +typedef void (*UCRYPTO_FREE_CONTEXT_FN_PTR) + (crypto_ctx_t *context); + +typedef char* (*UCRYPTO_STRERROR_FN_PTR)(int rv); + /* dynamically resolved functions from libmd, and libsoftcrypto @@ -153,6 +156,11 @@ typedef struct T4CRYPTO_FUNCTION_TABLE { UCRYPTO_VERIFY_INIT_FN_PTR ucryptoVerifyInit; UCRYPTO_VERIFY_UPDATE_FN_PTR ucryptoVerifyUpdate; UCRYPTO_VERIFY_FINAL_FN_PTR ucryptoVerifyFinal; + UCRYPTO_DIGEST_INIT_FN_PTR ucryptoDigestInit; + UCRYPTO_DIGEST_UPDATE_FN_PTR ucryptoDigestUpdate; + UCRYPTO_DIGEST_FINAL_FN_PTR ucryptoDigestFinal; + UCRYPTO_FREE_CONTEXT_FN_PTR ucryptoFreeContext; + UCRYPTO_STRERROR_FN_PTR ucryptoStrerror; } T4CRYPTO_FUNCTION_TABLE; typedef T4CRYPTO_FUNCTION_TABLE *T4CRYPTO_FUNCTION_TABLE_PTR; diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java index 2c9337d6404..9b7edac4d33 100644 --- a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java +++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java @@ -2498,6 +2498,12 @@ public class ConsoleReader //ignore } + if (o instanceof Runnable) { + ((Runnable) o).run(); + sb.setLength(0); + continue; + } + // Search mode. // // Note that we have to do this first, because if there is a command diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java new file mode 100644 index 00000000000..7e4bbbff6a4 --- /dev/null +++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jline.extra; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.function.Supplier; + +import jdk.internal.jline.console.ConsoleReader; +import jdk.internal.jline.console.KeyMap; +import jdk.internal.jline.console.history.History; +import jdk.internal.jline.console.history.History.Entry; +import jdk.internal.jline.console.history.MemoryHistory; + +/*Public for tests (HistoryTest). + */ +public abstract class EditingHistory implements History { + + private final History fullHistory; + private History currentDelegate; + + protected EditingHistory(ConsoleReader in, Iterable originalHistory) { + this.fullHistory = new MemoryHistory(); + this.currentDelegate = fullHistory; + bind(in, CTRL_UP, + (Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::previousSnippet)); + bind(in, CTRL_DOWN, + (Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::nextSnippet)); + load(originalHistory); + } + + private void moveHistoryToSnippet(ConsoleReader in, Supplier action) { + if (!action.get()) { + try { + in.beep(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } else { + try { + //could use: + //in.resetPromptLine(in.getPrompt(), in.getHistory().current().toString(), -1); + //but that would mean more re-writing on the screen, (and prints an additional + //empty line), so using setBuffer directly: + Method setBuffer = in.getClass().getDeclaredMethod("setBuffer", String.class); + + setBuffer.setAccessible(true); + setBuffer.invoke(in, in.getHistory().current().toString()); + in.flush(); + } catch (ReflectiveOperationException | IOException ex) { + throw new IllegalStateException(ex); + } + } + } + + private void bind(ConsoleReader in, String shortcut, Object action) { + KeyMap km = in.getKeys(); + for (int i = 0; i < shortcut.length(); i++) { + Object value = km.getBound(Character.toString(shortcut.charAt(i))); + if (value instanceof KeyMap) { + km = (KeyMap) value; + } else { + km.bind(shortcut.substring(i), action); + } + } + } + + private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP + private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN + + @Override + public int size() { + return currentDelegate.size(); + } + + @Override + public boolean isEmpty() { + return currentDelegate.isEmpty(); + } + + @Override + public int index() { + return currentDelegate.index(); + } + + @Override + public void clear() { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + currentDelegate.clear(); + } + + @Override + public CharSequence get(int index) { + return currentDelegate.get(index); + } + + @Override + public void add(CharSequence line) { + NarrowingHistoryLine currentLine = null; + int origIndex = fullHistory.index(); + int fullSize; + try { + fullHistory.moveToEnd(); + fullSize = fullHistory.index(); + if (currentDelegate == fullHistory) { + if (origIndex < fullHistory.index()) { + for (Entry entry : fullHistory) { + if (!(entry.value() instanceof NarrowingHistoryLine)) + continue; + int[] cluster = ((NarrowingHistoryLine) entry.value()).span; + if (cluster[0] == origIndex && cluster[1] > cluster[0]) { + currentDelegate = new MemoryHistory(); + for (int i = cluster[0]; i <= cluster[1]; i++) { + currentDelegate.add(fullHistory.get(i)); + } + } + } + } + } + fullHistory.moveToEnd(); + while (fullHistory.previous()) { + CharSequence c = fullHistory.current(); + if (c instanceof NarrowingHistoryLine) { + currentLine = (NarrowingHistoryLine) c; + break; + } + } + } finally { + fullHistory.moveTo(origIndex); + } + if (currentLine == null || currentLine.span[1] != (-1)) { + line = currentLine = new NarrowingHistoryLine(line, fullSize); + } + StringBuilder complete = new StringBuilder(); + for (int i = currentLine.span[0]; i < fullSize; i++) { + complete.append(fullHistory.get(i)); + } + complete.append(line); + if (isComplete(complete)) { + currentLine.span[1] = fullSize; //TODO: +1? + currentDelegate = fullHistory; + } + fullHistory.add(line); + } + + protected abstract boolean isComplete(CharSequence input); + + @Override + public void set(int index, CharSequence item) { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + currentDelegate.set(index, item); + } + + @Override + public CharSequence remove(int i) { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + return currentDelegate.remove(i); + } + + @Override + public CharSequence removeFirst() { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + return currentDelegate.removeFirst(); + } + + @Override + public CharSequence removeLast() { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + return currentDelegate.removeLast(); + } + + @Override + public void replace(CharSequence item) { + if (currentDelegate != fullHistory) + throw new IllegalStateException("narrowed"); + currentDelegate.replace(item); + } + + @Override + public ListIterator entries(int index) { + return currentDelegate.entries(index); + } + + @Override + public ListIterator entries() { + return currentDelegate.entries(); + } + + @Override + public Iterator iterator() { + return currentDelegate.iterator(); + } + + @Override + public CharSequence current() { + return currentDelegate.current(); + } + + @Override + public boolean previous() { + return currentDelegate.previous(); + } + + @Override + public boolean next() { + return currentDelegate.next(); + } + + @Override + public boolean moveToFirst() { + return currentDelegate.moveToFirst(); + } + + @Override + public boolean moveToLast() { + return currentDelegate.moveToLast(); + } + + @Override + public boolean moveTo(int index) { + return currentDelegate.moveTo(index); + } + + @Override + public void moveToEnd() { + currentDelegate.moveToEnd(); + } + + public boolean previousSnippet() { + for (int i = index() - 1; i >= 0; i--) { + if (get(i) instanceof NarrowingHistoryLine) { + moveTo(i); + return true; + } + } + + return false; + } + + public boolean nextSnippet() { + for (int i = index() + 1; i < size(); i++) { + if (get(i) instanceof NarrowingHistoryLine) { + moveTo(i); + return true; + } + } + + if (index() < size()) { + moveToEnd(); + return true; + } + + return false; + } + + public final void load(Iterable originalHistory) { + NarrowingHistoryLine currentHistoryLine = null; + boolean start = true; + int currentLine = 0; + for (String historyItem : originalHistory) { + StringBuilder line = new StringBuilder(historyItem); + int trailingBackSlashes = countTrailintBackslashes(line); + boolean continuation = trailingBackSlashes % 2 != 0; + line.delete(line.length() - trailingBackSlashes / 2 - (continuation ? 1 : 0), line.length()); + if (start) { + class PersistentNarrowingHistoryLine extends NarrowingHistoryLine implements PersistentEntryMarker { + public PersistentNarrowingHistoryLine(CharSequence delegate, int start) { + super(delegate, start); + } + } + fullHistory.add(currentHistoryLine = new PersistentNarrowingHistoryLine(line, currentLine)); + } else { + class PersistentLine implements CharSequence, PersistentEntryMarker { + private final CharSequence delegate; + public PersistentLine(CharSequence delegate) { + this.delegate = delegate; + } + @Override public int length() { + return delegate.length(); + } + @Override public char charAt(int index) { + return delegate.charAt(index); + } + @Override public CharSequence subSequence(int start, int end) { + return delegate.subSequence(start, end); + } + @Override public String toString() { + return delegate.toString(); + } + } + fullHistory.add(new PersistentLine(line)); + } + start = !continuation; + currentHistoryLine.span[1] = currentLine; + currentLine++; + } + } + + public Collection save() { + Collection result = new ArrayList<>(); + Iterator entries = fullHistory.iterator(); + + if (entries.hasNext()) { + Entry entry = entries.next(); + while (entry != null) { + StringBuilder historyLine = new StringBuilder(entry.value()); + int trailingBackSlashes = countTrailintBackslashes(historyLine); + for (int i = 0; i < trailingBackSlashes; i++) { + historyLine.append("\\"); + } + entry = entries.hasNext() ? entries.next() : null; + if (entry != null && !(entry.value() instanceof NarrowingHistoryLine)) { + historyLine.append("\\"); + } + result.add(historyLine.toString()); + } + } + + return result; + } + + private int countTrailintBackslashes(CharSequence text) { + int count = 0; + + for (int i = text.length() - 1; i >= 0; i--) { + if (text.charAt(i) == '\\') { + count++; + } else { + break; + } + } + + return count; + } + + public List currentSessionEntries() { + List result = new ArrayList<>(); + + for (Entry e : fullHistory) { + if (!(e.value() instanceof PersistentEntryMarker)) { + result.add(e.value().toString()); + } + } + + return result; + } + + public void fullHistoryReplace(String source) { + fullHistory.replace(source); + } + + private class NarrowingHistoryLine implements CharSequence { + private final CharSequence delegate; + private final int[] span; + + public NarrowingHistoryLine(CharSequence delegate, int start) { + this.delegate = delegate; + this.span = new int[] {start, -1}; + } + + @Override + public int length() { + return delegate.length(); + } + + @Override + public char charAt(int index) { + return delegate.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return delegate.subSequence(start, end); + } + + @Override + public String toString() { + return delegate.toString(); + } + + } + + private interface PersistentEntryMarker {} +} + diff --git a/jdk/src/jdk.internal.le/share/classes/module-info.java b/jdk/src/jdk.internal.le/share/classes/module-info.java index b4ae508ac6e..d52b3b5f98d 100644 --- a/jdk/src/jdk.internal.le/share/classes/module-info.java +++ b/jdk/src/jdk.internal.le/share/classes/module-info.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 @@ -36,6 +36,9 @@ module jdk.internal.le { exports jdk.internal.jline.console.history to jdk.scripting.nashorn.shell, jdk.jshell; + exports jdk.internal.jline.extra to + jdk.scripting.nashorn.shell, + jdk.jshell; exports jdk.internal.jline.internal to jdk.scripting.nashorn.shell, jdk.jshell; diff --git a/jdk/src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProvider.java b/jdk/src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProvider.java deleted file mode 100644 index 55be308348a..00000000000 --- a/jdk/src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.vm.agent.spi; - -/** - * Service interface for jdk.hotspot.agent to provide the tools that - * jstack, jmap, jinfo will invoke, if present. - */ -public interface ToolProvider { - /** - * Returns the name of the tool provider - */ - String getName(); - - /** - * Invoke the tool provider with the given arguments - */ - void run(String... arguments); -} diff --git a/jdk/src/jdk.jcmd/share/classes/module-info.java b/jdk/src/jdk.jcmd/share/classes/module-info.java index 4b8dbce1304..c78803b774c 100644 --- a/jdk/src/jdk.jcmd/share/classes/module-info.java +++ b/jdk/src/jdk.jcmd/share/classes/module-info.java @@ -26,9 +26,4 @@ module jdk.jcmd { requires jdk.attach; requires jdk.jvmstat; - - exports jdk.internal.vm.agent.spi to jdk.hotspot.agent; - - uses jdk.internal.vm.agent.spi.ToolProvider; } - diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java new file mode 100644 index 00000000000..e08b11d6cb5 --- /dev/null +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java @@ -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. + */ + +package sun.tools.common; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.MonitoredVmUtil; +import sun.jvmstat.monitor.VmIdentifier; + +/** + * Class for finding process matching a process argument, + * excluding tool it self and returning a list containing + * the process identifiers. + */ +public class ProcessArgumentMatcher { + private String excludeCls; + private String matchClass = null; + private String singlePid = null; + private boolean matchAll = false; + + public ProcessArgumentMatcher(String pidArg, Class excludeClass) { + excludeCls = excludeClass.getName(); + if (pidArg == null || pidArg.isEmpty()) { + throw new IllegalArgumentException("Pid string is invalid"); + } + if (pidArg.charAt(0) == '-') { + throw new IllegalArgumentException("Unrecognized " + pidArg); + } + try { + long pid = Long.parseLong(pidArg); + if (pid == 0) { + matchAll = true; + } else { + singlePid = String.valueOf(pid); + } + } catch (NumberFormatException nfe) { + matchClass = pidArg; + } + } + + private boolean check(VirtualMachineDescriptor vmd) { + String mainClass = null; + try { + VmIdentifier vmId = new VmIdentifier(vmd.id()); + MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId); + MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1); + mainClass = MonitoredVmUtil.mainClass(monitoredVm, true); + monitoredHost.detach(monitoredVm); + } catch (NullPointerException npe) { + // There is a potential race, where a running java app is being + // queried, unfortunately the java app has shutdown after this + // method is started but before getMonitoredVM is called. + // If this is the case, then the /tmp/hsperfdata_xxx/pid file + // will have disappeared and we will get a NullPointerException. + // Handle this gracefully.... + return false; + } catch (MonitorException | URISyntaxException e) { + if (e.getMessage() != null) { + System.err.println(e.getMessage()); + } else { + Throwable cause = e.getCause(); + if ((cause != null) && (cause.getMessage() != null)) { + System.err.println(cause.getMessage()); + } else { + e.printStackTrace(); + } + } + return false; + } + + if (mainClass.equals(excludeCls)) { + return false; + } + + if (matchAll || mainClass.indexOf(matchClass) != -1) { + return true; + } + + return false; + } + + public Collection getPids() { + Collection pids = new ArrayList<>(); + if (singlePid != null) { + pids.add(singlePid); + return pids; + } + List vmds = VirtualMachine.list(); + for (VirtualMachineDescriptor vmd : vmds) { + if (check(vmd)) { + pids.add(vmd.id()); + } + } + return pids; + } +} diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java index fbd4ca9aae4..80708f5aa37 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java @@ -33,16 +33,14 @@ class Arguments { private boolean listProcesses = false; private boolean listCounters = false; private boolean showUsage = false; - private int pid = -1; private String command = null; - private String processSubstring; + private String processString = null; public boolean isListProcesses() { return listProcesses; } public boolean isListCounters() { return listCounters; } public boolean isShowUsage() { return showUsage; } - public int getPid() { return pid; } public String getCommand() { return command; } - public String getProcessSubstring() { return processSubstring; } + public String getProcessString() { return processString; } public Arguments(String[] args) { if (args.length == 0 || args[0].equals("-l")) { @@ -55,15 +53,7 @@ class Arguments { return; } - try { - pid = Integer.parseInt(args[0]); - } catch (NumberFormatException ex) { - // use as a partial class-name instead - if (args[0].charAt(0) != '-') { - // unless it starts with a '-' - processSubstring = args[0]; - } - } + processString = args[0]; StringBuilder sb = new StringBuilder(); for (int i = 1; i < args.length; i++) { diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java index 0ff46323ec6..ab77547a077 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java @@ -29,22 +29,22 @@ import java.io.InputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.List; -import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.net.URISyntaxException; import com.sun.tools.attach.AttachOperationFailedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; -import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import sun.tools.attach.HotSpotVirtualMachine; +import sun.tools.common.ProcessArgumentMatcher; import sun.tools.jstat.JStatLogger; import sun.jvmstat.monitor.Monitor; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.VmIdentifier; @@ -73,52 +73,18 @@ public class JCmd { System.exit(0); } - List pids = new ArrayList(); - if (arg.getPid() == 0) { - // find all VMs - List vmds = VirtualMachine.list(); - for (VirtualMachineDescriptor vmd : vmds) { - if (!isJCmdProcess(vmd)) { - pids.add(vmd.id()); - } - } - } else if (arg.getProcessSubstring() != null) { - // use the partial class-name match - List vmds = VirtualMachine.list(); - for (VirtualMachineDescriptor vmd : vmds) { - if (isJCmdProcess(vmd)) { - continue; - } - try { - String mainClass = getMainClass(vmd); - if (mainClass != null - && mainClass.indexOf(arg.getProcessSubstring()) != -1) { - pids.add(vmd.id()); - } - } catch (MonitorException|URISyntaxException e) { - if (e.getMessage() != null) { - System.err.println(e.getMessage()); - } else { - Throwable cause = e.getCause(); - if ((cause != null) && (cause.getMessage() != null)) { - System.err.println(cause.getMessage()); - } else { - e.printStackTrace(); - } - } - } - } - if (pids.isEmpty()) { - System.err.println("Could not find any processes matching : '" - + arg.getProcessSubstring() + "'"); - System.exit(1); - } - } else if (arg.getPid() == -1) { + Collection pids = Collections.emptyList(); + try { + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(arg.getProcessString(), JCmd.class); + pids = ap.getPids(); + } catch (IllegalArgumentException iae) { System.err.println("Invalid pid specified"); System.exit(1); - } else { - // Use the found pid - pids.add(arg.getPid() + ""); + } + if (pids.isEmpty()) { + System.err.println("Could not find any processes matching : '" + + arg.getProcessString() + "'"); + System.exit(1); } boolean success = true; @@ -199,36 +165,6 @@ public class JCmd { } } - private static boolean isJCmdProcess(VirtualMachineDescriptor vmd) { - try { - String mainClass = getMainClass(vmd); - return mainClass != null && mainClass.equals(JCmd.class.getName()); - } catch (URISyntaxException|MonitorException ex) { - return false; - } - } - - private static String getMainClass(VirtualMachineDescriptor vmd) - throws URISyntaxException, MonitorException { - try { - String mainClass = null; - VmIdentifier vmId = new VmIdentifier(vmd.id()); - MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId); - MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1); - mainClass = MonitoredVmUtil.mainClass(monitoredVm, true); - monitoredHost.detach(monitoredVm); - return mainClass; - } catch(NullPointerException e) { - // There is a potential race, where a running java app is being - // queried, unfortunately the java app has shutdown after this - // method is started but before getMonitoredVM is called. - // If this is the case, then the /tmp/hsperfdata_xxx/pid file - // will have disappeared and we will get a NullPointerException. - // Handle this gracefully.... - return null; - } - } - /** * Class to compare two Monitor objects by name in ascending order. * (from jstat) diff --git a/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java b/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java index f19b6d159f0..ca774122a17 100644 --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java @@ -25,15 +25,14 @@ package sun.tools.jinfo; -import java.util.Arrays; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import com.sun.tools.attach.VirtualMachine; import sun.tools.attach.HotSpotVirtualMachine; -import jdk.internal.vm.agent.spi.ToolProvider; -import jdk.internal.vm.agent.spi.ToolProviderFinder; +import sun.tools.common.ProcessArgumentMatcher; /* * This class is the main class for the JInfo utility. It parses its arguments @@ -41,155 +40,94 @@ import jdk.internal.vm.agent.spi.ToolProviderFinder; * or an SA tool. */ final public class JInfo { - private static final String SA_JINFO_TOOL_NAME = "jinfo"; - private boolean useSA = false; - private String[] args = null; - - private JInfo(String[] args) throws IllegalArgumentException { - if (args.length == 0) { - throw new IllegalArgumentException(); - } - - int argCopyIndex = 0; - // First determine if we should launch SA or not - if (args[0].equals("-F")) { - // delete the -F - argCopyIndex = 1; - useSA = true; - } else if (args[0].equals("-flags") - || args[0].equals("-sysprops")) - { - if (args.length == 2) { - if (!isPid(args[1])) { - // If args[1] doesn't parse to a number then - // it must be the SA debug server - // (otherwise it is the pid) - useSA = true; - } - } else if (args.length == 3) { - // arguments include an executable and a core file - useSA = true; - } else { - throw new IllegalArgumentException(); - } - } else if (!args[0].startsWith("-")) { - if (args.length == 2) { - // the only arguments are an executable and a core file - useSA = true; - } else if (args.length == 1) { - if (!isPid(args[0])) { - // The only argument is not a PID; it must be SA debug - // server - useSA = true; - } - } else { - throw new IllegalArgumentException(); - } - } else if (args[0].equals("-h") || args[0].equals("-help")) { - if (args.length > 1) { - throw new IllegalArgumentException(); - } - } else if (args[0].equals("-flag")) { - if (args.length == 3) { - if (!isPid(args[2])) { - throw new IllegalArgumentException(); - } - } else { - throw new IllegalArgumentException(); - } - } else { - throw new IllegalArgumentException(); - } - - this.args = Arrays.copyOfRange(args, argCopyIndex, args.length); - } - - @SuppressWarnings("fallthrough") - private void execute() throws Exception { - if (args[0].equals("-h") - || args[0].equals("-help")) { - usage(0); - } - - if (useSA) { - // SA only supports -flags or -sysprops - if (args[0].startsWith("-")) { - if (!(args[0].equals("-flags") || args[0].equals("-sysprops"))) { - usage(1); - } - } - - // invoke SA which does it's own argument parsing - runTool(); - - } else { - // Now we can parse arguments for the non-SA case - String pid = null; - - switch(args[0]) { - case "-flag": - if (args.length != 3) { - usage(1); - } - String option = args[1]; - pid = args[2]; - flag(pid, option); - break; - case "-flags": - if (args.length != 2) { - usage(1); - } - pid = args[1]; - flags(pid); - break; - case "-sysprops": - if (args.length != 2) { - usage(1); - } - pid = args[1]; - sysprops(pid); - break; - case "-help": - case "-h": - usage(0); - // Fall through - default: - if (args.length == 1) { - // no flags specified, we do -sysprops and -flags - pid = args[0]; - sysprops(pid); - System.out.println(); - flags(pid); - System.out.println(); - commandLine(pid); - } else { - usage(1); - } - } - } - } public static void main(String[] args) throws Exception { - JInfo jinfo = null; - try { - jinfo = new JInfo(args); - jinfo.execute(); - } catch (IllegalArgumentException e) { + if (args.length == 0) { + usage(1); // no arguments + } + checkForUnsupportedOptions(args); + + boolean doFlag = false; + boolean doFlags = false; + boolean doSysprops = false; + + // Parse the options (arguments starting with "-" ) + int optionCount = 0; + while (optionCount < args.length) { + String arg = args[optionCount]; + if (!arg.startsWith("-")) { + break; + } + + optionCount++; + + if (arg.equals("-help") || arg.equals("-h")) { + usage(0); + } + + if (arg.equals("-flag")) { + doFlag = true; + continue; + } + + if (arg.equals("-flags")) { + doFlags = true; + continue; + } + + if (arg.equals("-sysprops")) { + doSysprops = true; + continue; + } + } + + // Next we check the parameter count. -flag allows extra parameters + int paramCount = args.length - optionCount; + if ((doFlag && paramCount != 2) || ((!doFlag && paramCount != 1))) { usage(1); } - } - private static boolean isPid(String arg) { - return arg.matches("[0-9]+"); - } - - // Invoke SA tool with the given arguments - private void runTool() throws Exception { - ToolProvider tool = ToolProviderFinder.find(SA_JINFO_TOOL_NAME); - if (tool == null) { - usage(1); + if (!doFlag && !doFlags && !doSysprops) { + // Print flags and sysporps if no options given + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + sysprops(pid); + System.out.println(); + flags(pid); + System.out.println(); + commandLine(pid); + } + } + + if (doFlag) { + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount+1], JInfo.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + flag(pid, args[optionCount]); + } + } + else if (doFlags || doSysprops) { + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + if (doFlags) { + flags(pid); + } + else if (doSysprops) { + sysprops(pid); + } + } } - tool.run(args); } private static void flag(String pid, String option) throws IOException { @@ -274,46 +212,49 @@ final public class JInfo { vm.detach(); } + private static void checkForUnsupportedOptions(String[] args) { + // Check arguments for -F, and non-numeric value + // and warn the user that SA is not supported anymore + int maxCount = 1; + int paramCount = 0; - // print usage message - private static void usage(int exit) { - boolean usageSA = ToolProviderFinder.find(SA_JINFO_TOOL_NAME) != null; - - System.err.println("Usage:"); - if (usageSA) { - System.err.println(" jinfo [option] "); - System.err.println(" (to connect to a running process)"); - System.err.println(" jinfo -F [option] "); - System.err.println(" (to connect to a hung process)"); - System.err.println(" jinfo [option] "); - System.err.println(" (to connect to a core file)"); - System.err.println(" jinfo [option] [server_id@]"); - System.err.println(" (to connect to remote debug server)"); - System.err.println(""); - System.err.println("where