This commit is contained in:
Alejandro Murillo 2016-05-20 11:30:52 -07:00
commit ef493e2be1
587 changed files with 18390 additions and 48713 deletions

View File

@ -1,5 +1,6 @@
^build/ ^build/
^dist/ ^dist/
^.idea/
nbproject/private/ nbproject/private/
^webrev ^webrev
^.hgtip ^.hgtip

View File

@ -360,3 +360,4 @@ c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114
8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115 8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115
84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116 84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116
82b8d12a553f5617737c238cec060281d52e351c jdk-9+117 82b8d12a553f5617737c238cec060281d52e351c jdk-9+117
7c04fcb12bd4a31570a238e663fa846dfa5ec3b8 jdk-9+118

View File

@ -360,3 +360,4 @@ f900d5afd9c83a0df8f36161c27c5e4c86a66f4c jdk-9+111
09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115 09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115
6743a8e0cab7b5f6f4a0575f6664892f0ab740af jdk-9+116 6743a8e0cab7b5f6f4a0575f6664892f0ab740af jdk-9+116
e882bcdbdac436523f3d5681611d3118a3804ea7 jdk-9+117 e882bcdbdac436523f3d5681611d3118a3804ea7 jdk-9+117
047f95de8f918d8ff5e8cd2636a2abb5c3c8adb8 jdk-9+118

View File

@ -768,7 +768,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
$2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing"
;; ;;
esac 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 elif test "x$TOOLCHAIN_TYPE" = xclang; then
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_GNU_SOURCE" $2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_GNU_SOURCE"
@ -964,7 +964,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
-Wunused-value -Woverloaded-virtual" -Wunused-value -Woverloaded-virtual"
if test "x$TOOLCHAIN_TYPE" = xgcc; then 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: [ IF_AT_LEAST: [
# These flags either do not work or give spurious warnings prior to gcc 4.8. # 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" $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= DISABLE_WARNING_PREFIX=
fi fi
CFLAGS_WARNINGS_ARE_ERRORS="-Werror" 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" CC_OLD="$CC"
CXX_OLD="$CXX"
CC="$BUILD_CC" CC="$BUILD_CC"
CXX="$BUILD_CXX"
CFLAGS_OLD="$CFLAGS"
CFLAGS=""
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [-Wno-this-is-a-warning-that-do-not-exist], FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [-Wno-this-is-a-warning-that-do-not-exist],
IF_TRUE: [BUILD_CC_CAN_DISABLE_WARNINGS=true], IF_TRUE: [BUILD_CC_CAN_DISABLE_WARNINGS=true],
IF_FALSE: [BUILD_CC_CAN_DISABLE_WARNINGS=false] 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= BUILD_CC_DISABLE_WARNING_PREFIX=
fi fi
CC="$CC_OLD" CC="$CC_OLD"
CXX="$CXX_OLD"
CFLAGS="$CFLAGS_OLD"
;; ;;
clang) clang)
DISABLE_WARNING_PREFIX="-Wno-" DISABLE_WARNING_PREFIX="-Wno-"

View File

@ -4900,6 +4900,8 @@ TOOLCHAIN_MINIMUM_VERSION_xlc=""
# Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called. # Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called.
# Must have CC_VERSION_NUMBER and CXX_VERSION_NUMBER. # 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 # 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 # 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_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 (<) # 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 #CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks: # 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 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:${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 has different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER." >&2;} $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:${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;} $as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not supported" >&2;}
fi fi
# We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. # 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:${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;} $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 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:${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;} $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
fi 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 fi
# #
@ -46475,6 +46487,268 @@ $as_echo "$as_me: Rewriting BUILD_STRIP to \"$new_complete\"" >&6;}
BUILD_LDCXX="$BUILD_CXX" BUILD_LDCXX="$BUILD_CXX"
PATH="$OLDPATH" 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 else
# If we are not cross compiling, use the normal target compilers for # If we are not cross compiling, use the normal target compilers for
# building the build platform executables. # 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 elif test "x$TOOLCHAIN_TYPE" = xclang; then
JVM_CFLAGS="$JVM_CFLAGS -D_GNU_SOURCE" JVM_CFLAGS="$JVM_CFLAGS -D_GNU_SOURCE"
@ -49935,6 +50223,18 @@ $as_echo "$supports" >&6; }
@ -49987,6 +50287,8 @@ $as_echo "$supports" >&6; }
fi fi
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
# Non-zero builds have stricter warnings # 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 # 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"` 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 else
@ -50488,6 +50802,8 @@ $as_echo "$supports" >&6; }
elif test "x$TOOLCHAIN_TYPE" = xclang; then elif test "x$TOOLCHAIN_TYPE" = xclang; then
OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_GNU_SOURCE" 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 # 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"` 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. # These flags either do not work or give spurious warnings prior to gcc 4.8.
@ -50764,6 +51092,8 @@ $as_echo "$supports" >&6; }
fi fi
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
# Non-zero builds have stricter warnings # Non-zero builds have stricter warnings
@ -51918,9 +52248,15 @@ $as_echo "$supports" >&6; }
DISABLE_WARNING_PREFIX= DISABLE_WARNING_PREFIX=
fi fi
CFLAGS_WARNINGS_ARE_ERRORS="-Werror" 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" CC_OLD="$CC"
CXX_OLD="$CXX"
CC="$BUILD_CC" CC="$BUILD_CC"
CXX="$BUILD_CXX"
CFLAGS_OLD="$CFLAGS"
CFLAGS=""
@ -52198,6 +52534,8 @@ $as_echo "$supports" >&6; }
BUILD_CC_DISABLE_WARNING_PREFIX= BUILD_CC_DISABLE_WARNING_PREFIX=
fi fi
CC="$CC_OLD" CC="$CC_OLD"
CXX="$CXX_OLD"
CFLAGS="$CFLAGS_OLD"
;; ;;
clang) clang)
DISABLE_WARNING_PREFIX="-Wno-" DISABLE_WARNING_PREFIX="-Wno-"

View File

@ -59,23 +59,25 @@ TOOLCHAIN_MINIMUM_VERSION_xlc=""
# Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called. # Prepare the system so that TOOLCHAIN_CHECK_COMPILER_VERSION can be called.
# Must have CC_VERSION_NUMBER and CXX_VERSION_NUMBER. # 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], AC_DEFUN([TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS],
[ [
if test "x$CC_VERSION_NUMBER" != "x$CXX_VERSION_NUMBER"; then if test "x[$]$1CC_VERSION_NUMBER" != "x[$]$1CXX_VERSION_NUMBER"; then
AC_MSG_WARN([C and C++ compiler has different version numbers, $CC_VERSION_NUMBER vs $CXX_VERSION_NUMBER.]) 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]) AC_MSG_WARN([This typically indicates a broken setup, and is not supported])
fi fi
# We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
if [ [[ "$CC_VERSION_NUMBER" =~ (.*\.){3} ]] ]; then if [ [[ "[$]$1CC_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.]) AC_MSG_WARN([C compiler version number has more than three parts (X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
fi fi
if [ [[ "$CC_VERSION_NUMBER" =~ [0-9]{6} ]] ]; then if [ [[ "[$]$1CC_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.]) AC_MSG_WARN([C compiler version number has a part larger than 99999: [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
fi 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 # 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 # 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_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 (<) # 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], 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 []. # Need to assign to a variable since m4 is blocked from modifying parts in [].
REFERENCE_VERSION=ARG_VERSION 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 # 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"` 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 ARG_IF_AT_LEAST
else else
@ -808,6 +811,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
BUILD_LDCXX="$BUILD_CXX" BUILD_LDCXX="$BUILD_CXX"
PATH="$OLDPATH" 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 else
# If we are not cross compiling, use the normal target compilers for # If we are not cross compiling, use the normal target compilers for
# building the build platform executables. # building the build platform executables.

199
common/bin/idea.sh Normal file
View File

@ -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 <path>] [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=" <sourceFolder url=\"file://\$MODULE_DIR\$/####\" isTestSource=\"false\" />"
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 "^ .* <sourceFolder.*####" > /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 "^ .* <excludeFolder.*####" > /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=" <property name=\"module.name\" value=\"####\" />"
addModuleName() {
mn="`echo "$MODULE_NAME" | sed -e s@"\(.*\)####\(.*\)"@"\1$MODULE_NAMES\2"@`"
printf "%s\n" "$mn" >> $IDEA_ANT
}
BUILD_DIR=" <property name=\"build.target.dir\" value=\"####\" />"
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 "^ .* <property name=\"module.name\"" > /dev/null ; then
addModuleName
elif echo "$line" | egrep "^ .* <property name=\"build.target.dir\"" > /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

View File

@ -89,7 +89,7 @@ install_jib() {
fi fi
if command -v curl > /dev/null; then 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 elif command -v wget > /dev/null; then
getcmd="wget --quiet -O -" getcmd="wget --quiet -O -"
else else

View File

@ -360,3 +360,4 @@ cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113
7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115 7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115
7dfa7377a5e601b8f740741a9a80e04c72dd04d6 jdk-9+116 7dfa7377a5e601b8f740741a9a80e04c72dd04d6 jdk-9+116
7a1b36bf2fe55a9a7732489ccdd326c910329a7e jdk-9+117 7a1b36bf2fe55a9a7732489ccdd326c910329a7e jdk-9+117
8c2c2d17f7ce92a31c9ccb44a122ec62f5a85ace jdk-9+118

View File

@ -520,3 +520,4 @@ b64432bae5271735fd53300b2005b713e98ef411 jdk-9+114
88dd08d7be0fe7fb9f1914b1628f0aae9bf56e25 jdk-9+115 88dd08d7be0fe7fb9f1914b1628f0aae9bf56e25 jdk-9+115
61a214186dae6811dd989e9165e42f7dbf02acde jdk-9+116 61a214186dae6811dd989e9165e42f7dbf02acde jdk-9+116
88170d3642905b9e6cac03e8efcc976885a7e6da jdk-9+117 88170d3642905b9e6cac03e8efcc976885a7e6da jdk-9+117
9b1075cac08dc836ec32e7b368415cbe3aceaf8c jdk-9+118

View File

@ -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 (!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 // Return the first user-defined class loader up the execution stack, or null
// if only code from the null class loader is on the stack. // if only code from the bootstrap or platform class loader is on the stack.
JVM_ENTRY(jobject, JVM_LatestUserDefinedLoader(JNIEnv *env)) JVM_ENTRY(jobject, JVM_LatestUserDefinedLoader(JNIEnv *env))
for (vframeStream vfst(thread); !vfst.at_end(); vfst.next()) { for (vframeStream vfst(thread); !vfst.at_end(); vfst.next()) {
vfst.skip_reflection_related_frames(); // Only needed for 1.4 reflection vfst.skip_reflection_related_frames(); // Only needed for 1.4 reflection
oop loader = vfst.method()->method_holder()->class_loader(); 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); return JNIHandles::make_local(env, loader);
} }
} }

View File

@ -120,24 +120,33 @@ endif
TEST_ROOT := $(shell pwd) TEST_ROOT := $(shell pwd)
# Root of all test results # Root of all test results
ifdef ALT_OUTPUTDIR ifdef TEST_OUTPUT_DIR
ABS_BUILD_ROOT = $(ALT_OUTPUTDIR) $(shell $(MKDIR) -p $(TEST_OUTPUT_DIR)/jtreg)
ABS_TEST_OUTPUT_DIR := \
$(shell $(CD) $(TEST_OUTPUT_DIR)/jtreg && $(PWD))
else 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 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) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
ifndef PRODUCT_HOME ifndef PRODUCT_HOME
# Try to use j2sdk-image if it exists # Try to use images/jdk if it exists
ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/jdk
PRODUCT_HOME := \ PRODUCT_HOME := \
$(shell \ $(shell \
if [ -d $(ABS_JDK_IMAGE) ] ; then \ if [ -d $(ABS_JDK_IMAGE) ] ; then \
$(ECHO) "$(ABS_JDK_IMAGE)"; \ $(ECHO) "$(ABS_JDK_IMAGE)"; \
else \ else \
$(ECHO) "$(ABS_BUILD_ROOT)" ; \ $(ECHO) "$(ABS_PLATFORM_BUILD_ROOT)"; \
fi) fi)
PRODUCT_HOME := $(PRODUCT_HOME)
endif endif
# Expect JPRT to set JAVA_ARGS (e.g. -server etc.) # Expect JPRT to set JAVA_ARGS (e.g. -server etc.)

View File

@ -360,3 +360,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103
1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115 1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115
9d71d20e614777cd23c1a43b38b5c08a9094d27a jdk-9+116 9d71d20e614777cd23c1a43b38b5c08a9094d27a jdk-9+116
46b57560cd06ebcdd21489250628ff5f9d9d8916 jdk-9+117 46b57560cd06ebcdd21489250628ff5f9d9d8916 jdk-9+117
a8aa25fc6c5fda0ed7a93b8ffee62da326a752fc jdk-9+118

View File

@ -3387,7 +3387,6 @@ included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
Apache Commons Math 2.2 Apache Commons Math 2.2
Apache Derby 10.10.1.2 [included with JDK 8] Apache Derby 10.10.1.2 [included with JDK 8]
Apache Jakarta BCEL 5.2 Apache Jakarta BCEL 5.2
Apache Jakarta Regexp 1.4
Apache Santuario XML Security for Java 1.5.4 Apache Santuario XML Security for Java 1.5.4
Apache Xalan-Java 2.7.1 Apache Xalan-Java 2.7.1
Apache Xerces Java 2.10.0 Apache Xerces Java 2.10.0

View File

@ -4,64 +4,29 @@
*/ */
package com.sun.org.apache.bcel.internal.util; 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 * http://www.apache.org/licenses/LICENSE-2.0
* reserved.
* *
* Redistribution and use in source and binary forms, with or without * Unless required by applicable law or agreed to in writing, software
* modification, are permitted provided that the following conditions * distributed under the License is distributed on an "AS IS" BASIS,
* are met: * 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
* <http://www.apache.org/>.
*/ */
import java.util.*;
import com.sun.org.apache.bcel.internal.Constants; import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.generic.*; 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, * InstructionFinder is a tool to search for given instructions patterns,
@ -231,28 +196,22 @@ public class InstructionFinder {
if(start == -1) if(start == -1)
throw new ClassGenException("Instruction handle " + from + throw new ClassGenException("Instruction handle " + from +
" not found in instruction list."); " 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)) { Pattern regex = Pattern.compile(search);
int startExpr = regex.getParenStart(0); List<InstructionHandle[]> matches = new ArrayList<>();
int endExpr = regex.getParenEnd(0); Matcher matcher = regex.matcher(il_string);
int lenExpr = regex.getParenLength(0); 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);
if((constraint == null) || constraint.checkCode(match)) start = endExpr;
matches.add(match);
start = endExpr;
}
return matches.iterator();
} catch(RESyntaxException e) {
System.err.println(e);
} }
return null; return matches.iterator();
} }
/** /**

View File

@ -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 <a href="mailto:ales.novak@netbeans.com">Ales Novak</a>
*/
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 <tt>true</tt> iff if the specified index is after the end of the character stream */
public boolean isEnd(int pos)
{
return (pos >= len);
}
}

View File

@ -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 <a href="mailto:ales.novak@netbeans.com">Ales Novak</a>
*/
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 <tt>true</tt> iff if the specified index is after the end of the character stream */
boolean isEnd(int pos);
}

View File

@ -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 <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
*/
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("");
}
}
}

View File

@ -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 <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
*/
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;
}
}
}
}
}

View File

@ -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 <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
* @author <a href="mailto:gholam@xtra.co.nz>Michael McCallum</a>
*/
public class RESyntaxException extends RuntimeException
{
/**
* Constructor.
* @param s Further description of the syntax error
*/
public RESyntaxException(String s)
{
super("Syntax error: " + s);
}
}

View File

@ -1,883 +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.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.StringBufferInputStream;
import java.io.StringReader;
import java.io.IOException;
/**
* Data driven (and optionally interactive) testing harness to exercise regular
* expression compiler and matching engine.
*
* @author <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
* @author <a href="mailto:gholam@xtra.co.nz">Michael McCallum</a>
*/
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<a href=\"$0\">$0</a>", RE.REPLACE_BACKREFERENCES);
assertEquals("Wrong subst() result", "visit us: 1234<a href=\"http://www.apache.org\">http://www.apache.org</a>!", 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 <code>BufferedReader</code> 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 <code>BufferedReader</code> 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);
}
}
}

View File

@ -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 <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
*/
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);
}
}

View File

@ -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 <a href="mailto:ales.novak@netbeans.com">Ales Novak</a>
*/
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 <tt>true</tt> 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());
}
}

View File

@ -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 <a href="mailto:ales.novak@netbeans.com">Ales Novak</a>
*/
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 <tt>true</tt> 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());
}
}

View File

@ -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 <a href="mailto:ales.novak@netbeans.com">Ales Novak</a>
*/
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 <tt>true</tt> iff if the specified index is after the end of the character stream */
public boolean isEnd(int pos)
{
return (pos >= src.length());
}
}

View File

@ -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>
*
* // 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);
*
* </pre>
*
* 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:
*
* <pre>
*
* RE r = new RE(re1);
*
* </pre>
*
* @see RE
* @see RECompiler
*
* @author <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
*/
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 <patternname> <pattern>");
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());
}
}
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * Writes XML content to underlying writer. Escapes characters unless
* escaping character feature is turned off. * escaping character feature is turned off.
@ -1368,10 +1377,14 @@ public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamW
if (fEncoder != null && !fEncoder.canEncode(ch)){ if (fEncoder != null && !fEncoder.canEncode(ch)){
fWriter.write(content, startWritePos, index - startWritePos ); fWriter.write(content, startWritePos, index - startWritePos );
// Escape this char as underlying encoder cannot handle it // Check if current and next characters forms a surrogate pair
fWriter.write( "&#x" ); // and escape it to avoid generation of invalid xml content
fWriter.write(Integer.toHexString(ch)); if ( index != end - 1 && Character.isSurrogatePair(ch, content[index+1])) {
fWriter.write( ';' ); writeCharRef(Character.toCodePoint(ch, content[index+1]));
index++;
} else {
writeCharRef(ch);
}
startWritePos = index + 1; startWritePos = index + 1;
continue; continue;
} }
@ -1439,10 +1452,15 @@ public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamW
if (fEncoder != null && !fEncoder.canEncode(ch)){ if (fEncoder != null && !fEncoder.canEncode(ch)){
fWriter.write(content, startWritePos, index - startWritePos ); fWriter.write(content, startWritePos, index - startWritePos );
// Escape this char as underlying encoder cannot handle it // Check if current and next characters forms a surrogate pair
fWriter.write( "&#x" ); // and escape it to avoid generation of invalid xml content
fWriter.write(Integer.toHexString(ch)); if ( index != end - 1 && Character.isSurrogatePair(ch, content.charAt(index+1))) {
fWriter.write( ';' ); writeCharRef(Character.toCodePoint(ch, content.charAt(index+1)));
index++;
} else {
writeCharRef(ch);
}
startWritePos = index + 1; startWritePos = index + 1;
continue; continue;
} }

View File

@ -86,5 +86,6 @@ module java.xml {
uses javax.xml.transform.TransformerFactory; uses javax.xml.transform.TransformerFactory;
uses javax.xml.validation.SchemaFactory; uses javax.xml.validation.SchemaFactory;
uses javax.xml.xpath.XPathFactory; uses javax.xml.xpath.XPathFactory;
uses org.xml.sax.XMLReader;
} }

View File

@ -93,6 +93,7 @@ package org.xml.sax;
* @see org.xml.sax.DocumentHandler#startElement startElement * @see org.xml.sax.DocumentHandler#startElement startElement
* @see org.xml.sax.helpers.AttributeListImpl AttributeListImpl * @see org.xml.sax.helpers.AttributeListImpl AttributeListImpl
*/ */
@Deprecated(since="5")
public interface AttributeList { public interface AttributeList {

View File

@ -68,6 +68,7 @@ package org.xml.sax;
* @see org.xml.sax.Locator * @see org.xml.sax.Locator
* @see org.xml.sax.HandlerBase * @see org.xml.sax.HandlerBase
*/ */
@Deprecated(since="5")
public interface DocumentHandler { public interface DocumentHandler {

View File

@ -73,6 +73,7 @@ import java.util.Locale;
* @see org.xml.sax.HandlerBase * @see org.xml.sax.HandlerBase
* @see org.xml.sax.InputSource * @see org.xml.sax.InputSource
*/ */
@Deprecated(since="5")
public interface Parser public interface Parser
{ {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,8 +32,7 @@
package org.xml.sax.helpers; package org.xml.sax.helpers;
import java.lang.reflect.Method; import java.util.Objects;
import java.lang.reflect.InvocationTargetException;
/** /**
* Create a new instance of a class by name. * Create a new instance of a class by name.
@ -57,31 +56,26 @@ import java.lang.reflect.InvocationTargetException;
* @version 2.0.1 (sax2r2) * @version 2.0.1 (sax2r2)
*/ */
class NewInstance { class NewInstance {
private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal";
/** /**
* Creates a new instance of the specified class name * Creates a new instance of the specified class name
* *
* Package private so this code is not exposed at the API level. * Package private so this code is not exposed at the API level.
*/ */
static Object newInstance (ClassLoader classLoader, String className) static <T> T newInstance (Class<T> type, ClassLoader loader, String clsName)
throws ClassNotFoundException, IllegalAccessException, throws ClassNotFoundException, IllegalAccessException,
InstantiationException InstantiationException
{ {
// make sure we have access to restricted packages ClassLoader classLoader = Objects.requireNonNull(loader);
boolean internal = false; String className = Objects.requireNonNull(clsName);
if (System.getSecurityManager() != null) {
if (className != null && className.startsWith(DEFAULT_PACKAGE)) { if (className.startsWith(DEFAULT_PACKAGE)) {
internal = true; return type.cast(new com.sun.org.apache.xerces.internal.parsers.SAXParser());
}
} }
Class driverClass; Class<?> driverClass = classLoader.loadClass(className);
if (classLoader == null || internal) { return type.cast(driverClass.newInstance());
driverClass = Class.forName(className);
} else {
driverClass = classLoader.loadClass(className);
}
return driverClass.newInstance();
} }
} }

View File

@ -30,8 +30,6 @@
package org.xml.sax.helpers; package org.xml.sax.helpers;
import org.xml.sax.Parser;
/** /**
* Java-specific class for dynamically loading SAX parsers. * Java-specific class for dynamically loading SAX parsers.
@ -65,6 +63,8 @@ import org.xml.sax.Parser;
* @author David Megginson * @author David Megginson
* @version 2.0.1 (sax2r2) * @version 2.0.1 (sax2r2)
*/ */
@SuppressWarnings( "deprecation" )
@Deprecated(since="5")
public class ParserFactory { public class ParserFactory {
private static SecuritySupport ss = new SecuritySupport(); private static SecuritySupport ss = new SecuritySupport();
@ -97,7 +97,7 @@ public class ParserFactory {
* @see #makeParser(java.lang.String) * @see #makeParser(java.lang.String)
* @see org.xml.sax.Parser * @see org.xml.sax.Parser
*/ */
public static Parser makeParser () public static org.xml.sax.Parser makeParser ()
throws ClassNotFoundException, throws ClassNotFoundException,
IllegalAccessException, IllegalAccessException,
InstantiationException, InstantiationException,
@ -134,14 +134,13 @@ public class ParserFactory {
* @see #makeParser() * @see #makeParser()
* @see org.xml.sax.Parser * @see org.xml.sax.Parser
*/ */
public static Parser makeParser (String className) public static org.xml.sax.Parser makeParser (String className)
throws ClassNotFoundException, throws ClassNotFoundException,
IllegalAccessException, IllegalAccessException,
InstantiationException, InstantiationException,
ClassCastException ClassCastException
{ {
return (Parser) NewInstance.newInstance ( return NewInstance.newInstance (org.xml.sax.Parser.class, ss.getClassLoader(), className);
ss.getContextClassLoader(), className);
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -37,72 +37,56 @@ import java.security.*;
*/ */
class SecuritySupport { class SecuritySupport {
/**
ClassLoader getContextClassLoader() throws SecurityException{ * Returns the current thread's context class loader, or the system class loader
return (ClassLoader) * if the context class loader is null.
AccessController.doPrivileged(new PrivilegedAction() { * @return the current thread's context class loader, or the system class loader
public Object run() { * @throws SecurityException
ClassLoader cl = null; */
//try { ClassLoader getClassLoader() throws SecurityException{
cl = Thread.currentThread().getContextClassLoader(); return AccessController.doPrivileged((PrivilegedAction<ClassLoader>)() -> {
//} catch (SecurityException ex) { } ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
if (cl == null) cl = ClassLoader.getSystemClassLoader();
cl = ClassLoader.getSystemClassLoader();
return cl;
} }
return cl;
}); });
} }
String getSystemProperty(final String propName) { String getSystemProperty(final String propName) {
return (String) return AccessController.doPrivileged((PrivilegedAction<String>)()
AccessController.doPrivileged(new PrivilegedAction() { -> System.getProperty(propName));
public Object run() {
return System.getProperty(propName);
}
});
} }
FileInputStream getFileInputStream(final File file) FileInputStream getFileInputStream(final File file)
throws FileNotFoundException throws FileNotFoundException
{ {
try { try {
return (FileInputStream) return AccessController.doPrivileged((PrivilegedExceptionAction<FileInputStream>)() ->
AccessController.doPrivileged(new PrivilegedExceptionAction() { new FileInputStream(file));
public Object run() throws FileNotFoundException {
return new FileInputStream(file);
}
});
} catch (PrivilegedActionException e) { } catch (PrivilegedActionException e) {
throw (FileNotFoundException)e.getException(); throw (FileNotFoundException)e.getException();
} }
} }
InputStream getResourceAsStream(final ClassLoader cl,
final String name) InputStream getResourceAsStream(final ClassLoader cl, final String name)
{ {
return (InputStream) return AccessController.doPrivileged((PrivilegedAction<InputStream>) () -> {
AccessController.doPrivileged(new PrivilegedAction() { InputStream ris;
public Object run() { if (cl == null) {
InputStream ris; ris = SecuritySupport.class.getResourceAsStream(name);
if (cl == null) { } else {
ris = SecuritySupport.class.getResourceAsStream(name); ris = cl.getResourceAsStream(name);
} else { }
ris = cl.getResourceAsStream(name); return ris;
} });
return ris;
}
});
} }
boolean doesFileExist(final File f) { boolean doesFileExist(final File f) {
return ((Boolean) return (AccessController.doPrivileged((PrivilegedAction<Boolean>)() ->
AccessController.doPrivileged(new PrivilegedAction() { new Boolean(f.exists())));
public Object run() {
return new Boolean(f.exists());
}
})).booleanValue();
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,10 +32,17 @@
package org.xml.sax.helpers; package org.xml.sax.helpers;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; 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.SAXException;
import org.xml.sax.XMLReader;
/** /**
@ -70,7 +77,11 @@ import org.xml.sax.SAXException;
* @since 1.4, SAX 2.0 * @since 1.4, SAX 2.0
* @author David Megginson, David Brownell * @author David Megginson, David Brownell
* @version 2.0.1 (sax2r2) * @version 2.0.1 (sax2r2)
*
* @deprecated It is recommended to use {@link javax.xml.parsers.SAXParserFactory}
* instead.
*/ */
@Deprecated(since="9")
final public class XMLReaderFactory final public class XMLReaderFactory
{ {
/** /**
@ -83,47 +94,43 @@ final public class XMLReaderFactory
} }
private static final String property = "org.xml.sax.driver"; 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. * Obtains a new instance of a {@link org.xml.sax.XMLReader}.
* In environments which can support it, the name of the XMLReader * This method uses the following ordered lookup procedure to find and load
* class is determined by trying each these options in order, and * the {@link org.xml.sax.XMLReader} implementation class:
* using the first one which succeeds: * <p>
* <ul> * <ol>
*
* <li>If the system property {@code org.xml.sax.driver} * <li>If the system property {@code org.xml.sax.driver}
* has a value, that is used as an XMLReader class name. </li> * has a value, that is used as an XMLReader class name. </li>
* <li>
* 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.
* </li>
* <li>
* 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.</li>
* <li>
* <p>
* Otherwise, the system-default implementation is returned.
* </li>
* </ol>
* *
* <li>The JAR "Services API" is used to look for a class name * @apiNote
* in the <em>META-INF/services/org.xml.sax.driver</em> file in * The process that looks for a class name in the
* jarfiles available to the runtime.</li> * {@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.
* *
* <li> SAX parser distributions are strongly encouraged to provide * @return a new XMLReader.
* a default XMLReader class name that will take effect only when
* previous options (on this list) are not successful.</li>
*
* <li>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.) </li>
* </ul>
*
* <p> In environments such as small embedded systems, which can not
* support that flexibility, other mechanisms to determine the default
* may be used.
*
* <p>Note that many Java environments allow system properties to be
* initialized on a command line. This means that <em>in most cases</em>
* 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.
* @exception org.xml.sax.SAXException If no default XMLReader class * @exception org.xml.sax.SAXException If no default XMLReader class
* can be identified and instantiated. * can be identified and instantiated.
* @see #createXMLReader(java.lang.String) * @see #createXMLReader(java.lang.String)
@ -132,7 +139,7 @@ final public class XMLReaderFactory
throws SAXException throws SAXException
{ {
String className = null; String className = null;
ClassLoader cl = ss.getContextClassLoader(); ClassLoader cl = ss.getClassLoader();
// 1. try the JVM-instance-wide system property // 1. try the JVM-instance-wide system property
try { try {
@ -140,62 +147,26 @@ final public class XMLReaderFactory
} }
catch (RuntimeException e) { /* continue searching */ } catch (RuntimeException e) { /* continue searching */ }
// 2. if that fails, try META-INF/services/ // 2. try the ServiceLoader
if (className == null) { if (className == null) {
if (!_jarread) { final XMLReader provider = findServiceProvider(XMLReader.class, cl);
_jarread = true; if (provider != null) {
String service = "META-INF/services/" + property; return provider;
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) {
}
} }
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) { if (className == null) {
// BEGIN DISTRIBUTION-SPECIFIC className = jarLookup(cl);
// 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
} }
// do we know the XMLReader implementation class yet? // 4. Distro-specific fallback
if (className != null) if (className == null) {
return loadClass (cl, className); return new com.sun.org.apache.xerces.internal.parsers.SAXParser();
// 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?");
} }
return loadClass (cl, className);
} }
@ -217,14 +188,14 @@ final public class XMLReaderFactory
public static XMLReader createXMLReader (String className) public static XMLReader createXMLReader (String className)
throws SAXException throws SAXException
{ {
return loadClass (ss.getContextClassLoader(), className); return loadClass (ss.getClassLoader(), className);
} }
private static XMLReader loadClass (ClassLoader loader, String className) private static XMLReader loadClass (ClassLoader loader, String className)
throws SAXException throws SAXException
{ {
try { try {
return (XMLReader) NewInstance.newInstance (loader, className); return NewInstance.newInstance (XMLReader.class, loader, className);
} catch (ClassNotFoundException e1) { } catch (ClassNotFoundException e1) {
throw new SAXException("SAX2 driver class " + className + throw new SAXException("SAX2 driver class " + className +
" not found", e1); " not found", e1);
@ -240,4 +211,64 @@ final public class XMLReaderFactory
" does not implement XMLReader", e4); " 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> T findServiceProvider(final Class<T> type, final ClassLoader loader)
throws SAXException {
ClassLoader cl = Objects.requireNonNull(loader);
try {
return AccessController.doPrivileged((PrivilegedAction<T>) () -> {
final ServiceLoader<T> serviceLoader;
serviceLoader = ServiceLoader.load(type, cl);
final Iterator<T> 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);
}
}
} }

View File

@ -76,14 +76,20 @@ endif
TEST_ROOT := $(shell $(PWD)) TEST_ROOT := $(shell $(PWD))
# Root of all test results # Root of all test results
ifdef ALT_OUTPUTDIR ifdef TEST_OUTPUT_DIR
ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD)) $(shell $(MKDIR) -p $(TEST_OUTPUT_DIR)/jtreg)
ABS_TEST_OUTPUT_DIR := \
$(shell $(CD) $(TEST_OUTPUT_DIR)/jtreg && $(PWD))
else else
ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD)) ifdef ALT_OUTPUTDIR
endif ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD))
else
ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD))
endif
ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR) ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR)
ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) 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) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
ifndef PRODUCT_HOME ifndef PRODUCT_HOME

View File

@ -29,3 +29,5 @@ javax/xml/jaxp/isolatedjdk/catalog/PropertiesTest.sh generic-all
# 8150145 # 8150145
javax/xml/jaxp/unittest/common/TransformationWarningsTest.java generic-all javax/xml/jaxp/unittest/common/TransformationWarningsTest.java generic-all
# 8156508
javax/xml/jaxp/unittest/stream/FactoryFindTest.java generic-all

View File

@ -38,7 +38,7 @@ import org.testng.annotations.Test;
* @library /javax/xml/jaxp/libs * @library /javax/xml/jaxp/libs
* @build jdk.testlibrary.* * @build jdk.testlibrary.*
* @run testng BasicModularXMLParserTest * @run testng BasicModularXMLParserTest
* @bug 8078820 * @bug 8078820 8156119
* @summary Tests JAXP lib can instantiate the following interfaces * @summary Tests JAXP lib can instantiate the following interfaces
* with customized provider module on boot layer * with customized provider module on boot layer
* *
@ -51,6 +51,7 @@ import org.testng.annotations.Test;
* javax.xml.transform.TransformerFactory * javax.xml.transform.TransformerFactory
* javax.xml.validation.SchemaFactory * javax.xml.validation.SchemaFactory
* javax.xml.xpath.XPathFactory * javax.xml.xpath.XPathFactory
* org.xml.sax.XMLReader
*/ */
@Test @Test

View File

@ -50,7 +50,7 @@ import jdk.testlibrary.CompilerUtils;
* @library /javax/xml/jaxp/libs * @library /javax/xml/jaxp/libs
* @build jdk.testlibrary.* * @build jdk.testlibrary.*
* @run testng LayerModularXMLParserTest * @run testng LayerModularXMLParserTest
* @bug 8078820 * @bug 8078820 8156119
* @summary Tests JAXP lib works with layer and TCCL * @summary Tests JAXP lib works with layer and TCCL
*/ */
@ -75,7 +75,7 @@ public class LayerModularXMLParserTest {
* services provided by provider2 * services provided by provider2
*/ */
private static final String[] services2 = { "javax.xml.datatype.DatatypeFactory", 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 * Compiles all modules used by the test

View File

@ -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);
}
}
}

View File

@ -31,6 +31,8 @@ import java.lang.System;
import java.util.Iterator; import java.util.Iterator;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import org.xml.sax.helpers.XMLReaderFactory;
public class XMLFactoryHelper { public class XMLFactoryHelper {
/* /*
* instantiate a xml factory by reflection e.g. * instantiate a xml factory by reflection e.g.
@ -41,7 +43,9 @@ public class XMLFactoryHelper {
try { try {
// set thread context class loader to module class loader // set thread context class loader to module class loader
Thread.currentThread().setContextClassLoader(XMLFactoryHelper.class.getClassLoader()); 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) return Class.forName(serviceName).getMethod("newInstance", String.class)
.invoke(null, W3C_XML_SCHEMA_NS_URI); .invoke(null, W3C_XML_SCHEMA_NS_URI);
else else

View File

@ -30,6 +30,8 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.xml.sax.helpers.XMLReaderFactory;
public class Main { public class Main {
/* /*
* @param args, the names of provider modules, which have been loaded * @param args, the names of provider modules, which have been loaded
@ -69,7 +71,9 @@ public class Main {
*/ */
private static Object instantiateXMLService(String serviceName) { private static Object instantiateXMLService(String serviceName) {
try { 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) return Class.forName(serviceName).getMethod("newInstance", String.class)
.invoke(null, W3C_XML_SCHEMA_NS_URI); .invoke(null, W3C_XML_SCHEMA_NS_URI);
else else
@ -102,6 +106,7 @@ public class Main {
"javax.xml.parsers.DocumentBuilderFactory", "javax.xml.parsers.SAXParserFactory", "javax.xml.parsers.DocumentBuilderFactory", "javax.xml.parsers.SAXParserFactory",
"javax.xml.stream.XMLEventFactory", "javax.xml.stream.XMLInputFactory", "javax.xml.stream.XMLEventFactory", "javax.xml.stream.XMLInputFactory",
"javax.xml.stream.XMLOutputFactory", "javax.xml.transform.TransformerFactory", "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"};
} }

View File

@ -26,4 +26,5 @@ module xmlprovider2 {
provides javax.xml.datatype.DatatypeFactory with xp2.DatatypeFactoryImpl; provides javax.xml.datatype.DatatypeFactory with xp2.DatatypeFactoryImpl;
provides javax.xml.stream.XMLEventFactory with xp2.XMLEventFactoryImpl; provides javax.xml.stream.XMLEventFactory with xp2.XMLEventFactoryImpl;
provides org.xml.sax.XMLReader with xp2.XMLReaderImpl;
} }

View File

@ -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 {
}
}

View File

@ -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 {
}
}

View File

@ -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"},
};
}
}

View File

@ -363,3 +363,4 @@ b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114
4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115 4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115
529f0bf896e58525614d863e283ad155531941cb jdk-9+116 529f0bf896e58525614d863e283ad155531941cb jdk-9+116
58265b39fc74b932bda4d4f4649c530a89f55c4e jdk-9+117 58265b39fc74b932bda4d4f4649c530a89f55c4e jdk-9+117
6ba73d04589ccc0705a5d8ae5111b63632b6ad20 jdk-9+118

View File

@ -361,3 +361,4 @@ bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114
baeb5edb38939cdb78ae0ac6f4fd368465cbf188 jdk-9+116 baeb5edb38939cdb78ae0ac6f4fd368465cbf188 jdk-9+116
4da0f73ce03aaf245b92cc040cc0ab0e3fa54dc2 jdk-9+117 4da0f73ce03aaf245b92cc040cc0ab0e3fa54dc2 jdk-9+117
e1eba5cfa5cc8c66d524396a05323dc93568730a jdk-9+118 e1eba5cfa5cc8c66d524396a05323dc93568730a jdk-9+118
bad3f8a33db271a6143ba6eac0c8bd5bbd942417 jdk-9+119

View File

@ -112,7 +112,7 @@ $(BASE_INSTALL_LIBRARIES_HERE)/server/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_
$(LN) -s ../$(@F) $@ $(LN) -s ../$(@F) $@
ifeq ($(OPENJDK_TARGET_OS), macosx) 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) $(MKDIR) -p $(@D)
$(RM) $@ $(RM) $@
$(LN) -s ../$(@F) $@ $(LN) -s ../$(@F) $@

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,8 @@
# Version of the currency data format. # Version of the currency data format.
# 1: initial # 1: initial
# 2: Change in minor unit (allowing 4-9 digits) # 2: Change in minor unit (allowing 4-9 digits)
formatVersion=2 # 3: Change in the order of special case and other currency entries
formatVersion=3
# Version of the currency code information in this class. # Version of the currency code information in this class.
# It is a serial number that accompanies with each amendment. # It is a serial number that accompanies with each amendment.

View File

@ -96,10 +96,7 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
mlib_c_ImageAffine_BL.c \ mlib_c_ImageAffine_BL.c \
mlib_c_ImageAffine_BL_S16.c \ mlib_c_ImageAffine_BL_S16.c \
mlib_c_ImageAffine_BL_U16.c \ mlib_c_ImageAffine_BL_U16.c \
mlib_c_ImageAffineIndex_BC.c \
mlib_c_ImageAffineIndex_BL.c \
mlib_c_ImageAffine_NN.c \ mlib_c_ImageAffine_NN.c \
mlib_c_ImageBlendTable.c \
mlib_c_ImageConvClearEdge.c \ mlib_c_ImageConvClearEdge.c \
mlib_c_ImageConvCopyEdge.c \ mlib_c_ImageConvCopyEdge.c \
mlib_c_ImageConv_f.c \ mlib_c_ImageConv_f.c \
@ -107,14 +104,6 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
mlib_c_ImageCopy.c \ mlib_c_ImageCopy.c \
mlib_c_ImageLookUp.c \ mlib_c_ImageLookUp.c \
mlib_c_ImageLookUp_f.c \ mlib_c_ImageLookUp_f.c \
mlib_v_ImageChannelExtract.c \
mlib_v_ImageChannelExtract_f.c \
mlib_v_ImageChannelInsert_34.c \
mlib_v_ImageChannelInsert.c \
mlib_v_ImageConvIndex3_8_16nw.c \
mlib_v_ImageConvIndex3_8_8nw.c \
mlib_v_ImageCopy.c \
mlib_v_ImageCopy_blk.s \
# #
LIBMLIB_IMAGE_V_CFLAGS += $(filter-out -DMLIB_NO_LIBSUNMATH, $(BUILD_LIBMLIB_CFLAGS)) LIBMLIB_IMAGE_V_CFLAGS += $(filter-out -DMLIB_NO_LIBSUNMATH, $(BUILD_LIBMLIB_CFLAGS))

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -584,7 +584,9 @@ public class CLDRConverter {
String[] data = (String[])e[1]; String[] data = (String[])e[1];
if (map.get(TIMEZONE_ID_PREFIX + tzid) == null && if (map.get(TIMEZONE_ID_PREFIX + tzid) == null &&
handlerMetaZones.get(tzid) == null) { handlerMetaZones.get(tzid) == null ||
handlerMetaZones.get(tzid) != null &&
map.get(METAZONE_ID_PREFIX + handlerMetaZones.get(tzid)) == null) {
// First, check the CLDR meta key // First, check the CLDR meta key
Optional<Map.Entry<String, String>> cldrMeta = Optional<Map.Entry<String, String>> cldrMeta =
handlerMetaZones.getData().entrySet().stream() handlerMetaZones.getData().entrySet().stream()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -121,7 +121,7 @@ public class GenerateCurrencyData {
private static final int maxOtherCurrencies = 128; private static final int maxOtherCurrencies = 128;
private static int otherCurrenciesCount = 0; private static int otherCurrenciesCount = 0;
private static StringBuffer otherCurrencies = new StringBuffer(); private static String[] otherCurrencies = new String[maxOtherCurrencies];
private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies]; private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies];
private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies]; private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies];
@ -318,10 +318,7 @@ public class GenerateCurrencyData {
if (otherCurrenciesCount == maxOtherCurrencies) { if (otherCurrenciesCount == maxOtherCurrencies) {
throw new RuntimeException("too many other currencies"); throw new RuntimeException("too many other currencies");
} }
if (otherCurrencies.length() > 0) { otherCurrencies[otherCurrenciesCount] = currencyCode;
otherCurrencies.append('-');
}
otherCurrencies.append(currencyCode);
otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode); otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode);
otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode); otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode);
otherCurrenciesCount++; otherCurrenciesCount++;
@ -350,35 +347,41 @@ public class GenerateCurrencyData {
out.writeInt(Integer.parseInt(dataVersion)); out.writeInt(Integer.parseInt(dataVersion));
writeIntArray(mainTable, mainTable.length); writeIntArray(mainTable, mainTable.length);
out.writeInt(specialCaseCount); out.writeInt(specialCaseCount);
writeLongArray(specialCaseCutOverTimes, specialCaseCount); writeSpecialCaseEntries();
writeStringArray(specialCaseOldCurrencies, specialCaseCount);
writeStringArray(specialCaseNewCurrencies, specialCaseCount);
writeIntArray(specialCaseOldCurrenciesDefaultFractionDigits, specialCaseCount);
writeIntArray(specialCaseNewCurrenciesDefaultFractionDigits, specialCaseCount);
writeIntArray(specialCaseOldCurrenciesNumericCode, specialCaseCount);
writeIntArray(specialCaseNewCurrenciesNumericCode, specialCaseCount);
out.writeInt(otherCurrenciesCount); out.writeInt(otherCurrenciesCount);
out.writeUTF(otherCurrencies.toString()); writeOtherCurrencies();
writeIntArray(otherCurrenciesDefaultFractionDigits, otherCurrenciesCount);
writeIntArray(otherCurrenciesNumericCode, otherCurrenciesCount);
} }
private static void writeIntArray(int[] ia, int count) throws IOException { private static void writeIntArray(int[] ia, int count) throws IOException {
for (int i = 0; i < count; i ++) { for (int i = 0; i < count; i++) {
out.writeInt(ia[i]); out.writeInt(ia[i]);
} }
} }
private static void writeLongArray(long[] la, int count) throws IOException { private static void writeSpecialCaseEntries() throws IOException {
for (int i = 0; i < count; i ++) { for (int index = 0; index < specialCaseCount; index++) {
out.writeLong(la[i]); out.writeLong(specialCaseCutOverTimes[index]);
String str = (specialCaseOldCurrencies[index] != null)
? specialCaseOldCurrencies[index] : "";
out.writeUTF(str);
str = (specialCaseNewCurrencies[index] != null)
? specialCaseNewCurrencies[index] : "";
out.writeUTF(str);
out.writeInt(specialCaseOldCurrenciesDefaultFractionDigits[index]);
out.writeInt(specialCaseNewCurrenciesDefaultFractionDigits[index]);
out.writeInt(specialCaseOldCurrenciesNumericCode[index]);
out.writeInt(specialCaseNewCurrenciesNumericCode[index]);
} }
} }
private static void writeStringArray(String[] sa, int count) throws IOException { private static void writeOtherCurrencies() throws IOException {
for (int i = 0; i < count; i ++) { for (int index = 0; index < otherCurrenciesCount; index++) {
String str = (sa[i] != null) ? sa[i] : ""; String str = (otherCurrencies[index] != null)
? otherCurrencies[index] : "";
out.writeUTF(str); out.writeUTF(str);
out.writeInt(otherCurrenciesDefaultFractionDigits[index]);
out.writeInt(otherCurrenciesNumericCode[index]);
} }
} }
} }

View File

@ -415,7 +415,7 @@ Additional information can also be found by doing a search on "jvmti" at
Various technical articles are also available through this website. Various technical articles are also available through this website.
And don't forget the And don't forget the
Java Tutorials at Java Tutorials at
<A HREF="http://java.sun.com/docs/books/tutorial">http://java.sun.com/docs/books/tutorial</A> <A HREF="http://docs.oracle.com/javase/tutorial">http://docs.oracle.com/javase/tutorial</A>
for getting a quick start on all the various interfaces. for getting a quick start on all the various interfaces.
<h2>Comments and Feedback</h2> <h2>Comments and Feedback</h2>

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,9 +43,10 @@ class Constants {
1.0 to 1.3.X 45,3 1.0 to 1.3.X 45,3
1.4 to 1.4.X 46,0 1.4 to 1.4.X 46,0
1.5 to 1.5.X 49,0 1.5 to 1.5.X 49,0
1.6 to 1.5.x 50,0 1.6 to 1.6.X 50,0
1.7 to 1.6.x 51,0 1.7 to 1.7.X 51,0
1.8 to 1.7.x 52,0 1.8 to 1.8.X 52,0
1.9 to 1.9.X 53,0
*/ */
public static final Package.Version JAVA_MIN_CLASS_VERSION = public static final Package.Version JAVA_MIN_CLASS_VERSION =
@ -63,6 +64,9 @@ class Constants {
public static final Package.Version JAVA8_MAX_CLASS_VERSION = public static final Package.Version JAVA8_MAX_CLASS_VERSION =
Package.Version.of(52, 00); Package.Version.of(52, 00);
public static final Package.Version JAVA9_MAX_CLASS_VERSION =
Package.Version.of(53, 00);
public static final int JAVA_PACKAGE_MAGIC = 0xCAFED00D; public static final int JAVA_PACKAGE_MAGIC = 0xCAFED00D;
public static final Package.Version JAVA5_PACKAGE_VERSION = public static final Package.Version JAVA5_PACKAGE_VERSION =
@ -79,7 +83,7 @@ class Constants {
// upper limit, should point to the latest class version // upper limit, should point to the latest class version
public static final Package.Version JAVA_MAX_CLASS_VERSION = public static final Package.Version JAVA_MAX_CLASS_VERSION =
JAVA8_MAX_CLASS_VERSION; JAVA9_MAX_CLASS_VERSION;
// upper limit should point to the latest package version, for version info!. // upper limit should point to the latest package version, for version info!.
public static final Package.Version MAX_PACKAGE_VERSION = public static final Package.Version MAX_PACKAGE_VERSION =

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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, * 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 * however, then this method will flush the buffer and write the characters
* directly to the underlying stream. Thus redundant * directly to the underlying stream. Thus redundant
* <code>BufferedWriter</code>s will not copy data unnecessarily. * {@code BufferedWriter}s will not copy data unnecessarily.
* *
* @param cbuf A character array * @param cbuf A character array
* @param off Offset from which to start reading characters * @param off Offset from which to start reading characters
* @param len Number of characters to write * @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 { public void write(char cbuf[], int off, int len) throws IOException {
synchronized (lock) { synchronized (lock) {
@ -195,17 +200,24 @@ public class BufferedWriter extends Writer {
/** /**
* Writes a portion of a String. * Writes a portion of a String.
* *
* <p> If the value of the {@code len} parameter is negative then no * @implSpec
* characters are written. This is contrary to the specification of this * While the specification of this method in the
* method in the {@linkplain java.io.Writer#write(java.lang.String,int,int) * {@linkplain java.io.Writer#write(java.lang.String,int,int) superclass}
* superclass}, which requires that an {@link IndexOutOfBoundsException} be * recommends that an {@link IndexOutOfBoundsException} be thrown
* 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 s String to be written
* @param off Offset from which to start reading characters * @param off Offset from which to start reading characters
* @param len Number of characters to be written * @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 { public void write(String s, int off, int len) throws IOException {
synchronized (lock) { synchronized (lock) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 c the data to be written
* @param off the start offset in the data * @param off the start offset in the data
* @param len the number of chars that are written * @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) { public void write(char c[], int off, int len) {
if ((off < 0) || (off > c.length) || (len < 0) || if ((off < 0) || (off > c.length) || (len < 0) ||
@ -114,6 +119,11 @@ class CharArrayWriter extends Writer {
* @param str String to be written from * @param str String to be written from
* @param off Offset from which to start reading characters * @param off Offset from which to start reading characters
* @param len Number of characters to be written * @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) { public void write(String str, int off, int len) {
synchronized (lock) { synchronized (lock) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 off Offset from which to start reading characters
* @param len Number of characters to be written * @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 { public void write(char cbuf[], int off, int len) throws IOException {
out.write(cbuf, off, len); 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 off Offset from which to start reading characters
* @param len Number of characters to be written * @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 { public void write(String str, int off, int len) throws IOException {
out.write(str, off, len); out.write(str, off, len);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 off Offset from which to start writing characters
* @param len Number of characters to write * @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 { public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len); se.write(cbuf, off, len);
@ -215,7 +220,12 @@ public class OutputStreamWriter extends Writer {
* @param off Offset from which to start writing characters * @param off Offset from which to start writing characters
* @param len Number of characters to write * @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 { public void write(String str, int off, int len) throws IOException {
se.write(str, off, len); se.write(str, off, len);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -125,19 +125,25 @@ public class PipedWriter extends Writer {
} }
/** /**
* Writes <code>len</code> characters from the specified character array * Writes {@code len} characters from the specified character array
* starting at offset <code>off</code> to this piped output stream. * starting at offset {@code off} to this piped output stream.
* This method blocks until all the characters are written to the output * This method blocks until all the characters are written to the output
* stream. * stream.
* If a thread was reading data characters from the connected piped input * If a thread was reading data characters from the connected piped input
* stream, but the thread is no longer alive, then an * stream, but the thread is no longer alive, then an
* <code>IOException</code> is thrown. * {@code IOException} is thrown.
* *
* @param cbuf the data. * @param cbuf the data.
* @param off the start offset in the data. * @param off the start offset in the data.
* @param len the number of characters to write. * @param len the number of characters to write.
* @exception IOException if the pipe is *
* <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>, * @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
* <a href=PipedOutputStream.html#BROKEN><code>broken</code></a>,
* {@link #connect(java.io.PipedReader) unconnected}, closed * {@link #connect(java.io.PipedReader) unconnected}, closed
* or an I/O error occurs. * or an I/O error occurs.
*/ */

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 buf Array of characters
* @param off Offset from which to start writing characters * @param off Offset from which to start writing characters
* @param len Number of characters to write * @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) { public void write(char buf[], int off, int len) {
try { try {
@ -440,6 +445,11 @@ public class PrintWriter extends Writer {
* @param s A String * @param s A String
* @param off Offset from which to start writing characters * @param off Offset from which to start writing characters
* @param len Number of characters to write * @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) { public void write(String s, int off, int len) {
try { try {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 cbuf Array of characters
* @param off Offset from which to start writing characters * @param off Offset from which to start writing characters
* @param len Number of characters to write * @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) { public void write(char cbuf[], int off, int len) {
if ((off < 0) || (off > cbuf.length) || (len < 0) || if ((off < 0) || (off > cbuf.length) || (len < 0) ||
@ -107,6 +112,11 @@ public class StringWriter extends Writer {
* @param str String to be written * @param str String to be written
* @param off Offset from which to start writing characters * @param off Offset from which to start writing characters
* @param len Number of characters to write * @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) { public void write(String str, int off, int len) {
buf.append(str, off, off + len); buf.append(str, off, off + len);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * Most subclasses, however, will override some of the methods defined here in
* order to provide higher efficiency, additional functionality, or both. * order to provide higher efficiency, additional functionality, or both.
* *
* @see Writer
* @see BufferedWriter * @see BufferedWriter
* @see CharArrayWriter * @see CharArrayWriter
* @see FilterWriter * @see FilterWriter
* @see OutputStreamWriter * @see OutputStreamWriter
* @see FileWriter * @see FileWriter
* @see PipedWriter * @see PipedWriter
* @see PrintWriter * @see PrintWriter
* @see StringWriter * @see StringWriter
@ -139,6 +138,12 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* @param len * @param len
* Number of characters to write * 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 * @throws IOException
* If an I/O error occurs * If an I/O error occurs
*/ */
@ -160,6 +165,11 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
/** /**
* Writes a portion of a string. * 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 * @param str
* A String * A String
* *
@ -170,8 +180,9 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* Number of characters to write * Number of characters to write
* *
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException
* If {@code off} is negative, or {@code len} is negative, * Implementations should throw this exception
* or {@code off+len} is negative or greater than the length * 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 * of the given string
* *
* @throws IOException * @throws IOException

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,9 +26,21 @@
package java.lang; package java.lang;
import java.io.*; import java.io.*;
import java.math.BigInteger;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.RandomAccess;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection; import jdk.internal.reflect.Reflection;
import sun.security.action.GetPropertyAction;
/** /**
* Every Java application has a single instance of class * Every Java application has a single instance of class
@ -46,6 +58,8 @@ import jdk.internal.reflect.Reflection;
public class Runtime { public class Runtime {
private static final Runtime currentRuntime = new Runtime(); private static final Runtime currentRuntime = new Runtime();
private static Version version;
/** /**
* Returns the runtime object associated with the current Java application. * Returns the runtime object associated with the current Java application.
* Most of the methods of class {@code Runtime} are instance * Most of the methods of class {@code Runtime} are instance
@ -917,4 +931,591 @@ public class Runtime {
return out; return out;
} }
/**
* Returns the version of the Java Runtime Environment as a {@link
* Runtime.Version}.
*
* @return the {@link Runtime.Version} of the Java Runtime Environment
*
* @since 9
*/
public static Version version() {
if (version == null) {
version = Version.parse(
GetPropertyAction.privilegedGetProperty("java.runtime.version"));
}
return version;
}
/**
* A representation of a version string for an implemenation of the
* Java&nbsp;SE Platform. A version string contains a version number
* optionally followed by pre-release and build information.
*
* <h2><a name="verNum">Version numbers</a></h2>
*
* <p> A <em>version number</em>, {@code $VNUM}, is a non-empty sequence
* of elements separated by period characters (U+002E). An element is
* either zero, or a unsigned integer numeral without leading zeros. The
* final element in a version number must not be zero. The format is:
* </p>
*
* <blockquote><pre>
* ^[1-9][0-9]*(((\.0)*\.[1-9][0-9]*)*)*$
* </pre></blockquote>
*
* <p> The sequence may be of arbitrary length but the first three
* elements are assigned specific meanings, as follows:</p>
*
* <blockquote><pre>
* $MAJOR.$MINOR.$SECURITY
* </pre></blockquote>
*
* <ul>
*
* <li><p> <a name="major">{@code $MAJOR}</a> --- The major version
* number, incremented for a major release that contains significant new
* features as specified in a new edition of the Java&#160;SE Platform
* Specification, <em>e.g.</em>, <a
* href="https://jcp.org/en/jsr/detail?id=337">JSR 337</a> for
* Java&#160;SE&#160;8. Features may be removed in a major release, given
* advance notice at least one major release ahead of time, and
* incompatible changes may be made when justified. The {@code $MAJOR}
* version number of JDK&#160;8 is {@code 8}; the {@code $MAJOR} version
* number of JDK&#160;9 is {@code 9}. When {@code $MAJOR} is incremented,
* all subsequent elements are removed. </p></li>
*
* <li><p> <a name="minor">{@code $MINOR}</a> --- The minor version
* number, incremented for a minor update release that may contain
* compatible bug fixes, revisions to standard APIs mandated by a
* <a href="https://jcp.org/en/procedures/jcp2#5.3">Maintenance Release</a>
* of the relevant Platform Specification, and implementation features
* outside the scope of that Specification such as new JDK-specific APIs,
* additional service providers, new garbage collectors, and ports to new
* hardware architectures. </p></li>
*
* <li><p> <a name="security">{@code $SECURITY}</a> --- The security
* level, incremented for a security update release that contains critical
* fixes including those necessary to improve security. {@code $SECURITY}
* is <strong>not</strong> reset when {@code $MINOR} is incremented. A
* higher value of {@code $SECURITY} for a given {@code $MAJOR} value,
* therefore, always indicates a more secure release, regardless of the
* value of {@code $MINOR}. </p></li>
*
* </ul>
*
* <p> The fourth and later elements of a version number are free for use
* by downstream consumers of this code base. Such a consumer may,
* <em>e.g.</em>, use the fourth element to identify patch releases which
* contain a small number of critical non-security fixes in addition to
* the security fixes in the corresponding security release. </p>
*
* <p> The version number does not include trailing zero elements;
* <em>i.e.</em>, {@code $SECURITY} is omitted if it has the value zero,
* and {@code $MINOR} is omitted if both {@code $MINOR} and {@code
* $SECURITY} have the value zero. </p>
*
* <p> The sequence of numerals in a version number is compared to another
* such sequence in numerical, pointwise fashion; <em>e.g.</em>, {@code
* 9.9.1} is less than {@code 9.10.3}. If one sequence is shorter than
* another then the missing elements of the shorter sequence are
* considered to be less than the corresponding elements of the longer
* sequence; <em>e.g.</em>, {@code 9.1.2} is less than {@code 9.1.2.1}.
* </p>
*
* <h2><a name="verStr">Version strings</a></h2>
*
* <p> A <em>version string</em>, {@code $VSTR}, consists of a version
* number {@code $VNUM}, as described above, optionally followed by
* pre-release and build information, in the format </p>
*
* <blockquote><pre>
* $VNUM(-$PRE)?(\+($BUILD)?(-$OPT)?)?
* </pre></blockquote>
*
* <p> where: </p>
*
* <ul>
*
* <li><p> <a name="pre">{@code $PRE}</a>, matching {@code ([a-zA-Z0-9]+)}
* --- A pre-release identifier. Typically {@code ea}, for a
* potentially unstable early-access release under active development,
* or {@code internal}, for an internal developer build.
*
* <li><p> <a name="build">{@code $BUILD}</a>, matching {@code
* (0|[1-9][0-9]*)} --- The build number, incremented for each promoted
* build. {@code $BUILD} is reset to {@code 1} when any portion of {@code
* $VNUM} is incremented. </p>
*
* <li><p> <a name="opt">{@code $OPT}</a>, matching {@code
* ([-a-zA-Z0-9\.]+)} --- Additional build information, if desired. In
* the case of an {@code internal} build this will often contain the date
* and time of the build. </p>
*
* </ul>
*
* <p> A version number {@code 10-ea} matches {@code $VNUM = "10"} and
* {@code $PRE = "ea"}. The version number {@code 10+-ea} matches
* {@code $VNUM = "10"} and {@code $OPT = "ea"}. </p>
*
* <p> When comparing two version strings, the value of {@code $OPT}, if
* present, may or may not be significant depending on the chosen
* comparison method. The comparison methods {@link #compareTo(Version)
* compareTo()} and {@link #compareToIgnoreOpt(Version)
* compareToIgnoreOpt()} should be used consistently with the
* corresponding methods {@link #equals(Object) equals()} and {@link
* #equalsIgnoreOpt(Object) equalsIgnoreOpt()}. </p>
*
* <p> A <em>short version string</em>, {@code $SVSTR}, often useful in
* less formal contexts, is a version number optionally followed by a
* pre-release identifier:
*
* <blockquote><pre>
* $VNUM(-$PRE)?
* </pre></blockquote>
*
* @since 9
*/
public static class Version
implements Comparable<Version>
{
private final List<Integer> version;
private final Optional<String> pre;
private final Optional<Integer> build;
private final Optional<String> optional;
// $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)?
// RE limits the format of version strings
// ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))?
private static final String VNUM
= "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)";
private static final String VNUM_GROUP = "VNUM";
private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?";
private static final String PRE_GROUP = "PRE";
private static final String BUILD
= "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?";
private static final String PLUS_GROUP = "PLUS";
private static final String BUILD_GROUP = "BUILD";
private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";
private static final String OPT_GROUP = "OPT";
private static final String VSTR_FORMAT
= "^" + VNUM + PRE + BUILD + OPT + "$";
private static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
/**
* Constructs a valid <a href="verStr">version string</a> containing
* a <a href="#verNum">version number</a> followed by pre-release and
* build information.
*
* @param s
* A string to be interpreted as a version
*
* @throws IllegalArgumentException
* If the given string cannot be interpreted as a valid
* version
*
* @throws NullPointerException
* If {@code s} is {@code null}
*
* @throws NumberFormatException
* If an element of the version number or the build number
* cannot be represented as an {@link Integer}
*/
private Version(String s) {
if (s == null)
throw new NullPointerException();
Matcher m = VSTR_PATTERN.matcher(s);
if (!m.matches())
throw new IllegalArgumentException("Invalid version string: '"
+ s + "'");
// $VNUM is a dot-separated list of integers of arbitrary length
List<Integer> list = new ArrayList<>();
for (String i : m.group(VNUM_GROUP).split("\\."))
list.add(Integer.parseInt(i));
version = Collections.unmodifiableList(list);
pre = Optional.ofNullable(m.group(PRE_GROUP));
String b = m.group(BUILD_GROUP);
// $BUILD is an integer
build = (b == null)
? Optional.<Integer>empty()
: Optional.ofNullable(Integer.parseInt(b));
optional = Optional.ofNullable(m.group(OPT_GROUP));
// empty '+'
if ((m.group(PLUS_GROUP) != null) && !build.isPresent()) {
if (optional.isPresent()) {
if (pre.isPresent())
throw new IllegalArgumentException("'+' found with"
+ " pre-release and optional components:'" + s
+ "'");
} else {
throw new IllegalArgumentException("'+' found with neither"
+ " build or optional components: '" + s + "'");
}
}
}
/**
* Parses the given string as a valid
* <a href="#verStr">version string</a> containing a
* <a href="#verNum">version number</a> followed by pre-release and
* build information.
*
* @param s
* A string to interpret as a version
*
* @throws IllegalArgumentException
* If the given string cannot be interpreted as a valid
* version
*
* @throws NullPointerException
* If the given string is {@code null}
*
* @throws NumberFormatException
* If an element of the version number or the build number
* cannot be represented as an {@link Integer}
*
* @return The Version of the given string
*/
public static Version parse(String s) {
return new Version(s);
}
/**
* Returns the <a href="#major">major</a> version number.
*
* @return The major version number
*/
public int major() {
return version.get(0);
}
/**
* Returns the <a href="#minor">minor</a> version number or zero if it
* was not set.
*
* @return The minor version number or zero if it was not set
*/
public int minor() {
return (version.size() > 1 ? version.get(1) : 0);
}
/**
* Returns the <a href="#security">security</a> version number or zero
* if it was not set.
*
* @return The security version number or zero if it was not set
*/
public int security() {
return (version.size() > 2 ? version.get(2) : 0);
}
/**
* Returns an unmodifiable {@link java.util.List List} of the
* integer numerals contained in the <a href="#verNum">version
* number</a>. The {@code List} always contains at least one
* element corresponding to the <a href="#major">major version
* number</a>.
*
* @return An unmodifiable list of the integer numerals
* contained in the version number
*/
public List<Integer> version() {
return version;
}
/**
* Returns the optional <a href="#pre">pre-release</a> information.
*
* @return The optional pre-release information as a String
*/
public Optional<String> pre() {
return pre;
}
/**
* Returns the <a href="#build">build number</a>.
*
* @return The optional build number.
*/
public Optional<Integer> build() {
return build;
}
/**
* Returns <a href="#opt">optional</a> additional identifying build
* information.
*
* @return Additional build information as a String
*/
public Optional<String> optional() {
return optional;
}
/**
* Compares this version to another.
*
* <p> Each of the components in the <a href="#verStr">version</a> is
* compared in the follow order of precedence: version numbers,
* pre-release identifiers, build numbers, optional build information.
* </p>
*
* <p> Comparison begins by examining the sequence of version numbers.
* If one sequence is shorter than another, then the missing elements
* of the shorter sequence are considered to be less than the
* corresponding elements of the longer sequence. </p>
*
* <p> A version with a pre-release identifier is always considered to
* be less than a version without one. Pre-release identifiers are
* compared numerically when they consist only of digits, and
* lexicographically otherwise. Numeric identifiers are considered to
* be less than non-numeric identifiers. </p>
*
* <p> A version without a build number is always less than one with a
* build number; otherwise build numbers are compared numerically. </p>
*
* <p> The optional build information is compared lexicographically.
* During this comparison, a version with optional build information is
* considered to be greater than a version without one. </p>
*
* <p> A version is not comparable to any other type of object.
*
* @param ob
* The object to be compared
*
* @return A negative integer, zero, or a positive integer if this
* {@code Version} is less than, equal to, or greater than the
* given {@code Version}
*
* @throws NullPointerException
* If the given object is {@code null}
*/
@Override
public int compareTo(Version ob) {
return compare(ob, false);
}
/**
* Compares this version to another disregarding optional build
* information.
*
* <p> Two versions are compared by examining the version string as
* described in {@link #compareTo(Version)} with the exception that the
* optional build information is always ignored. </p>
*
* <p> A version is not comparable to any other type of object.
*
* @param ob
* The object to be compared
*
* @return A negative integer, zero, or a positive integer if this
* {@code Version} is less than, equal to, or greater than the
* given {@code Version}
*
* @throws NullPointerException
* If the given object is {@code null}
*/
public int compareToIgnoreOpt(Version ob) {
return compare(ob, true);
}
private int compare(Version ob, boolean ignoreOpt) {
if (ob == null)
throw new NullPointerException("Invalid argument");
int ret = compareVersion(ob);
if (ret != 0)
return ret;
ret = comparePre(ob);
if (ret != 0)
return ret;
ret = compareBuild(ob);
if (ret != 0)
return ret;
if (!ignoreOpt)
return compareOpt(ob);
return 0;
}
private int compareVersion(Version ob) {
int size = version.size();
int oSize = ob.version().size();
int min = Math.min(size, oSize);
for (int i = 0; i < min; i++) {
Integer val = version.get(i);
Integer oVal = ob.version().get(i);
if (val != oVal)
return val - oVal;
}
if (size != oSize)
return size - oSize;
return 0;
}
private int comparePre(Version ob) {
Optional<String> oPre = ob.pre();
if (!pre.isPresent()) {
if (oPre.isPresent())
return 1;
} else {
if (!oPre.isPresent())
return -1;
String val = pre.get();
String oVal = oPre.get();
if (val.matches("\\d+")) {
return (oVal.matches("\\d+")
? (new BigInteger(val)).compareTo(new BigInteger(oVal))
: -1);
} else {
return (oVal.matches("\\d+")
? 1
: val.compareTo(oVal));
}
}
return 0;
}
private int compareBuild(Version ob) {
Optional<Integer> oBuild = ob.build();
if (oBuild.isPresent()) {
return (build.isPresent()
? build.get().compareTo(oBuild.get())
: 1);
} else if (build.isPresent()) {
return -1;
}
return 0;
}
private int compareOpt(Version ob) {
Optional<String> oOpt = ob.optional();
if (!optional.isPresent()) {
if (oOpt.isPresent())
return -1;
} else {
if (!oOpt.isPresent())
return 1;
return optional.get().compareTo(oOpt.get());
}
return 0;
}
/**
* Returns a string representation of this version.
*
* @return The version string
*/
@Override
public String toString() {
StringBuilder sb
= new StringBuilder(version.stream()
.map(Object::toString)
.collect(Collectors.joining(".")));
pre.ifPresent(v -> sb.append("-").append(v));
if (build.isPresent()) {
sb.append("+").append(build.get());
if (optional.isPresent())
sb.append("-").append(optional.get());
} else {
if (optional.isPresent()) {
sb.append(pre.isPresent() ? "-" : "+-");
sb.append(optional.get());
}
}
return sb.toString();
}
/**
* Determines whether this {@code Version} is equal to another object.
*
* <p> Two {@code Version}s are equal if and only if they represent the
* same version string.
*
* <p> This method satisfies the general contract of the {@link
* Object#equals(Object) Object.equals} method. </p>
*
* @param ob
* The object to which this {@code Version} is to be compared
*
* @return {@code true} if, and only if, the given object is a {@code
* Version} that is identical to this {@code Version}
*
*/
@Override
public boolean equals(Object ob) {
boolean ret = equalsIgnoreOpt(ob);
if (!ret)
return false;
Version that = (Version)ob;
return (this.optional().equals(that.optional()));
}
/**
* Determines whether this {@code Version} is equal to another
* disregarding optional build information.
*
* <p> Two {@code Version}s are equal if and only if they represent the
* same version string disregarding the optional build information.
*
* @param ob
* The object to which this {@code Version} is to be compared
*
* @return {@code true} if, and only if, the given object is a {@code
* Version} that is identical to this {@code Version}
* ignoring the optinal build information
*
*/
public boolean equalsIgnoreOpt(Object ob) {
if (this == ob)
return true;
if (!(ob instanceof Version))
return false;
Version that = (Version)ob;
return (this.version().equals(that.version())
&& this.pre().equals(that.pre())
&& this.build().equals(that.build()));
}
/**
* Returns the hash code of this version.
*
* <p> This method satisfies the general contract of the {@link
* Object#hashCode Object.hashCode} method.
*
* @return The hashcode of this version
*/
@Override
public int hashCode() {
int h = 1;
int p = 17;
h = p * h + version.hashCode();
h = p * h + pre.hashCode();
h = p * h + build.hashCode();
h = p * h + optional.hashCode();
return h;
}
}
} }

View File

@ -576,7 +576,8 @@ public final class System {
* <tr><th>Key</th> * <tr><th>Key</th>
* <th>Description of Associated Value</th></tr> * <th>Description of Associated Value</th></tr>
* <tr><td><code>java.version</code></td> * <tr><td><code>java.version</code></td>
* <td>Java Runtime Environment version</td></tr> * <td>Java Runtime Environment version which may be interpreted
* as a {@link Runtime.Version}</td></tr>
* <tr><td><code>java.vendor</code></td> * <tr><td><code>java.vendor</code></td>
* <td>Java Runtime Environment vendor</td></tr> * <td>Java Runtime Environment vendor</td></tr>
* <tr><td><code>java.vendor.url</code></td> * <tr><td><code>java.vendor.url</code></td>
@ -584,19 +585,22 @@ public final class System {
* <tr><td><code>java.home</code></td> * <tr><td><code>java.home</code></td>
* <td>Java installation directory</td></tr> * <td>Java installation directory</td></tr>
* <tr><td><code>java.vm.specification.version</code></td> * <tr><td><code>java.vm.specification.version</code></td>
* <td>Java Virtual Machine specification version</td></tr> * <td>Java Virtual Machine specification version which may be
* interpreted as a {@link Runtime.Version}</td></tr>
* <tr><td><code>java.vm.specification.vendor</code></td> * <tr><td><code>java.vm.specification.vendor</code></td>
* <td>Java Virtual Machine specification vendor</td></tr> * <td>Java Virtual Machine specification vendor</td></tr>
* <tr><td><code>java.vm.specification.name</code></td> * <tr><td><code>java.vm.specification.name</code></td>
* <td>Java Virtual Machine specification name</td></tr> * <td>Java Virtual Machine specification name</td></tr>
* <tr><td><code>java.vm.version</code></td> * <tr><td><code>java.vm.version</code></td>
* <td>Java Virtual Machine implementation version</td></tr> * <td>Java Virtual Machine implementation version which may be
* interpreted as a {@link Runtime.Version}</td></tr>
* <tr><td><code>java.vm.vendor</code></td> * <tr><td><code>java.vm.vendor</code></td>
* <td>Java Virtual Machine implementation vendor</td></tr> * <td>Java Virtual Machine implementation vendor</td></tr>
* <tr><td><code>java.vm.name</code></td> * <tr><td><code>java.vm.name</code></td>
* <td>Java Virtual Machine implementation name</td></tr> * <td>Java Virtual Machine implementation name</td></tr>
* <tr><td><code>java.specification.version</code></td> * <tr><td><code>java.specification.version</code></td>
* <td>Java Runtime Environment specification version</td></tr> * <td>Java Runtime Environment specification version which may be
* interpreted as a {@link Runtime.Version}</td></tr>
* <tr><td><code>java.specification.vendor</code></td> * <tr><td><code>java.specification.vendor</code></td>
* <td>Java Runtime Environment specification vendor</td></tr> * <td>Java Runtime Environment specification vendor</td></tr>
* <tr><td><code>java.specification.name</code></td> * <tr><td><code>java.specification.name</code></td>

View File

@ -706,6 +706,9 @@ class InvokerBytecodeGenerator {
case ARRAY_STORE: case ARRAY_STORE:
emitArrayStore(name); emitArrayStore(name);
continue; continue;
case ARRAY_LENGTH:
emitArrayLength(name);
continue;
case IDENTITY: case IDENTITY:
assert(name.arguments.length == 1); assert(name.arguments.length == 1);
emitPushArguments(name); emitPushArguments(name);
@ -740,15 +743,16 @@ class InvokerBytecodeGenerator {
return classFile; return classFile;
} }
void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); } void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); }
void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); } void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
void emitArrayLength(Name name) { emitArrayOp(name, Opcodes.ARRAYLENGTH); }
void emitArrayOp(Name name, int arrayOpcode) { 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(); Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
assert elementType != null; assert elementType != null;
emitPushArguments(name); emitPushArguments(name);
if (elementType.isPrimitive()) { if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) {
Wrapper w = Wrapper.forPrimitiveType(elementType); Wrapper w = Wrapper.forPrimitiveType(elementType);
arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode); arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
} }

View File

@ -95,12 +95,12 @@ class Invokers {
/*non-public*/ MethodHandle varHandleMethodInvoker(VarHandle.AccessMode ak) { /*non-public*/ MethodHandle varHandleMethodInvoker(VarHandle.AccessMode ak) {
// TODO cache invoker // TODO cache invoker
return makeVarHandleMethodInvoker(ak); return makeVarHandleMethodInvoker(ak, false);
} }
/*non-public*/ MethodHandle varHandleMethodExactInvoker(VarHandle.AccessMode ak) { /*non-public*/ MethodHandle varHandleMethodExactInvoker(VarHandle.AccessMode ak) {
// TODO cache invoker // TODO cache invoker
return makeVarHandleMethodExactInvoker(ak); return makeVarHandleMethodInvoker(ak, true);
} }
private MethodHandle cachedInvoker(int idx) { private MethodHandle cachedInvoker(int idx) {
@ -127,26 +127,11 @@ class Invokers {
return invoker; return invoker;
} }
private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak) { private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak, boolean isExact) {
MethodType mtype = targetType; MethodType mtype = targetType;
MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class); MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class);
LambdaForm lform = varHandleMethodGenericInvokerHandleForm(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);
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);
VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal()); VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal());
MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad); MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad);
@ -400,59 +385,7 @@ class Invokers {
return lform; return lform;
} }
private static LambdaForm varHandleMethodExactInvokerHandleForm(String name, MethodType mtype) { private static LambdaForm varHandleMethodInvokerHandleForm(String name, MethodType mtype, boolean isExact) {
// 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) {
// TODO Cache form? // TODO Cache form?
final int THIS_MH = 0; final int THIS_MH = 0;
@ -477,8 +410,11 @@ class Invokers {
NamedFunction getter = speciesData.getterFunction(0); NamedFunction getter = speciesData.getterFunction(0);
names[VAD_ARG] = new Name(getter, names[THIS_MH]); 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]; Object[] outArgs = new Object[ARG_LIMIT];
outArgs[0] = names[CHECK_TYPE]; outArgs[0] = names[CHECK_TYPE];
for (int i = 1; i < ARG_LIMIT; i++) { for (int i = 1; i < ARG_LIMIT; i++) {
@ -488,7 +424,8 @@ class Invokers {
MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class)
.basicType(); .basicType();
names[LINKER_CALL] = new Name(outCallType, outArgs); 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); ARG_LIMIT, names);
lform.prepare(); lform.prepare();
@ -511,21 +448,13 @@ class Invokers {
/*non-public*/ static /*non-public*/ static
@ForceInline @ForceInline
void checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) { MethodHandle checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) {
MethodType erasedTarget = handle.vform.methodType_table[ad.type]; MethodHandle mh = handle.getMethodHandle(ad.mode);
MethodType erasedSymbolic = ad.symbolicMethodTypeErased; MethodType mt = mh.type();
if (erasedTarget != erasedSymbolic) if (mt != ad.symbolicMethodTypeInvoker) {
throw newWrongMethodTypeException(erasedTarget, erasedSymbolic); throw newWrongMethodTypeException(mt, ad.symbolicMethodTypeInvoker);
}
/*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();
} }
return mn; return mh;
} }
/*non-public*/ static /*non-public*/ static
@ -649,8 +578,7 @@ class Invokers {
NF_getCallSiteTarget, NF_getCallSiteTarget,
NF_checkCustomized, NF_checkCustomized,
NF_checkVarHandleGenericType, NF_checkVarHandleGenericType,
NF_checkVarHandleExactType, NF_checkVarHandleExactType;
NF_getVarHandleMemberName;
static { static {
try { try {
NamedFunction nfs[] = { NamedFunction nfs[] = {
@ -666,8 +594,6 @@ class Invokers {
.getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)), .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)),
NF_checkVarHandleExactType = new NamedFunction(Invokers.class NF_checkVarHandleExactType = new NamedFunction(Invokers.class
.getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.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. // Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs)); assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));

View File

@ -41,9 +41,15 @@ import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType; import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/** /**
* Trusted implementation code for MethodHandle. * Trusted implementation code for MethodHandle.
@ -66,25 +72,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/// Factory methods to create method handles: /// Factory methods to create method handles:
static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) { static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, ArrayAccess access) {
if (arrayClass == Object[].class) if (arrayClass == Object[].class) {
return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); return ArrayAccess.objectAccessor(access);
}
if (!arrayClass.isArray()) if (!arrayClass.isArray())
throw newIllegalArgumentException("not an array: "+arrayClass); throw newIllegalArgumentException("not an array: "+arrayClass);
MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(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]; MethodHandle mh = cache[cacheIndex];
if (mh != null) return mh; if (mh != null) return mh;
mh = ArrayAccessor.getAccessor(arrayClass, isSetter); mh = ArrayAccessor.getAccessor(arrayClass, access);
MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); MethodType correctType = ArrayAccessor.correctType(arrayClass, access);
if (mh.type() != correctType) { if (mh.type() != correctType) {
assert(mh.type().parameterType(0) == Object[].class); assert(mh.type().parameterType(0) == Object[].class);
assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); /* if access == SET */ assert(access != ArrayAccess.SET || mh.type().parameterType(2) == Object.class);
assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); /* 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 // safe to view non-strictly, because element type follows from array type
mh = mh.viewAsType(correctType, false); 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. // Atomically update accessor cache.
synchronized(cache) { synchronized(cache) {
if (cache[cacheIndex] == null) { if (cache[cacheIndex] == null) {
@ -97,9 +106,52 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mh; 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 { static final class ArrayAccessor {
/// Support for array element access /// Support for array element and length access
static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; static final int GETTER_INDEX = 0, SETTER_INDEX = 1, LENGTH_INDEX = 2, INDEX_LIMIT = 3;
static final ClassValue<MethodHandle[]> TYPED_ACCESSORS static final ClassValue<MethodHandle[]> TYPED_ACCESSORS
= new ClassValue<MethodHandle[]>() { = new ClassValue<MethodHandle[]>() {
@Override @Override
@ -107,14 +159,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return new MethodHandle[INDEX_LIMIT]; 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 { static {
MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD); 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, true), Intrinsic.ARRAY_STORE); 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_GETTER.internalMemberName()));
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.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]; } static int getElementI(int[] a, int i) { return a[i]; }
@ -137,31 +191,47 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static void setElementC(char[] a, int i, char x) { a[i] = x; } 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 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(); Class<?> elemClass = arrayClass.getComponentType();
if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); 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<?> elemClass = arrayClass.getComponentType();
Class<?> arrayArgClass = arrayClass; Class<?> arrayArgClass = arrayClass;
if (!elemClass.isPrimitive()) { if (!elemClass.isPrimitive()) {
arrayArgClass = Object[].class; arrayArgClass = Object[].class;
elemClass = Object.class; elemClass = Object.class;
} }
return !isSetter ? switch (access) {
MethodType.methodType(elemClass, arrayArgClass, int.class) : case GET: return MethodType.methodType(elemClass, arrayArgClass, int.class);
MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); 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(); Class<?> elemClass = arrayClass.getComponentType();
return !isSetter ? switch (access) {
MethodType.methodType(elemClass, arrayClass, int.class) : case GET: return MethodType.methodType(elemClass, arrayClass, int.class);
MethodType.methodType(void.class, arrayClass, int.class, elemClass); 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) { static MethodHandle getAccessor(Class<?> arrayClass, ArrayAccess access) {
String name = name(arrayClass, isSetter); String name = name(arrayClass, access);
MethodType type = type(arrayClass, isSetter); MethodType type = type(arrayClass, access);
try { try {
return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type); return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
@ -1091,6 +1161,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// Put the whole mess into its own nested class. // Put the whole mess into its own nested class.
// That way we can lazily load the code and set up the constants. // That way we can lazily load the code and set up the constants.
private static class BindCaller { private static class BindCaller {
private static MethodType INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
static static
MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
// Do not use this function to inject calls into system classes. // Do not use this function to inject calls into system classes.
@ -1109,38 +1181,15 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
if (hostClass.getClassLoader() != bcc.getClassLoader())
throw new InternalError(hostClass.getName()+" (CL)");
try { try {
if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, INJECTED_INVOKER_TEMPLATE, null);
throw new InternalError(hostClass.getName()+" (PD)"); assert checkInjectedInvoker(hostClass, invokerClass);
} catch (SecurityException ex) { return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
// Self-check was blocked by security manager. This is OK.
// In fact the whole try body could be turned into an assertion.
}
try {
MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
init.invokeExact(); // force initialization of the class
} catch (Throwable ex) {
throw uncaughtException(ex);
}
MethodHandle bccInvoker;
try {
MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
// Test the invoker, to ensure that it really injects into the right place.
try {
MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
} catch (Throwable ex) {
throw new InternalError(ex);
}
return bccInvoker;
} }
private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
@Override protected MethodHandle computeValue(Class<?> hostClass) { @Override protected MethodHandle computeValue(Class<?> hostClass) {
return makeInjectedInvoker(hostClass); return makeInjectedInvoker(hostClass);
@ -1171,62 +1220,82 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mh; return mh;
} }
private static boolean checkInjectedInvoker(Class<?> hostClass, Class<?> invokerClass) {
assert (hostClass.getClassLoader() == invokerClass.getClassLoader()) : hostClass.getName()+" (CL)";
try {
assert (hostClass.getProtectionDomain() == invokerClass.getProtectionDomain()) : hostClass.getName()+" (PD)";
} catch (SecurityException ex) {
// Self-check was blocked by security manager. This is OK.
}
try {
// Test the invoker to ensure that it really injects into the right place.
MethodHandle invoker = IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
return (boolean)invoker.invoke(vamh, new Object[]{ invokerClass });
} catch (Throwable ex) {
throw new InternalError(ex);
}
}
private static final MethodHandle MH_checkCallerClass; private static final MethodHandle MH_checkCallerClass;
static { static {
final Class<?> THIS_CLASS = BindCaller.class; final Class<?> THIS_CLASS = BindCaller.class;
assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); assert(checkCallerClass(THIS_CLASS));
try { try {
MH_checkCallerClass = IMPL_LOOKUP MH_checkCallerClass = IMPL_LOOKUP
.findStatic(THIS_CLASS, "checkCallerClass", .findStatic(THIS_CLASS, "checkCallerClass",
MethodType.methodType(boolean.class, Class.class, Class.class)); MethodType.methodType(boolean.class, Class.class));
assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS));
} catch (Throwable ex) { } catch (Throwable ex) {
throw new InternalError(ex); throw new InternalError(ex);
} }
} }
@CallerSensitive @CallerSensitive
private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { private static boolean checkCallerClass(Class<?> expected) {
// This method is called via MH_checkCallerClass and so it's // This method is called via MH_checkCallerClass and so it's correct to ask for the immediate caller here.
// correct to ask for the immediate caller here.
Class<?> actual = Reflection.getCallerClass(); Class<?> actual = Reflection.getCallerClass();
if (actual != expected && actual != expected2) if (actual != expected)
throw new InternalError("found "+actual.getName()+", expected "+expected.getName() throw new InternalError("found " + actual.getName() + ", expected " + expected.getName());
+(expected == expected2 ? "" : ", or else "+expected2.getName()));
return true; return true;
} }
private static final byte[] T_BYTES; private static final byte[] INJECTED_INVOKER_TEMPLATE = generateInvokerTemplate();
static {
final Object[] values = {null};
AccessController.doPrivileged(new PrivilegedAction<>() {
public Void run() {
try {
Class<T> tClass = T.class;
String tName = tClass.getName();
String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
try (java.io.InputStream in = tClass.getResourceAsStream(tResource)) {
values[0] = in.readAllBytes();
}
} catch (java.io.IOException ex) {
throw new InternalError(ex);
}
return null;
}
});
T_BYTES = (byte[]) values[0];
}
// The following class is used as a template for Unsafe.defineAnonymousClass: /** Produces byte code for a class that is used as an injected invoker. */
private static class T { private static byte[] generateInvokerTemplate() {
static void init() { } // side effect: initializes this class ClassWriter cw = new ClassWriter(0);
static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
return vamh.invokeExact(args); // private static class InjectedInvoker {
} // @Hidden
// static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
// return vamh.invokeExact(args);
// }
// }
cw.visit(52, ACC_PRIVATE | ACC_SUPER, "InjectedInvoker", null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(ACC_STATIC, "invoke_V",
"(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
null, null);
// Suppress invoker method in stack traces.
AnnotationVisitor av0 = mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
av0.visitEnd();
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact",
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
} }
} }
/** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
private static final class WrappedMember extends DelegatingMethodHandle { private static final class WrappedMember extends DelegatingMethodHandle {
private final MethodHandle target; private final MethodHandle target;
@ -1282,6 +1351,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
NEW_ARRAY, NEW_ARRAY,
ARRAY_LOAD, ARRAY_LOAD,
ARRAY_STORE, ARRAY_STORE,
ARRAY_LENGTH,
IDENTITY, IDENTITY,
ZERO, ZERO,
NONE // no intrinsic associated NONE // no intrinsic associated

View File

@ -2244,6 +2244,20 @@ return mh1;
return ani.asType(ani.type().changeReturnType(arrayClass)); 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. * 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 * The type of the method handle will have a return type of the array's
@ -2256,7 +2270,7 @@ return mh1;
*/ */
public static public static
MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException { 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 public static
MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException { MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true); return MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.SET);
} }
/** /**

View File

@ -128,7 +128,7 @@ public final class StringConcatFactory {
/** /**
* Default strategy to use for concatenation. * Default strategy to use for concatenation.
*/ */
private static final Strategy DEFAULT_STRATEGY = Strategy.BC_SB; private static final Strategy DEFAULT_STRATEGY = Strategy.MH_INLINE_SIZED_EXACT;
private enum Strategy { private enum Strategy {
/** /**

View File

@ -1475,11 +1475,11 @@ public abstract class VarHandle {
TypesAndInvokers tis = getTypesAndInvokers(); TypesAndInvokers tis = getTypesAndInvokers();
MethodHandle mh = tis.methodHandle_table[mode]; MethodHandle mh = tis.methodHandle_table[mode];
if (mh == null) { if (mh == null) {
mh = tis.methodHandle_table[mode] = getMethodHandleUncached(tis, mode); mh = tis.methodHandle_table[mode] = getMethodHandleUncached(mode);
} }
return mh; return mh;
} }
private final MethodHandle getMethodHandleUncached(TypesAndInvokers tis, int mode) { private final MethodHandle getMethodHandleUncached(int mode) {
MethodType mt = accessModeType(AccessMode.values()[mode]). MethodType mt = accessModeType(AccessMode.values()[mode]).
insertParameterTypes(0, VarHandle.class); insertParameterTypes(0, VarHandle.class);
MemberName mn = vform.getMemberName(mode); MemberName mn = vform.getMemberName(mode);

View File

@ -165,8 +165,7 @@ final class VarHandle$Type$s {
@ForceInline @ForceInline
static boolean weakCompareAndSetVolatile(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) { static boolean weakCompareAndSetVolatile(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) {
// TODO defer to strong form until new Unsafe method is added return UNSAFE.weakCompareAndSwap$Type$Volatile(Objects.requireNonNull(handle.receiverType.cast(holder)),
return UNSAFE.compareAndSwap$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
handle.fieldOffset, handle.fieldOffset,
{#if[Object]?handle.fieldType.cast(expected):expected}, {#if[Object]?handle.fieldType.cast(expected):expected},
{#if[Object]?handle.fieldType.cast(value):value}); {#if[Object]?handle.fieldType.cast(value):value});
@ -347,8 +346,7 @@ final class VarHandle$Type$s {
@ForceInline @ForceInline
static boolean weakCompareAndSetVolatile(FieldStaticReadWrite handle, $type$ expected, $type$ value) { static boolean weakCompareAndSetVolatile(FieldStaticReadWrite handle, $type$ expected, $type$ value) {
// TODO defer to strong form until new Unsafe method is added return UNSAFE.weakCompareAndSwap$Type$Volatile(handle.base,
return UNSAFE.compareAndSwap$Type$(handle.base,
handle.fieldOffset, handle.fieldOffset,
{#if[Object]?handle.fieldType.cast(expected):expected}, {#if[Object]?handle.fieldType.cast(expected):expected},
{#if[Object]?handle.fieldType.cast(value):value}); {#if[Object]?handle.fieldType.cast(value):value});
@ -583,8 +581,7 @@ final class VarHandle$Type$s {
#else[Object] #else[Object]
$type$[] array = ($type$[]) oarray; $type$[] array = ($type$[]) oarray;
#end[Object] #end[Object]
// TODO defer to strong form until new Unsafe method is added return UNSAFE.weakCompareAndSwap$Type$Volatile(array,
return UNSAFE.compareAndSwap$Type$(array,
(((long) Preconditions.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(expected):expected},
{#if[Object]?handle.componentType.cast(value):value}); {#if[Object]?handle.componentType.cast(value):value});

View File

@ -234,8 +234,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
@ForceInline @ForceInline
static boolean weakCompareAndSetVolatile(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) { static boolean weakCompareAndSetVolatile(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) {
byte[] ba = (byte[]) oba; byte[] ba = (byte[]) oba;
// TODO defer to strong form until new Unsafe method is added return UNSAFE.weakCompareAndSwap$RawType$Volatile(
return UNSAFE.compareAndSwap$RawType$(
ba, ba,
address(ba, index(ba, index)), address(ba, index(ba, index)),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
@ -272,22 +271,33 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
#if[AtomicAdd] #if[AtomicAdd]
@ForceInline @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; byte[] ba = (byte[]) oba;
return convEndian(handle.be, if (handle.be == BE) {
UNSAFE.getAndAdd$RawType$( return UNSAFE.getAndAdd$RawType$(
ba, ba,
address(ba, index(ba, index)), address(ba, index(ba, index)),
convEndian(handle.be, value))); delta);
} else {
return getAndAddConvEndianWithCAS(ba, index, delta);
}
} }
@ForceInline @ForceInline
static $type$ addAndGet(ArrayHandle handle, Object oba, int index, $type$ value) { static $type$ getAndAddConvEndianWithCAS(byte[] ba, int index, $type$ delta) {
byte[] ba = (byte[]) oba; $type$ nativeExpectedValue, expectedValue;
return convEndian(handle.be, UNSAFE.getAndAdd$RawType$( long offset = address(ba, index(ba, index));
ba, do {
address(ba, index(ba, index)), nativeExpectedValue = UNSAFE.get$RawType$Volatile(ba, offset);
convEndian(handle.be, value))) + value; 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] #end[AtomicAdd]
@ -467,8 +477,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
@ForceInline @ForceInline
static boolean weakCompareAndSetVolatile(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) { static boolean weakCompareAndSetVolatile(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) {
ByteBuffer bb = (ByteBuffer) obb; ByteBuffer bb = (ByteBuffer) obb;
// TODO defer to strong form until new Unsafe method is added return UNSAFE.weakCompareAndSwap$RawType$Volatile(
return UNSAFE.compareAndSwap$RawType$(
UNSAFE.getObject(bb, BYTE_BUFFER_HB), UNSAFE.getObject(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)), address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
@ -505,23 +514,34 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
#if[AtomicAdd] #if[AtomicAdd]
@ForceInline @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; ByteBuffer bb = (ByteBuffer) obb;
return convEndian(handle.be, if (handle.be == BE) {
UNSAFE.getAndAdd$RawType$( return UNSAFE.getAndAdd$RawType$(
UNSAFE.getObject(bb, BYTE_BUFFER_HB), UNSAFE.getObject(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)), address(bb, indexRO(bb, index)),
convEndian(handle.be, value))); delta);
} else {
return getAndAddConvEndianWithCAS(bb, index, delta);
}
} }
@ForceInline @ForceInline
static $type$ addAndGet(ByteBufferHandle handle, Object obb, int index, $type$ value) { static $type$ getAndAddConvEndianWithCAS(ByteBuffer bb, int index, $type$ delta) {
ByteBuffer bb = (ByteBuffer) obb; $type$ nativeExpectedValue, expectedValue;
return convEndian(handle.be, Object base = UNSAFE.getObject(bb, BYTE_BUFFER_HB);
UNSAFE.getAndAdd$RawType$( long offset = address(bb, indexRO(bb, index));
UNSAFE.getObject(bb, BYTE_BUFFER_HB), do {
address(bb, indexRO(bb, index)), nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
convEndian(handle.be, value))) + value; 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] #end[AtomicAdd]

View File

@ -154,7 +154,7 @@ final class ModuleInfo {
int minor_version = in.readUnsignedShort(); int minor_version = in.readUnsignedShort();
int major_version = in.readUnsignedShort(); int major_version = in.readUnsignedShort();
if (major_version < 53) { if (major_version < 53) {
// throw invalidModuleDescriptor"Must be >= 53.0"); throw invalidModuleDescriptor("Must be >= 53.0");
} }
ConstantPool cpool = new ConstantPool(in); ConstantPool cpool = new ConstantPool(in);

View File

@ -45,6 +45,7 @@ import jdk.internal.jimage.ImageLocation;
import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReader;
import jdk.internal.jimage.ImageReaderFactory; import jdk.internal.jimage.ImageReaderFactory;
import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleHashes.HashSupplier;
import jdk.internal.module.SystemModules; import jdk.internal.module.SystemModules;
import jdk.internal.module.ModulePatcher; import jdk.internal.module.ModulePatcher;
import jdk.internal.perf.PerfCounter; import jdk.internal.perf.PerfCounter;
@ -84,57 +85,23 @@ class SystemModuleFinder implements ModuleFinder {
long t0 = System.nanoTime(); long t0 = System.nanoTime();
imageReader = ImageReaderFactory.getImageReader(); imageReader = ImageReaderFactory.getImageReader();
String[] moduleNames = SystemModules.MODULE_NAMES; String[] names = moduleNames();
ModuleDescriptor[] descriptors = null; ModuleDescriptor[] descriptors = descriptors(names);
boolean fastLoad = System.getProperty("jdk.installed.modules.disable") == null; int n = names.length;
if (fastLoad) {
// fast loading of ModuleDescriptor of installed modules
descriptors = SystemModules.modules();
}
int n = moduleNames.length;
moduleCount.add(n); moduleCount.add(n);
Set<ModuleReference> mods = new HashSet<>(n); Set<ModuleReference> mods = new HashSet<>(n);
Map<String, ModuleReference> map = new HashMap<>(n); Map<String, ModuleReference> map = new HashMap<>(n);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
String mn = moduleNames[i]; ModuleDescriptor md = descriptors[i];
ModuleDescriptor md;
String hash;
if (fastLoad) {
md = descriptors[i];
hash = SystemModules.MODULES_TO_HASH[i];
} else {
// fallback to read module-info.class
// if fast loading of ModuleDescriptors is disabled
ImageLocation location = imageReader.findLocation(mn, "module-info.class");
md = ModuleDescriptor.read(imageReader.getResourceBuffer(location));
hash = null;
}
if (!md.name().equals(mn))
throw new InternalError();
// create the ModuleReference // create the ModuleReference
ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
URI uri = URI.create("jrt:/" + mn);
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
@Override
public ModuleReader get() {
return new ImageModuleReader(mn, uri);
}
};
ModuleReference mref =
new ModuleReference(md, uri, readerSupplier, hashSupplier(hash));
// may need a reference to a patched module if -Xpatch specified
mref = ModulePatcher.interposeIfNeeded(mref);
mods.add(mref); mods.add(mref);
map.put(mn, mref); map.put(names[i], mref);
// counters // counters
packageCount.add(md.packages().size()); packageCount.add(md.packages().size());
@ -147,16 +114,114 @@ class SystemModuleFinder implements ModuleFinder {
initTime.addElapsedTimeFrom(t0); initTime.addElapsedTimeFrom(t0);
} }
private static ModuleHashes.HashSupplier hashSupplier(String hash) { /*
if (hash == null) * Returns an array of ModuleDescriptor of the given module names.
return null; *
* This obtains ModuleDescriptors from SystemModules class that is generated
* from the jlink system-modules plugin. ModuleDescriptors have already
* been validated at link time.
*
* If java.base is patched, or fastpath is disabled for troubleshooting
* purpose, it will fall back to find system modules via jrt file system.
*/
private static ModuleDescriptor[] descriptors(String[] names) {
// fastpath is enabled by default.
// It can be disabled for troubleshooting purpose.
boolean disabled =
System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
return new ModuleHashes.HashSupplier() { // fast loading of ModuleDescriptor of system modules
if (isFastPathSupported() && !disabled)
return SystemModules.modules();
// if fast loading of ModuleDescriptors is disabled
// fallback to read module-info.class
ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
for (int i = 0; i < names.length; i++) {
String mn = names[i];
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
// add the recorded hashes of tied modules
Hashes.add(descriptors[i]);
}
return descriptors;
}
private static boolean isFastPathSupported() {
return SystemModules.MODULE_NAMES.length > 0;
}
private static String[] moduleNames() {
if (isFastPathSupported())
// module names recorded at link time
return SystemModules.MODULE_NAMES;
// this happens when java.base is patched with java.base
// from an exploded image
return imageReader.getModuleNames();
}
private static ModuleReference toModuleReference(ModuleDescriptor md,
HashSupplier hash)
{
String mn = md.name();
URI uri = URI.create("jrt:/" + mn);
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
@Override @Override
public String generate(String algorithm) { public ModuleReader get() {
return hash; return new ImageModuleReader(mn, uri);
} }
}; };
ModuleReference mref =
new ModuleReference(md, uri, readerSupplier, hash);
// may need a reference to a patched module if -Xpatch specified
mref = ModulePatcher.interposeIfNeeded(mref);
return mref;
}
private static HashSupplier hashSupplier(int index, String name) {
if (isFastPathSupported()) {
return new HashSupplier() {
@Override
public String generate(String algorithm) {
return SystemModules.MODULES_TO_HASH[index];
}
};
} else {
return Hashes.hashFor(name);
}
}
/*
* This helper class is only used when SystemModules is patched.
* It will get the recorded hashes from module-info.class.
*/
private static class Hashes {
static Map<String, String> hashes = new HashMap<>();
static void add(ModuleDescriptor descriptor) {
Optional<ModuleHashes> ohashes = descriptor.hashes();
if (ohashes.isPresent()) {
hashes.putAll(ohashes.get().hashes());
}
}
static HashSupplier hashFor(String name) {
if (!hashes.containsKey(name))
return null;
return new HashSupplier() {
@Override
public String generate(String algorithm) {
return hashes.get(name);
}
};
}
} }
SystemModuleFinder() { } SystemModuleFinder() { }

View File

@ -111,7 +111,7 @@ import java.util.Spliterator;
* to zero. * to zero.
* *
* *
* <h2> Clearing, flipping, and rewinding </h2> * <h2> Additional operations </h2>
* *
* <p> In addition to methods for accessing the position, limit, and capacity * <p> In addition to methods for accessing the position, limit, and capacity
* values and for marking and resetting, this class also defines the following * 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 * it already contains: It leaves the limit unchanged and sets the position
* to zero. </p></li> * to zero. </p></li>
* *
* <li><p> {@link #slice} creates a subsequence of a buffer: It leaves the
* limit and the position unchanged. </p></li>
*
* <li><p> {@link #duplicate} creates a shallow copy of a buffer: It leaves
* the limit and the position unchanged. </p></li>
*
* </ul> * </ul>
* *
* *
@ -567,6 +573,46 @@ public abstract class Buffer {
*/ */
public abstract boolean isDirect(); public abstract boolean isDirect();
/**
* Creates a new buffer whose content is a shared subsequence of
* this buffer's content.
*
* <p> 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.
*
* <p> 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. </p>
*
* @return The new buffer
*
* @since 9
*/
public abstract Buffer slice();
/**
* Creates a new buffer that shares this buffer's content.
*
* <p> 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.
*
* <p> 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. </p>
*
* @return The new buffer
*
* @since 9
*/
public abstract Buffer duplicate();
// -- Package-private methods for bounds checking, etc. -- // -- Package-private methods for bounds checking, etc. --

View File

@ -70,8 +70,7 @@ import java.util.stream.$Streamtype$Stream;
* *
#end[byte] #end[byte]
* *
* <li><p> Methods for {@link #compact compacting}, {@link * <li><p> A method for {@link #compact compacting}
* #duplicate duplicating}, and {@link #slice slicing}
* $a$ $type$ buffer. </p></li> * $a$ $type$ buffer. </p></li>
* *
* </ul> * </ul>
@ -535,6 +534,7 @@ public abstract class $Type$Buffer
* @see #alignedSlice(int) * @see #alignedSlice(int)
#end[byte] #end[byte]
*/ */
@Override
public abstract $Type$Buffer slice(); public abstract $Type$Buffer slice();
/** /**
@ -557,6 +557,7 @@ public abstract class $Type$Buffer
* *
* @return The new $type$ buffer * @return The new $type$ buffer
*/ */
@Override
public abstract $Type$Buffer duplicate(); public abstract $Type$Buffer duplicate();
/** /**

View File

@ -153,33 +153,13 @@ public final class Currency implements Serializable {
// - bits 0-4: final char for currency code for simple country, or ID of special case // - bits 0-4: final char for currency code for simple country, or ID of special case
// - special case IDs: // - special case IDs:
// - 0: country has no currency // - 0: country has no currency
// - other: index into sc* arrays + 1 // - other: index into specialCasesList
// - scCutOverTimes: cut-over time in millis as returned by
// System.currentTimeMillis for special case countries that are changing
// currencies; Long.MAX_VALUE for countries that are not changing currencies
// - scOldCurrencies: old currencies for special case countries
// - scNewCurrencies: new currencies for special case countries that are
// changing currencies; null for others
// - scOldCurrenciesDFD: default fraction digits for old currencies
// - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
// countries that are not changing currencies
// - otherCurrencies: concatenation of all currency codes that are not the
// main currency of a simple country, separated by "-"
// - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
static int formatVersion; static int formatVersion;
static int dataVersion; static int dataVersion;
static int[] mainTable; static int[] mainTable;
static long[] scCutOverTimes; static List<SpecialCaseEntry> specialCasesList;
static String[] scOldCurrencies; static List<OtherCurrencyEntry> otherCurrenciesList;
static String[] scNewCurrencies;
static int[] scOldCurrenciesDFD;
static int[] scNewCurrenciesDFD;
static int[] scOldCurrenciesNumericCode;
static int[] scNewCurrenciesNumericCode;
static String otherCurrencies;
static int[] otherCurrenciesDFD;
static int[] otherCurrenciesNumericCode;
// handy constants - must match definitions in GenerateCurrencyData // handy constants - must match definitions in GenerateCurrencyData
// magic number // magic number
@ -214,7 +194,7 @@ public final class Currency implements Serializable {
private static final int NUMERIC_CODE_SHIFT = 10; private static final int NUMERIC_CODE_SHIFT = 10;
// Currency data format version // Currency data format version
private static final int VALID_FORMAT_VERSION = 2; private static final int VALID_FORMAT_VERSION = 3;
static { static {
AccessController.doPrivileged(new PrivilegedAction<>() { AccessController.doPrivileged(new PrivilegedAction<>() {
@ -236,17 +216,9 @@ public final class Currency implements Serializable {
dataVersion = dis.readInt(); dataVersion = dis.readInt();
mainTable = readIntArray(dis, A_TO_Z * A_TO_Z); mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
int scCount = dis.readInt(); int scCount = dis.readInt();
scCutOverTimes = readLongArray(dis, scCount); specialCasesList = readSpecialCases(dis, scCount);
scOldCurrencies = readStringArray(dis, scCount);
scNewCurrencies = readStringArray(dis, scCount);
scOldCurrenciesDFD = readIntArray(dis, scCount);
scNewCurrenciesDFD = readIntArray(dis, scCount);
scOldCurrenciesNumericCode = readIntArray(dis, scCount);
scNewCurrenciesNumericCode = readIntArray(dis, scCount);
int ocCount = dis.readInt(); int ocCount = dis.readInt();
otherCurrencies = dis.readUTF(); otherCurrenciesList = readOtherCurrencies(dis, ocCount);
otherCurrenciesDFD = readIntArray(dis, ocCount);
otherCurrenciesNumericCode = readIntArray(dis, ocCount);
} }
} catch (IOException e) { } catch (IOException e) {
throw new InternalError(e); throw new InternalError(e);
@ -329,6 +301,7 @@ public final class Currency implements Serializable {
// Currency code not internally generated, need to verify first // Currency code not internally generated, need to verify first
// A currency code must have 3 characters and exist in the main table // A currency code must have 3 characters and exist in the main table
// or in the list of other currencies. // or in the list of other currencies.
boolean found = false;
if (currencyCode.length() != 3) { if (currencyCode.length() != 3) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -340,17 +313,23 @@ public final class Currency implements Serializable {
&& currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) { && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT; defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT; numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
} else { found = true;
// Check for '-' separately so we don't get false hits in the table. } else { //special case
if (currencyCode.charAt(2) == '-') { int[] fractionAndNumericCode = SpecialCaseEntry.findEntry(currencyCode);
if (fractionAndNumericCode != null) {
defaultFractionDigits = fractionAndNumericCode[0];
numericCode = fractionAndNumericCode[1];
found = true;
}
}
if (!found) {
OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode);
if (ocEntry == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
int index = otherCurrencies.indexOf(currencyCode); defaultFractionDigits = ocEntry.fraction;
if (index == -1) { numericCode = ocEntry.numericCode;
throw new IllegalArgumentException();
}
defaultFractionDigits = otherCurrenciesDFD[index / 4];
numericCode = otherCurrenciesNumericCode[index / 4];
} }
} }
@ -410,13 +389,17 @@ public final class Currency implements Serializable {
if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) { if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
return null; return null;
} else { } else {
int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA; int index = SpecialCaseEntry.toIndex(tableEntry);
if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) { SpecialCaseEntry scEntry = specialCasesList.get(index);
return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index], if (scEntry.cutOverTime == Long.MAX_VALUE
scOldCurrenciesNumericCode[index]); || System.currentTimeMillis() < scEntry.cutOverTime) {
return getInstance(scEntry.oldCurrency,
scEntry.oldCurrencyFraction,
scEntry.oldCurrencyNumericCode);
} else { } else {
return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index], return getInstance(scEntry.newCurrency,
scNewCurrenciesNumericCode[index]); scEntry.newCurrencyFraction,
scEntry.newCurrencyNumericCode);
} }
} }
} }
@ -451,14 +434,29 @@ public final class Currency implements Serializable {
sb.append(c2); sb.append(c2);
sb.append(finalChar); sb.append(finalChar);
available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode)); available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
} else if ((tableEntry & COUNTRY_TYPE_MASK) == SPECIAL_CASE_COUNTRY_MASK
&& tableEntry != INVALID_COUNTRY_ENTRY
&& tableEntry != COUNTRY_WITHOUT_CURRENCY_ENTRY) {
int index = SpecialCaseEntry.toIndex(tableEntry);
SpecialCaseEntry scEntry = specialCasesList.get(index);
if (scEntry.cutOverTime == Long.MAX_VALUE
|| System.currentTimeMillis() < scEntry.cutOverTime) {
available.add(getInstance(scEntry.oldCurrency,
scEntry.oldCurrencyFraction,
scEntry.oldCurrencyNumericCode));
} else {
available.add(getInstance(scEntry.newCurrency,
scEntry.newCurrencyFraction,
scEntry.newCurrencyNumericCode));
}
} }
} }
} }
// Now add other currencies // Now add other currencies
StringTokenizer st = new StringTokenizer(otherCurrencies, "-"); for (OtherCurrencyEntry entry : otherCurrenciesList) {
while (st.hasMoreElements()) { available.add(getInstance(entry.currencyCode));
available.add(getInstance((String)st.nextElement()));
} }
} }
} }
@ -521,15 +519,15 @@ public final class Currency implements Serializable {
} }
/** /**
* Gets the default number of fraction digits used with this currency. * Gets the default number of fraction digits used with this currency.
* Note that the number of fraction digits is the same as ISO 4217's * Note that the number of fraction digits is the same as ISO 4217's
* minor unit for the currency. * minor unit for the currency.
* For example, the default number of fraction digits for the Euro is 2, * For example, the default number of fraction digits for the Euro is 2,
* while for the Japanese Yen it's 0. * while for the Japanese Yen it's 0.
* In the case of pseudo-currencies, such as IMF Special Drawing Rights, * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
* -1 is returned. * -1 is returned.
* *
* @return the default number of fraction digits used with this currency * @return the default number of fraction digits used with this currency
*/ */
public int getDefaultFractionDigits() { public int getDefaultFractionDigits() {
return defaultFractionDigits; return defaultFractionDigits;
@ -693,22 +691,55 @@ public final class Currency implements Serializable {
return ret; return ret;
} }
private static long[] readLongArray(DataInputStream dis, int count) throws IOException { private static List<SpecialCaseEntry> readSpecialCases(DataInputStream dis,
long[] ret = new long[count]; int count)
for (int i = 0; i < count; i++) { throws IOException {
ret[i] = dis.readLong();
}
return ret; List<SpecialCaseEntry> list = new ArrayList<>(count);
long cutOverTime;
String oldCurrency;
String newCurrency;
int oldCurrencyFraction;
int newCurrencyFraction;
int oldCurrencyNumericCode;
int newCurrencyNumericCode;
for (int i = 0; i < count; i++) {
cutOverTime = dis.readLong();
oldCurrency = dis.readUTF();
newCurrency = dis.readUTF();
oldCurrencyFraction = dis.readInt();
newCurrencyFraction = dis.readInt();
oldCurrencyNumericCode = dis.readInt();
newCurrencyNumericCode = dis.readInt();
SpecialCaseEntry sc = new SpecialCaseEntry(cutOverTime,
oldCurrency, newCurrency,
oldCurrencyFraction, newCurrencyFraction,
oldCurrencyNumericCode, newCurrencyNumericCode);
list.add(sc);
}
return list;
} }
private static String[] readStringArray(DataInputStream dis, int count) throws IOException { private static List<OtherCurrencyEntry> readOtherCurrencies(DataInputStream dis,
String[] ret = new String[count]; int count)
for (int i = 0; i < count; i++) { throws IOException {
ret[i] = dis.readUTF();
}
return ret; List<OtherCurrencyEntry> list = new ArrayList<>(count);
String currencyCode;
int fraction;
int numericCode;
for (int i = 0; i < count; i++) {
currencyCode = dis.readUTF();
fraction = dis.readInt();
numericCode = dis.readInt();
OtherCurrencyEntry oc = new OtherCurrencyEntry(currencyCode,
fraction,
numericCode);
list.add(oc);
}
return list;
} }
/** /**
@ -766,21 +797,27 @@ public final class Currency implements Serializable {
return; return;
} }
int index; int index = SpecialCaseEntry.indexOf(code, fraction, numeric);
for (index = 0; index < scOldCurrencies.length; index++) {
if (scOldCurrencies[index].equals(code)) { /* if a country switches from simple case to special case or
break; * one special case to other special case which is not present
} * in the sc arrays then insert the new entry in special case arrays
*/
if (index == -1 && (ctry.charAt(0) != code.charAt(0)
|| ctry.charAt(1) != code.charAt(1))) {
specialCasesList.add(new SpecialCaseEntry(code, fraction, numeric));
index = specialCasesList.size() - 1;
} }
if (index == scOldCurrencies.length) { if (index == -1) {
// simple case // simple case
entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) | entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT)
(code.charAt(2) - 'A'); | (code.charAt(2) - 'A');
} else { } else {
// special case // special case
entry |= SPECIAL_CASE_COUNTRY_MASK | entry = SPECIAL_CASE_COUNTRY_MASK
(index + SPECIAL_CASE_COUNTRY_INDEX_DELTA); | (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
} }
setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry); setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
} }
@ -814,5 +851,128 @@ public final class Currency implements Serializable {
} }
} }
} }
/* Used to represent a special case currency entry
* - cutOverTime: cut-over time in millis as returned by
* System.currentTimeMillis for special case countries that are changing
* currencies; Long.MAX_VALUE for countries that are not changing currencies
* - oldCurrency: old currencies for special case countries
* - newCurrency: new currencies for special case countries that are
* changing currencies; null for others
* - oldCurrencyFraction: default fraction digits for old currencies
* - newCurrencyFraction: default fraction digits for new currencies, 0 for
* countries that are not changing currencies
* - oldCurrencyNumericCode: numeric code for old currencies
* - newCurrencyNumericCode: numeric code for new currencies, 0 for countries
* that are not changing currencies
*/
private static class SpecialCaseEntry {
final private long cutOverTime;
final private String oldCurrency;
final private String newCurrency;
final private int oldCurrencyFraction;
final private int newCurrencyFraction;
final private int oldCurrencyNumericCode;
final private int newCurrencyNumericCode;
private SpecialCaseEntry(long cutOverTime, String oldCurrency, String newCurrency,
int oldCurrencyFraction, int newCurrencyFraction,
int oldCurrencyNumericCode, int newCurrencyNumericCode) {
this.cutOverTime = cutOverTime;
this.oldCurrency = oldCurrency;
this.newCurrency = newCurrency;
this.oldCurrencyFraction = oldCurrencyFraction;
this.newCurrencyFraction = newCurrencyFraction;
this.oldCurrencyNumericCode = oldCurrencyNumericCode;
this.newCurrencyNumericCode = newCurrencyNumericCode;
}
private SpecialCaseEntry(String currencyCode, int fraction,
int numericCode) {
this(Long.MAX_VALUE, currencyCode, "", fraction, 0, numericCode, 0);
}
//get the index of the special case entry
private static int indexOf(String code, int fraction, int numeric) {
int size = specialCasesList.size();
for (int index = 0; index < size; index++) {
SpecialCaseEntry scEntry = specialCasesList.get(index);
if (scEntry.oldCurrency.equals(code)
&& scEntry.oldCurrencyFraction == fraction
&& scEntry.oldCurrencyNumericCode == numeric
&& scEntry.cutOverTime == Long.MAX_VALUE) {
return index;
}
}
return -1;
}
// get the fraction and numericCode of the sc currencycode
private static int[] findEntry(String code) {
int[] fractionAndNumericCode = null;
int size = specialCasesList.size();
for (int index = 0; index < size; index++) {
SpecialCaseEntry scEntry = specialCasesList.get(index);
if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE
|| System.currentTimeMillis() < scEntry.cutOverTime)) {
//consider only when there is no new currency or cutover time is not passed
fractionAndNumericCode = new int[2];
fractionAndNumericCode[0] = scEntry.oldCurrencyFraction;
fractionAndNumericCode[1] = scEntry.oldCurrencyNumericCode;
break;
} else if (scEntry.newCurrency.equals(code)
&& System.currentTimeMillis() >= scEntry.cutOverTime) {
//consider only if the cutover time is passed
fractionAndNumericCode = new int[2];
fractionAndNumericCode[0] = scEntry.newCurrencyFraction;
fractionAndNumericCode[1] = scEntry.newCurrencyNumericCode;
break;
}
}
return fractionAndNumericCode;
}
// convert the special case entry to sc arrays index
private static int toIndex(int tableEntry) {
return (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
}
}
/* Used to represent Other currencies
* - currencyCode: currency codes that are not the main currency
* of a simple country
* - otherCurrenciesDFD: decimal format digits for other currencies
* - otherCurrenciesNumericCode: numeric code for other currencies
*/
private static class OtherCurrencyEntry {
final private String currencyCode;
final private int fraction;
final private int numericCode;
private OtherCurrencyEntry(String currencyCode, int fraction,
int numericCode) {
this.currencyCode = currencyCode;
this.fraction = fraction;
this.numericCode = numericCode;
}
//get the instance of the other currency code
private static OtherCurrencyEntry findEntry(String code) {
int size = otherCurrenciesList.size();
for (int index = 0; index < size; index++) {
OtherCurrencyEntry ocEntry = otherCurrenciesList.get(index);
if (ocEntry.currencyCode.equalsIgnoreCase(code)) {
return ocEntry;
}
}
return null;
}
}
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -146,12 +146,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge
@ -598,12 +612,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge
@ -1086,12 +1114,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge
@ -1574,12 +1616,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge
@ -2158,12 +2214,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge
@ -2701,12 +2771,26 @@ final class DualPivotQuicksort {
} }
} }
// Check special cases // These invariants should hold true:
// Implementation note: variable "right" is increased by 1. // run[0] = 0
if (run[count] == right++) { // The last run contains one element // run[<last>] = right + 1; (terminator)
run[++count] = right;
} else if (count <= 1) { // The array is already sorted if (count == 0) {
// A single equal run
return; 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 // Determine alternation base for merge

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -229,6 +229,14 @@ public class Hashtable<K,V>
putAll(t); putAll(t);
} }
/**
* A constructor chained from {@link Properties} keeps Hashtable fields
* uninitialized since they are not used.
*
* @param dummy a dummy parameter
*/
Hashtable(Void dummy) {}
/** /**
* Returns the number of keys in this hashtable. * Returns the number of keys in this hashtable.
* *
@ -549,18 +557,23 @@ public class Hashtable<K,V>
* @return a clone of the hashtable * @return a clone of the hashtable
*/ */
public synchronized Object clone() { public synchronized Object clone() {
Hashtable<?,?> t = cloneHashtable();
t.table = new Entry<?,?>[table.length];
for (int i = table.length ; i-- > 0 ; ) {
t.table[i] = (table[i] != null)
? (Entry<?,?>) table[i].clone() : null;
}
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
return t;
}
/** Calls super.clone() */
final Hashtable<?,?> cloneHashtable() {
try { try {
Hashtable<?,?> t = (Hashtable<?,?>)super.clone(); return (Hashtable<?,?>)super.clone();
t.table = new Entry<?,?>[table.length];
for (int i = table.length ; i-- > 0 ; ) {
t.table[i] = (table[i] != null)
? (Entry<?,?>) table[i].clone() : null;
}
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
return t;
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable // this shouldn't happen, since we are Cloneable
throw new InternalError(e); throw new InternalError(e);
@ -1189,6 +1202,15 @@ public class Hashtable<K,V>
*/ */
private void writeObject(java.io.ObjectOutputStream s) private void writeObject(java.io.ObjectOutputStream s)
throws IOException { throws IOException {
writeHashtable(s);
}
/**
* Perform serialization of the Hashtable to an ObjectOutputStream.
* The Properties class overrides this method.
*/
void writeHashtable(java.io.ObjectOutputStream s)
throws IOException {
Entry<Object, Object> entryStack = null; Entry<Object, Object> entryStack = null;
synchronized (this) { synchronized (this) {
@ -1218,12 +1240,30 @@ public class Hashtable<K,V>
} }
} }
/**
* Called by Properties to write out a simulated threshold and loadfactor.
*/
final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length,
float loadFactor) throws IOException {
this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
this.loadFactor = loadFactor;
s.defaultWriteObject();
}
/** /**
* Reconstitute the Hashtable from a stream (i.e., deserialize it). * Reconstitute the Hashtable from a stream (i.e., deserialize it).
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException throws IOException, ClassNotFoundException {
{ readHashtable(s);
}
/**
* Perform deserialization of the Hashtable from an ObjectInputStream.
* The Properties class overrides this method.
*/
void readHashtable(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the threshold and loadFactor // Read in the threshold and loadFactor
s.defaultReadObject(); s.defaultReadObject();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,13 @@ import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import jdk.internal.util.xml.PropertiesDefaultHandler; import jdk.internal.util.xml.PropertiesDefaultHandler;
@ -60,6 +67,13 @@ import jdk.internal.util.xml.PropertiesDefaultHandler;
* object that contains a non-{@code String} key. * object that contains a non-{@code String} key.
* *
* <p> * <p>
* The iterators returned by the {@code iterator} method of this class's
* "collection views" (that is, {@code entrySet()}, {@code keySet()}, and
* {@code values()}) may not fail-fast (unlike the Hashtable implementation).
* These iterators are guaranteed to traverse elements as they existed upon
* construction exactly once, and may (but are not guaranteed to) reflect any
* modifications subsequent to construction.
* <p>
* The {@link #load(java.io.Reader) load(Reader)} {@code /} * The {@link #load(java.io.Reader) load(Reader)} {@code /}
* {@link #store(java.io.Writer, java.lang.String) store(Writer, String)} * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
* methods load and store properties from and to a character based stream * methods load and store properties from and to a character based stream
@ -127,6 +141,15 @@ class Properties extends Hashtable<Object,Object> {
*/ */
protected Properties defaults; protected Properties defaults;
/**
* Properties does not store values in its inherited Hashtable, but instead
* in an internal ConcurrentHashMap. Synchronization is omitted from
* simple read operations. Writes and bulk operations remain synchronized,
* as in Hashtable.
*/
private transient ConcurrentHashMap<Object, Object> map =
new ConcurrentHashMap<>(8);
/** /**
* Creates an empty property list with no default values. * Creates an empty property list with no default values.
*/ */
@ -140,6 +163,9 @@ class Properties extends Hashtable<Object,Object> {
* @param defaults the defaults. * @param defaults the defaults.
*/ */
public Properties(Properties defaults) { public Properties(Properties defaults) {
// use package-private constructor to
// initialize unused fields with dummy values
super((Void) null);
this.defaults = defaults; this.defaults = defaults;
} }
@ -826,9 +852,9 @@ class Properties extends Hashtable<Object,Object> {
bw.write("#" + new Date().toString()); bw.write("#" + new Date().toString());
bw.newLine(); bw.newLine();
synchronized (this) { synchronized (this) {
for (Enumeration<?> e = keys(); e.hasMoreElements();) { for (Map.Entry<Object, Object> e : entrySet()) {
String key = (String)e.nextElement(); String key = (String)e.getKey();
String val = (String)get(key); String val = (String)e.getValue();
key = saveConvert(key, true, escUnicode); key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence /* No need to escape embedded and trailing spaces for value, hence
* pass false to flag. * pass false to flag.
@ -967,7 +993,7 @@ class Properties extends Hashtable<Object,Object> {
* @see #defaults * @see #defaults
*/ */
public String getProperty(String key) { public String getProperty(String key) {
Object oval = super.get(key); Object oval = map.get(key);
String sval = (oval instanceof String) ? (String)oval : null; String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval; return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
} }
@ -1029,7 +1055,7 @@ class Properties extends Hashtable<Object,Object> {
* @since 1.6 * @since 1.6
*/ */
public Set<String> stringPropertyNames() { public Set<String> stringPropertyNames() {
Hashtable<String, String> h = new Hashtable<>(); Map<String, String> h = new HashMap<>();
enumerateStringProperties(h); enumerateStringProperties(h);
return h.keySet(); return h.keySet();
} }
@ -1044,11 +1070,11 @@ class Properties extends Hashtable<Object,Object> {
*/ */
public void list(PrintStream out) { public void list(PrintStream out) {
out.println("-- listing properties --"); out.println("-- listing properties --");
Hashtable<String,Object> h = new Hashtable<>(); Map<String, Object> h = new HashMap<>();
enumerate(h); enumerate(h);
for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { for (Map.Entry<String, Object> e : h.entrySet()) {
String key = e.nextElement(); String key = e.getKey();
String val = (String)h.get(key); String val = (String)e.getValue();
if (val.length() > 40) { if (val.length() > 40) {
val = val.substring(0, 37) + "..."; val = val.substring(0, 37) + "...";
} }
@ -1072,11 +1098,11 @@ class Properties extends Hashtable<Object,Object> {
*/ */
public void list(PrintWriter out) { public void list(PrintWriter out) {
out.println("-- listing properties --"); out.println("-- listing properties --");
Hashtable<String,Object> h = new Hashtable<>(); Map<String, Object> h = new HashMap<>();
enumerate(h); enumerate(h);
for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { for (Map.Entry<String, Object> e : h.entrySet()) {
String key = e.nextElement(); String key = e.getKey();
String val = (String)h.get(key); String val = (String)e.getValue();
if (val.length() > 40) { if (val.length() > 40) {
val = val.substring(0, 37) + "..."; val = val.substring(0, 37) + "...";
} }
@ -1085,33 +1111,33 @@ class Properties extends Hashtable<Object,Object> {
} }
/** /**
* Enumerates all key/value pairs in the specified hashtable. * Enumerates all key/value pairs into the specified Map.
* @param h the hashtable * @param h the Map
* @throws ClassCastException if any of the property keys * @throws ClassCastException if any of the property keys
* is not of String type. * is not of String type.
*/ */
private synchronized void enumerate(Hashtable<String,Object> h) { private void enumerate(Map<String, Object> h) {
if (defaults != null) { if (defaults != null) {
defaults.enumerate(h); defaults.enumerate(h);
} }
for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { for (Map.Entry<Object, Object> e : entrySet()) {
String key = (String)e.nextElement(); String key = (String)e.getKey();
h.put(key, get(key)); h.put(key, e.getValue());
} }
} }
/** /**
* Enumerates all key/value pairs in the specified hashtable * Enumerates all key/value pairs into the specified Map
* and omits the property if the key or value is not a string. * and omits the property if the key or value is not a string.
* @param h the hashtable * @param h the Map
*/ */
private synchronized void enumerateStringProperties(Hashtable<String, String> h) { private void enumerateStringProperties(Map<String, String> h) {
if (defaults != null) { if (defaults != null) {
defaults.enumerateStringProperties(h); defaults.enumerateStringProperties(h);
} }
for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { for (Map.Entry<Object, Object> e : entrySet()) {
Object k = e.nextElement(); Object k = e.getKey();
Object v = get(k); Object v = e.getValue();
if (k instanceof String && v instanceof String) { if (k instanceof String && v instanceof String) {
h.put((String) k, (String) v); h.put((String) k, (String) v);
} }
@ -1130,4 +1156,283 @@ class Properties extends Hashtable<Object,Object> {
private static final char[] hexDigit = { private static final char[] hexDigit = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
}; };
//
// Hashtable methods overridden and delegated to a ConcurrentHashMap instance
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public Enumeration<Object> keys() {
// CHM.keys() returns Iterator w/ remove() - instead wrap keySet()
return Collections.enumeration(map.keySet());
}
@Override
public Enumeration<Object> elements() {
// CHM.elements() returns Iterator w/ remove() - instead wrap values()
return Collections.enumeration(map.values());
}
@Override
public boolean contains(Object value) {
return map.contains(value);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public Object get(Object key) {
return map.get(key);
}
@Override
public synchronized Object put(Object key, Object value) {
return map.put(key, value);
}
@Override
public synchronized Object remove(Object key) {
return map.remove(key);
}
@Override
public synchronized void putAll(Map<?, ?> t) {
map.putAll(t);
}
@Override
public synchronized void clear() {
map.clear();
}
@Override
public synchronized String toString() {
return map.toString();
}
@Override
public Set<Object> keySet() {
return Collections.synchronizedSet(map.keySet(), this);
}
@Override
public Collection<Object> values() {
return Collections.synchronizedCollection(map.values(), this);
}
@Override
public Set<Map.Entry<Object, Object>> entrySet() {
return Collections.synchronizedSet(new EntrySet(map.entrySet()), this);
}
/*
* Properties.entrySet() should not support add/addAll, however
* ConcurrentHashMap.entrySet() provides add/addAll. This class wraps the
* Set returned from CHM, changing add/addAll to throw UOE.
*/
private static class EntrySet implements Set<Map.Entry<Object, Object>> {
private Set<Map.Entry<Object,Object>> entrySet;
private EntrySet(Set<Map.Entry<Object, Object>> entrySet) {
this.entrySet = entrySet;
}
@Override public int size() { return entrySet.size(); }
@Override public boolean isEmpty() { return entrySet.isEmpty(); }
@Override public boolean contains(Object o) { return entrySet.contains(o); }
@Override public Object[] toArray() { return entrySet.toArray(); }
@Override public <T> T[] toArray(T[] a) { return entrySet.toArray(a); }
@Override public void clear() { entrySet.clear(); }
@Override public boolean remove(Object o) { return entrySet.remove(o); }
@Override
public boolean add(Map.Entry<Object, Object> e) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends Map.Entry<Object, Object>> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
return entrySet.containsAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return entrySet.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return entrySet.retainAll(c);
}
@Override
public Iterator<Map.Entry<Object, Object>> iterator() {
return entrySet.iterator();
}
}
@Override
public synchronized boolean equals(Object o) {
return map.equals(o);
}
@Override
public synchronized int hashCode() {
return map.hashCode();
}
@Override
public Object getOrDefault(Object key, Object defaultValue) {
return map.getOrDefault(key, defaultValue);
}
@Override
public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
map.forEach(action);
}
@Override
public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
map.replaceAll(function);
}
@Override
public synchronized Object putIfAbsent(Object key, Object value) {
return map.putIfAbsent(key, value);
}
@Override
public synchronized boolean remove(Object key, Object value) {
return map.remove(key, value);
}
/** @hidden */
@Override
public synchronized boolean replace(Object key, Object oldValue, Object newValue) {
return map.replace(key, oldValue, newValue);
}
@Override
public synchronized Object replace(Object key, Object value) {
return map.replace(key, value);
}
@Override
public synchronized Object computeIfAbsent(Object key,
Function<? super Object, ?> mappingFunction) {
return map.computeIfAbsent(key, mappingFunction);
}
@Override
public synchronized Object computeIfPresent(Object key,
BiFunction<? super Object, ? super Object, ?> remappingFunction) {
return map.computeIfPresent(key, remappingFunction);
}
@Override
public synchronized Object compute(Object key,
BiFunction<? super Object, ? super Object, ?> remappingFunction) {
return map.compute(key, remappingFunction);
}
@Override
public synchronized Object merge(Object key, Object value,
BiFunction<? super Object, ? super Object, ?> remappingFunction) {
return map.merge(key, value, remappingFunction);
}
//
// Special Hashtable methods
@Override
protected void rehash() { /* no-op */ }
@Override
public synchronized Object clone() {
Properties clone = (Properties) cloneHashtable();
clone.map = new ConcurrentHashMap<>(map);
return clone;
}
//
// Hashtable serialization overrides
// (these should emit and consume Hashtable-compatible stream)
@Override
void writeHashtable(ObjectOutputStream s) throws IOException {
List<Object> entryStack = new ArrayList<>(map.size() * 2); // an estimate
for (Map.Entry<Object, Object> entry : map.entrySet()) {
entryStack.add(entry.getValue());
entryStack.add(entry.getKey());
}
// Write out the simulated threshold, loadfactor
float loadFactor = 0.75f;
int count = entryStack.size() / 2;
int length = (int)(count / loadFactor) + (count / 20) + 3;
if (length > count && (length & 1) == 0) {
length--;
}
synchronized (map) { // in case of multiple concurrent serializations
defaultWriteHashtable(s, length, loadFactor);
}
// Write out simulated length and real count of elements
s.writeInt(length);
s.writeInt(count);
// Write out the key/value objects from the stacked entries
for (int i = entryStack.size() - 1; i >= 0; i--) {
s.writeObject(entryStack.get(i));
}
}
@Override
void readHashtable(ObjectInputStream s) throws IOException,
ClassNotFoundException {
// Read in the threshold and loadfactor
s.defaultReadObject();
// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();
// Validate # of elements
if (elements < 0) {
throw new StreamCorruptedException("Illegal # of Elements: " + elements);
}
// create CHM of appropriate capacity
map = new ConcurrentHashMap<>(elements);
// Read all the key/value objects
for (; elements > 0; elements--) {
Object key = s.readObject();
Object value = s.readObject();
map.put(key, value);
}
}
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -153,7 +153,7 @@ class JarFile extends ZipFile {
SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
BASE_VERSION = 8; // one less than lowest version for versioned entries BASE_VERSION = 8; // one less than lowest version for versioned entries
int runtimeVersion = jdk.Version.current().major(); int runtimeVersion = Runtime.version().major();
String jarVersion = String jarVersion =
GetPropertyAction.privilegedGetProperty("jdk.util.jar.version"); GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
if (jarVersion != null) { if (jarVersion != null) {
@ -357,7 +357,7 @@ class JarFile extends ZipFile {
} }
private boolean runtimeVersionExists() { private boolean runtimeVersionExists() {
int version = jdk.Version.current().major(); int version = Runtime.version().major();
try { try {
Release.valueOf(version); Release.valueOf(version);
return true; return true;

View File

@ -106,7 +106,7 @@ abstract class AbstractTask<P_IN, P_OUT, R,
protected Spliterator<P_IN> spliterator; protected Spliterator<P_IN> spliterator;
/** Target leaf size, common to all tasks in a computation */ /** Target leaf size, common to all tasks in a computation */
protected long targetSize; // may be laziliy initialized protected long targetSize; // may be lazily initialized
/** /**
* The left child. * The left child.

View File

@ -211,6 +211,11 @@ public interface DoubleStream extends BaseStream<Double, DoubleStream> {
* .sum(); * .sum();
* }</pre> * }</pre>
* *
* <p>In cases where the stream implementation is able to optimize away the
* production of some or all the elements (such as with short-circuiting
* operations like {@code findFirst}, or in the example described in
* {@link #count}), the action will not be invoked for those elements.
*
* @param action a <a href="package-summary.html#NonInterference"> * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as * non-interfering</a> action to perform on the elements as
* they are consumed from the stream * they are consumed from the stream

View File

@ -209,6 +209,11 @@ public interface IntStream extends BaseStream<Integer, IntStream> {
* .sum(); * .sum();
* }</pre> * }</pre>
* *
* <p>In cases where the stream implementation is able to optimize away the
* production of some or all the elements (such as with short-circuiting
* operations like {@code findFirst}, or in the example described in
* {@link #count}), the action will not be invoked for those elements.
*
* @param action a <a href="package-summary.html#NonInterference"> * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as * non-interfering</a> action to perform on the elements as
* they are consumed from the stream * they are consumed from the stream

View File

@ -209,6 +209,11 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* .sum(); * .sum();
* }</pre> * }</pre>
* *
* <p>In cases where the stream implementation is able to optimize away the
* production of some or all the elements (such as with short-circuiting
* operations like {@code findFirst}, or in the example described in
* {@link #count}), the action will not be invoked for those elements.
*
* @param action a <a href="package-summary.html#NonInterference"> * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as * non-interfering</a> action to perform on the elements as
* they are consumed from the stream * they are consumed from the stream

View File

@ -82,6 +82,19 @@ import java.util.function.UnaryOperator;
* terminal operation is initiated, and source elements are consumed only * terminal operation is initiated, and source elements are consumed only
* as needed. * as needed.
* *
* <p>A stream implementation is permitted significant latitude in optimizing
* the computation of the result. For example, a stream implementation is free
* to elide operations (or entire stages) from a stream pipeline -- and
* therefore elide invocation of behavioral parameters -- if it can prove that
* it would not affect the result of the computation. This means that
* side-effects of behavioral parameters may not always be executed and should
* not be relied upon, unless otherwise specified (such as by the terminal
* operations {@code forEach} and {@code forEachOrdered}). (For a specific
* example of such an optimization, see the API note documented on the
* {@link #count} operation. For more detail, see the
* <a href="package-summary.html#SideEffects">side-effects</a> section of the
* stream package documentation.)
*
* <p>Collections and streams, while bearing some superficial similarities, * <p>Collections and streams, while bearing some superficial similarities,
* have different goals. Collections are primarily concerned with the efficient * have different goals. Collections are primarily concerned with the efficient
* management of, and access to, their elements. By contrast, streams do not * management of, and access to, their elements. By contrast, streams do not
@ -415,6 +428,11 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
* .collect(Collectors.toList()); * .collect(Collectors.toList());
* }</pre> * }</pre>
* *
* <p>In cases where the stream implementation is able to optimize away the
* production of some or all the elements (such as with short-circuiting
* operations like {@code findFirst}, or in the example described in
* {@link #count}), the action will not be invoked for those elements.
*
* @param action a <a href="package-summary.html#NonInterference"> * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as * non-interfering</a> action to perform on the elements as
* they are consumed from the stream * they are consumed from the stream

View File

@ -28,7 +28,6 @@ import java.util.Comparator;
import java.util.Objects; import java.util.Objects;
import java.util.Spliterator; import java.util.Spliterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -104,7 +103,7 @@ class StreamSpliterators {
T_BUFFER buffer; T_BUFFER buffer;
/** /**
* True if full traversal has occurred (with possible cancelation). * True if full traversal has occurred (with possible cancellation).
* If doing a partial traversal, there may be still elements in buffer. * If doing a partial traversal, there may be still elements in buffer.
*/ */
boolean finished; boolean finished;

View File

@ -287,18 +287,35 @@
* statelessness requirement, as well as other thread-safety hazards. * statelessness requirement, as well as other thread-safety hazards.
* *
* <p>If the behavioral parameters do have side-effects, unless explicitly * <p>If the behavioral parameters do have side-effects, unless explicitly
* stated, there are no guarantees as to the * stated, there are no guarantees as to:
* <a href="../concurrent/package-summary.html#MemoryVisibility"><i>visibility</i></a> * <ul>
* of those side-effects to other threads, nor are there any guarantees that * <li>the <a href="../concurrent/package-summary.html#MemoryVisibility">
* different operations on the "same" element within the same stream pipeline * <i>visibility</i></a> of those side-effects to other threads;</li>
* are executed in the same thread. Further, the ordering of those effects * <li>that different operations on the "same" element within the same stream
* may be surprising. Even when a pipeline is constrained to produce a * pipeline are executed in the same thread; and</li>
* <em>result</em> that is consistent with the encounter order of the stream * <li>that behavioral parameters are always invoked, since a stream
* source (for example, {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()} * implementation is free to elide operations (or entire stages) from a
* stream pipeline if it can prove that it would not affect the result of the
* computation.
* </li>
* </ul>
* <p>The ordering of side-effects may be surprising. Even when a pipeline is
* constrained to produce a <em>result</em> that is consistent with the
* encounter order of the stream source (for example,
* {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()}
* must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order * must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order
* in which the mapper function is applied to individual elements, or in what * in which the mapper function is applied to individual elements, or in what
* thread any behavioral parameter is executed for a given element. * thread any behavioral parameter is executed for a given element.
* *
* <p>The eliding of side-effects may also be surprising. With the exception of
* terminal operations {@link java.util.stream.Stream#forEach forEach} and
* {@link java.util.stream.Stream#forEachOrdered forEachOrdered}, side-effects
* of behavioral parameters may not always be executed when the stream
* implementation can optimize away the execution of behavioral parameters
* without affecting the result of the computation. (For a specific example
* see the API note documented on the {@link java.util.stream.Stream#count count}
* operation.)
*
* <p>Many computations where one might be tempted to use side effects can be more * <p>Many computations where one might be tempted to use side effects can be more
* safely and efficiently expressed without side-effects, such as using * safely and efficiently expressed without side-effects, such as using
* <a href="package-summary.html#Reduction">reduction</a> instead of mutable * <a href="package-summary.html#Reduction">reduction</a> instead of mutable

View File

@ -462,9 +462,13 @@ class ZipFile implements ZipConstants, Closeable {
private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> { private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
private int i = 0; private int i = 0;
private final int entryCount;
public ZipEntryIterator() { public ZipEntryIterator() {
ensureOpen(); synchronized (ZipFile.this) {
ensureOpen();
this.entryCount = zsrc.total;
}
} }
public boolean hasMoreElements() { public boolean hasMoreElements() {
@ -472,10 +476,7 @@ class ZipFile implements ZipConstants, Closeable {
} }
public boolean hasNext() { public boolean hasNext() {
synchronized (ZipFile.this) { return i < entryCount;
ensureOpen();
return i < zsrc.total;
}
} }
public ZipEntry nextElement() { public ZipEntry nextElement() {
@ -485,7 +486,7 @@ class ZipFile implements ZipConstants, Closeable {
public ZipEntry next() { public ZipEntry next() {
synchronized (ZipFile.this) { synchronized (ZipFile.this) {
ensureOpen(); ensureOpen();
if (i >= zsrc.total) { if (!hasNext()) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
// each "entry" has 3 ints in table entries // each "entry" has 3 ints in table entries
@ -526,34 +527,34 @@ class ZipFile implements ZipConstants, Closeable {
/* Checks ensureOpen() before invoke this method */ /* Checks ensureOpen() before invoke this method */
private ZipEntry getZipEntry(String name, int pos) { private ZipEntry getZipEntry(String name, int pos) {
byte[] cen = zsrc.cen; byte[] cen = zsrc.cen;
ZipEntry e = new ZipEntry();
int nlen = CENNAM(cen, pos); int nlen = CENNAM(cen, pos);
int elen = CENEXT(cen, pos); int elen = CENEXT(cen, pos);
int clen = CENCOM(cen, pos); int clen = CENCOM(cen, pos);
e.flag = CENFLG(cen, pos); // get the flag first int flag = CENFLG(cen, pos);
if (name != null) { if (name == null) {
e.name = name; if (!zc.isUTF8() && (flag & EFS) != 0) {
} else { name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
} else { } 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.xdostime = CENTIM(cen, pos);
e.crc = CENCRC(cen, pos); e.crc = CENCRC(cen, pos);
e.size = CENLEN(cen, pos); e.size = CENLEN(cen, pos);
e.csize = CENSIZ(cen, pos); e.csize = CENSIZ(cen, pos);
e.method = CENHOW(cen, pos); e.method = CENHOW(cen, pos);
if (elen != 0) { if (elen != 0) {
e.setExtra0(Arrays.copyOfRange(cen, pos + CENHDR + nlen, int start = pos + CENHDR + nlen;
pos + CENHDR + nlen + elen), true); e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
} }
if (clen != 0) { if (clen != 0) {
if (!zc.isUTF8() && (e.flag & EFS) != 0) { int start = pos + CENHDR + nlen + elen;
e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen); if (!zc.isUTF8() && (flag & EFS) != 0) {
e.comment = zc.toStringUTF8(cen, start, clen);
} else { } else {
e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen); e.comment = zc.toString(cen, start, clen);
} }
} }
return e; return e;
@ -817,7 +818,7 @@ class ZipFile implements ZipConstants, Closeable {
); );
} }
/* /**
* Returns an array of strings representing the names of all entries * Returns an array of strings representing the names of all entries
* that begin with "META-INF/" (case ignored). This method is used * that begin with "META-INF/" (case ignored). This method is used
* in JarFile, via SharedSecrets, as an optimization when looking up * in JarFile, via SharedSecrets, as an optimization when looking up
@ -827,14 +828,14 @@ class ZipFile implements ZipConstants, Closeable {
private String[] getMetaInfEntryNames() { private String[] getMetaInfEntryNames() {
synchronized (this) { synchronized (this) {
ensureOpen(); ensureOpen();
if (zsrc.metanames.size() == 0) { if (zsrc.metanames == null) {
return null; return null;
} }
String[] names = new String[zsrc.metanames.size()]; String[] names = new String[zsrc.metanames.length];
byte[] cen = zsrc.cen; byte[] cen = zsrc.cen;
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
int pos = zsrc.metanames.get(i); int pos = zsrc.metanames[i];
names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos), names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
StandardCharsets.UTF_8); StandardCharsets.UTF_8);
} }
return names; return names;
@ -850,7 +851,7 @@ class ZipFile implements ZipConstants, Closeable {
private long locpos; // position of first LOC header (usually 0) private long locpos; // position of first LOC header (usually 0)
private byte[] comment; // zip file comment private byte[] comment; // zip file comment
// list of meta entries in META-INF dir // list of meta entries in META-INF dir
private ArrayList<Integer> metanames = new ArrayList<>(); private int[] metanames;
private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true) private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
// A Hashmap for all entries. // A Hashmap for all entries.
@ -1159,7 +1160,7 @@ class ZipFile implements ZipConstants, Closeable {
int next = -1; int next = -1;
// list for all meta entries // list for all meta entries
metanames = new ArrayList<>(); ArrayList<Integer> metanamesList = null;
// Iterate through the entries in the central directory // Iterate through the entries in the central directory
int i = 0; int i = 0;
@ -1194,13 +1195,21 @@ class ZipFile implements ZipConstants, Closeable {
idx = addEntry(idx, hash, next, pos); idx = addEntry(idx, hash, next, pos);
// Adds name to metanames. // Adds name to metanames.
if (isMetaName(cen, pos + CENHDR, nlen)) { if (isMetaName(cen, pos + CENHDR, nlen)) {
metanames.add(pos); if (metanamesList == null)
metanamesList = new ArrayList<>(4);
metanamesList.add(pos);
} }
// skip ext and comment // skip ext and comment
pos += (CENHDR + nlen + elen + clen); pos += (CENHDR + nlen + elen + clen);
i++; i++;
} }
total = 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) { if (pos + ENDHDR != cen.length) {
zerror("invalid CEN header (bad header size)"); 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 bytes represent a non-directory name
}; * beginning with "META-INF/", disregarding ASCII case.
/*
* Returns true if the specified entry's name begins with the string
* "META-INF/" irrespective of case.
*/ */
private static boolean isMetaName(byte[] name, int off, int len) { private static boolean isMetaName(byte[] name, int off, int len) {
if (len < 9 || (name[off] != 'M' && name[off] != 'm')) { // sizeof("META-INF/") - 1 // Use the "oldest ASCII trick in the book"
return false; return len > 9 // "META-INF/".length()
} && name[off + len - 1] != '/' // non-directory
off++; && (name[off++] | 0x20) == 'm'
for (int i = 1; i < metainf.length; i++) { && (name[off++] | 0x20) == 'e'
byte c = name[off++]; && (name[off++] | 0x20) == 't'
// Avoid toupper; it's locale-dependent && (name[off++] | 0x20) == 'a'
if (c >= 'a' && c <= 'z') { && (name[off++] ) == '-'
c += 'A' - 'a'; && (name[off++] | 0x20) == 'i'
} && (name[off++] | 0x20) == 'n'
if (metainf[i] != c) { && (name[off++] | 0x20) == 'f'
return false; && (name[off] ) == '/';
}
}
return true;
} }
/* /*

View File

@ -1,603 +0,0 @@
/*
* 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;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import sun.security.action.GetPropertyAction;
/**
* A representation of the JDK version-string which contains a version
* number optionally followed by pre-release and build information.
*
* <h2><a name="verNum">Version numbers</a></h2>
*
* A <em>version number</em>, {@code $VNUM}, is a non-empty sequence of
* non-negative integer numerals, without leading or trailing zeroes,
* separated by period characters (U+002E); i.e., it matches the regular
* expression {@code ^[1-9][0-9]*(((\.0)*\.[1-9][0-9]*)*)*$}. The sequence may
* be of arbitrary length but the first three elements are assigned specific
* meanings, as follows:
*
* <blockquote><pre>
* $MAJOR.$MINOR.$SECURITY
* </pre></blockquote>
*
* <ul>
*
* <li><p> <a name="major">{@code $MAJOR}</a> --- The major version number,
* incremented for a major release that contains significant new features as
* specified in a new edition of the Java&#160;SE Platform Specification,
* <em>e.g.</em>, <a href="https://jcp.org/en/jsr/detail?id=337">JSR 337</a>
* for Java&#160;SE&#160;8. Features may be removed in a major release, given
* advance notice at least one major release ahead of time, and incompatible
* changes may be made when justified. The {@code $MAJOR} version number of
* JDK&#160;8 was {@code 8}; the {@code $MAJOR} version number of JDK&#160;9
* is {@code 9}. </p></li>
*
* <li><p> <a name="minor">{@code $MINOR}</a> --- The minor version number,
* incremented for a minor update release that may contain compatible bug
* fixes, revisions to standard APIs mandated by a <a
* href="https://jcp.org/en/procedures/jcp2#5.3">Maintenance Release</a> of
* the relevant Platform Specification, and implementation features outside
* the scope of that Specification such as new JDK-specific APIs, additional
* service providers, new garbage collectors, and ports to new hardware
* architectures. {@code $MINOR} is reset to zero when {@code $MAJOR} is
* incremented. </p></li>
*
* <li><p> <a name="security">{@code $SECURITY}</a> --- The security level,
* incremented for a security-update release that contains critical fixes
* including those necessary to improve security. {@code $SECURITY} is reset
* to zero <strong>only</strong> when {@code $MAJOR} is incremented. A higher
* value of {@code $SECURITY} for a given {@code $MAJOR} value, therefore,
* always indicates a more secure release, regardless of the value of {@code
* $MINOR}. </p></li>
*
* </ul>
*
* <p> The fourth and later elements of a version number are free for use by
* downstream consumers of the JDK code base. Such a consumer may,
* <em>e.g.</em>, use the fourth element to identify patch releases which
* contain a small number of critical non-security fixes in addition to the
* security fixes in the corresponding security release. </p>
*
* <p> The version number does not include trailing zero elements;
* <em>i.e.</em>, {@code $SECURITY} is omitted if it has the value zero, and
* {@code $MINOR} is omitted if both {@code $MINOR} and {@code $SECURITY} have
* the value zero. </p>
*
* <p> The sequence of numerals in a version number is compared to another
* such sequence in numerical, pointwise fashion; <em>e.g.</em>, {@code 9.9.1}
* is less than {@code 9.10.0}. If one sequence is shorter than another then
* the missing elements of the shorter sequence are considered to be zero;
* <em>e.g.</em>, {@code 9.1.2} is equal to {@code 9.1.2.0} but less than
* {@code 9.1.2.1}. </p>
*
* <h2><a name="verStr">Version strings</a></h2>
*
* <p> A <em>version string</em> {@code $VSTR} consists of a version number
* {@code $VNUM}, as described above, optionally followed by pre-release and
* build information, in the format </p>
*
* <blockquote><pre>
* $VNUM(-$PRE)?(\+($BUILD)?(-$OPT)?)?
* </pre></blockquote>
*
* <p> where: </p>
*
* <ul>
*
* <li><p> <a name="pre">{@code $PRE}</a>, matching {@code ([a-zA-Z0-9]+)} ---
* A pre-release identifier. Typically {@code ea}, for an early-access
* release that's under active development and potentially unstable, or {@code
* internal}, for an internal developer build.
*
* <li><p> <a name="build">{@code $BUILD}</a>, matching {@code
* (0|[1-9][0-9]*)} --- The build number, incremented for each promoted build.
* {@code $BUILD} is reset to {@code 1} when any portion of {@code $VNUM} is
* incremented. </p>
*
* <li><p> <a name="opt">{@code $OPT}</a>, matching {@code ([-a-zA-Z0-9\.]+)}
* --- Additional build information, if desired. In the case of an {@code
* internal} build this will often contain the date and time of the
* build. </p>
*
* </ul>
*
* <p> When comparing two version strings the value of {@code $OPT}, if
* present, may or may not be significant depending on the chosen comparison
* method. The comparison methods {@link #compareTo(Version) compareTo()} and
* {@link #compareToIgnoreOpt(Version) compareToIgnoreOpt{}} should be used
* consistently with the corresponding methods {@link #equals(Object) equals()}
* and {@link #equalsIgnoreOpt(Object) equalsIgnoreOpt()}. </p>
*
* <p> A <em>short version string</em> ({@code $SVSTR}), often useful in less
* formal contexts, is simply {@code $VNUM} optionally ended with {@code
* -$PRE}. </p>
*
* @since 9
*/
public final class Version
implements Comparable<Version>
{
private final List<Integer> version;
private final Optional<String> pre;
private final Optional<Integer> build;
private final Optional<String> optional;
private static Version current;
// $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)?
// RE limits the format of version strings
// ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))?
private static final String VNUM
= "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)";
private static final String VNUM_GROUP = "VNUM";
private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?";
private static final String PRE_GROUP = "PRE";
private static final String BUILD
= "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?";
private static final String PLUS_GROUP = "PLUS";
private static final String BUILD_GROUP = "BUILD";
private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";
private static final String OPT_GROUP = "OPT";
private static final String VSTR_FORMAT
= "^" + VNUM + PRE + BUILD + OPT + "$";
private static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
/**
* Constructs a valid JDK <a href="verStr">version string</a> containing a
* <a href="#verNum">version number</a> followed by pre-release and build
* information.
*
* @param s
* A string to be interpreted as a version
*
* @throws IllegalArgumentException
* If the given string cannot be interpreted a valid version
*
* @throws NullPointerException
* If {@code s} is {@code null}
*
* @throws NumberFormatException
* If an element of the version number or the build number cannot
* be represented as an {@link Integer}
*/
private Version(String s) {
if (s == null)
throw new NullPointerException();
Matcher m = VSTR_PATTERN.matcher(s);
if (!m.matches())
throw new IllegalArgumentException("Invalid version string: '"
+ s + "'");
// $VNUM is a dot-separated list of integers of arbitrary length
List<Integer> list = new ArrayList<>();
for (String i : m.group(VNUM_GROUP).split("\\."))
list.add(Integer.parseInt(i));
version = Collections.unmodifiableList(list);
pre = Optional.ofNullable(m.group(PRE_GROUP));
String b = m.group(BUILD_GROUP);
// $BUILD is an integer
build = (b == null)
? Optional.<Integer>empty()
: Optional.ofNullable(Integer.parseInt(b));
optional = Optional.ofNullable(m.group(OPT_GROUP));
// empty '+'
if ((m.group(PLUS_GROUP) != null) && !build.isPresent()) {
if (optional.isPresent()) {
if (pre.isPresent())
throw new IllegalArgumentException("'+' found with"
+ " pre-release and optional components:'" + s + "'");
} else {
throw new IllegalArgumentException("'+' found with neither"
+ " build or optional components: '" + s + "'");
}
}
}
/**
* Parses the given string as a valid JDK <a
* href="#verStr">version string</a> containing a <a
* href="#verNum">version number</a> followed by pre-release and
* build information.
*
* @param s
* A string to interpret as a version
*
* @throws IllegalArgumentException
* If the given string cannot be interpreted a valid version
*
* @throws NullPointerException
* If the given string is {@code null}
*
* @throws NumberFormatException
* If an element of the version number or the build number cannot
* be represented as an {@link Integer}
*
* @return This version
*/
public static Version parse(String s) {
return new Version(s);
}
/**
* Returns {@code System.getProperty("java.version")} as a Version.
*
* @throws SecurityException
* If a security manager exists and its {@link
* SecurityManager#checkPropertyAccess(String)
* checkPropertyAccess} method does not allow access to the
* system property "java.version"
*
* @return {@code System.getProperty("java.version")} as a Version
*/
public static Version current() {
if (current == null) {
current = parse(
GetPropertyAction.privilegedGetProperty("java.version"));
}
return current;
}
/**
* Returns the <a href="#major">major</a> version number.
*
* @return The major version number
*/
public int major() {
return version.get(0);
}
/**
* Returns the <a href="#minor">minor</a> version number or zero if it was
* not set.
*
* @return The minor version number or zero if it was not set
*/
public int minor() {
return (version.size() > 1 ? version.get(1) : 0);
}
/**
* Returns the <a href="#security">security</a> version number or zero if
* it was not set.
*
* @return The security version number or zero if it was not set
*/
public int security() {
return (version.size() > 2 ? version.get(2) : 0);
}
/**
* Returns an unmodifiable {@link java.util.List List} of the
* integer numerals contained in the <a href="#verNum">version
* number</a>. The {@code List} always contains at least one
* element corresponding to the <a href="#major">major version
* number</a>.
*
* @return An unmodifiable list of the integer numerals
* contained in the version number
*/
public List<Integer> version() {
return version;
}
/**
* Returns the optional <a href="#pre">pre-release</a> information.
*
* @return The optional pre-release information as a String
*/
public Optional<String> pre() {
return pre;
}
/**
* Returns the <a href="#build">build number</a>.
*
* @return The optional build number.
*/
public Optional<Integer> build() {
return build;
}
/**
* Returns <a href="#opt">optional</a> additional identifying build
* information.
*
* @return Additional build information as a String
*/
public Optional<String> optional() {
return optional;
}
/**
* Compares this version to another.
*
* <p> Each of the components in the <a href="#verStr">version</a> is
* compared in the follow order of precedence: version numbers,
* pre-release identifiers, build numbers, optional build information. </p>
*
* <p> Comparison begins by examining the sequence of version numbers. If
* one sequence is shorter than another, then the missing elements of the
* shorter sequence are considered to be zero. </p>
*
* <p> A version with a pre-release identifier is always considered to be
* less than a version without one. Pre-release identifiers are compared
* numerically when they consist only of digits, and lexicographically
* otherwise. Numeric identifiers are considered to be less than
* non-numeric identifiers. </p>
*
* <p> A version without a build number is always less than one with a
* build number; otherwise build numbers are compared numerically. </p>
*
* <p> The optional build information is compared lexicographically.
* During this comparison, a version with optional build information is
* considered to be greater than a version without one. </p>
*
* <p> A version is not comparable to any other type of object.
*
* @param ob
* The object to be compared
*
* @return A negative integer, zero, or a positive integer if this
* {@code Version} is less than, equal to, or greater than the
* given {@code Version}
*
* @throws NullPointerException
* If the given object is {@code null}
*/
@Override
public int compareTo(Version ob) {
return compare(ob, false);
}
/**
* Compares this version to another disregarding optional build
* information.
*
* <p> Two versions are compared by examining the version string as
* described in {@link #compareTo(Version)} with the exception that the
* optional build information is always ignored. </p>
*
* <p> A version is not comparable to any other type of object.
*
* @param ob
* The object to be compared
*
* @return A negative integer, zero, or a positive integer if this
* {@code Version} is less than, equal to, or greater than the
* given {@code Version}
*
* @throws NullPointerException
* If the given object is {@code null}
*/
public int compareToIgnoreOpt(Version ob) {
return compare(ob, true);
}
private int compare(Version ob, boolean ignoreOpt) {
if (ob == null)
throw new NullPointerException("Invalid argument");
int ret = compareVersion(ob);
if (ret != 0)
return ret;
ret = comparePre(ob);
if (ret != 0)
return ret;
ret = compareBuild(ob);
if (ret != 0)
return ret;
if (!ignoreOpt)
return compareOpt(ob);
return 0;
}
private int compareVersion(Version ob) {
int size = version.size();
int oSize = ob.version().size();
int min = Math.min(size, oSize);
for (int i = 0; i < min; i++) {
Integer val = version.get(i);
Integer oVal = ob.version().get(i);
if (val != oVal)
return val - oVal;
}
if (size != oSize)
return size - oSize;
return 0;
}
private int comparePre(Version ob) {
Optional<String> oPre = ob.pre();
if (!pre.isPresent()) {
if (oPre.isPresent())
return 1;
} else {
if (!oPre.isPresent())
return -1;
String val = pre.get();
String oVal = oPre.get();
if (val.matches("\\d+")) {
return (oVal.matches("\\d+")
? (new BigInteger(val)).compareTo(new BigInteger(oVal))
: -1);
} else {
return (oVal.matches("\\d+")
? 1
: val.compareTo(oVal));
}
}
return 0;
}
private int compareBuild(Version ob) {
Optional<Integer> oBuild = ob.build();
if (oBuild.isPresent()) {
return (build.isPresent()
? build.get().compareTo(oBuild.get())
: 1);
} else if (build.isPresent()) {
return -1;
}
return 0;
}
private int compareOpt(Version ob) {
Optional<String> oOpt = ob.optional();
if (!optional.isPresent()) {
if (oOpt.isPresent())
return -1;
} else {
if (!oOpt.isPresent())
return 1;
return optional.get().compareTo(oOpt.get());
}
return 0;
}
/**
* Returns a string representation of this version.
*
* @return The version string
*/
@Override
public String toString() {
StringBuilder sb
= new StringBuilder(version.stream()
.map(Object::toString)
.collect(Collectors.joining(".")));
pre.ifPresent(v -> sb.append("-").append(v));
if (build.isPresent()) {
sb.append("+").append(build.get());
if (optional.isPresent())
sb.append("-").append(optional.get());
} else {
if (optional.isPresent()) {
sb.append(pre.isPresent() ? "-" : "+-");
sb.append(optional.get());
}
}
return sb.toString();
}
/**
* Determines whether this {@code Version} is equal to another object.
*
* <p> Two {@code Version}s are equal if and only if they represent the
* same version string.
*
* <p> This method satisfies the general contract of the {@link
* Object#equals(Object) Object.equals} method. </p>
*
* @param ob
* The object to which this {@code Version} is to be compared
*
* @return {@code true} if, and only if, the given object is a {@code
* Version} that is identical to this {@code Version}
*
*/
@Override
public boolean equals(Object ob) {
boolean ret = equalsIgnoreOpt(ob);
if (!ret)
return false;
Version that = (Version)ob;
return (this.optional().equals(that.optional()));
}
/**
* Determines whether this {@code Version} is equal to another
* disregarding optional build information.
*
* <p> Two {@code Version}s are equal if and only if they represent the
* same version string disregarding the optional build information.
*
* @param ob
* The object to which this {@code Version} is to be compared
*
* @return {@code true} if, and only if, the given object is a {@code
* Version} that is identical to this {@code Version}
* ignoring the optinal build information
*
*/
public boolean equalsIgnoreOpt(Object ob) {
if (this == ob)
return true;
if (!(ob instanceof Version))
return false;
Version that = (Version)ob;
return (this.version().equals(that.version())
&& this.pre().equals(that.pre())
&& this.build().equals(that.build()));
}
/**
* Returns the hash code of this version.
*
* <p> This method satisfies the general contract of the {@link
* Object#hashCode Object.hashCode} method.
*
* @return The hashcode of this version
*/
@Override
public int hashCode() {
int h = 1;
int p = 17;
h = p * h + version.hashCode();
h = p * h + pre.hashCode();
h = p * h + build.hashCode();
h = p * h + optional.hashCode();
return h;
}
}

View File

@ -27,6 +27,8 @@ package jdk.internal.jimage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.IntBuffer; import java.nio.IntBuffer;
@ -98,8 +100,34 @@ public class BasicImageReader implements AutoCloseable {
} }
// Open the file only if no memory map yet or is 32 bit jvm // Open the file only if no memory map yet or is 32 bit jvm
channel = map != null && MAP_ALL ? null : if (map != null && MAP_ALL) {
FileChannel.open(imagePath, StandardOpenOption.READ); channel = null;
} else {
channel = FileChannel.open(imagePath, StandardOpenOption.READ);
// No lambdas during bootstrap
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
if (BasicImageReader.class.getClassLoader() == null) {
try {
Class<?> fileChannelImpl =
Class.forName("sun.nio.ch.FileChannelImpl");
Method setUninterruptible =
fileChannelImpl.getMethod("setUninterruptible");
setUninterruptible.invoke(channel);
} catch (ClassNotFoundException |
NoSuchMethodException |
IllegalAccessException |
InvocationTargetException ex) {
// fall thru - will only happen on JDK-8 systems where this code
// is only used by tools using jrt-fs (non-critical.)
}
}
return null;
}
});
}
// If no memory map yet and 64 bit jvm then memory map entire file // If no memory map yet and 64 bit jvm then memory map entire file
if (MAP_ALL && map == null) { if (MAP_ALL && map == null) {

View File

@ -149,6 +149,17 @@ public final class ImageReader implements AutoCloseable {
return reader.getEntryNames(); return reader.getEntryNames();
} }
public String[] getModuleNames() {
Objects.requireNonNull(reader, "image file closed");
int off = "/modules/".length();
return reader.findNode("/modules")
.getChildren()
.stream()
.map(Node::getNameString)
.map(s -> s.substring(off, s.length()))
.toArray(String[]::new);
}
public long[] getAttributes(int offset) { public long[] getAttributes(int offset) {
Objects.requireNonNull(reader, "image file closed"); Objects.requireNonNull(reader, "image file closed");
return reader.getAttributes(offset); return reader.getAttributes(offset);

View File

@ -68,13 +68,14 @@ public class ClassLoaders {
if (s != null && s.length() > 0) if (s != null && s.length() > 0)
bcp = toURLClassPath(s); 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 <working directory>.
URLClassPath ucp = null; URLClassPath ucp = null;
String mainMid = System.getProperty("jdk.module.main"); String mainMid = System.getProperty("jdk.module.main");
String cp = System.getProperty("java.class.path"); String cp = System.getProperty("java.class.path");
if (mainMid == null && (cp == null || cp.length() == 0)) if (mainMid == null && cp == null)
cp = "."; cp = "";
if (cp != null && cp.length() > 0) if (cp != null)
ucp = toURLClassPath(cp); ucp = toURLClassPath(cp);
@ -197,7 +198,7 @@ public class ClassLoaders {
* @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
*/ */
void appendToClassPathForInstrumentation(String path) { void appendToClassPathForInstrumentation(String path) {
appendToUCP(path, ucp); addClassPathToUCP(path, ucp);
} }
/** /**
@ -224,7 +225,7 @@ public class ClassLoaders {
*/ */
private static URLClassPath toURLClassPath(String cp) { private static URLClassPath toURLClassPath(String cp) {
URLClassPath ucp = new URLClassPath(new URL[0]); URLClassPath ucp = new URLClassPath(new URL[0]);
appendToUCP(cp, ucp); addClassPathToUCP(cp, ucp);
return ucp; return ucp;
} }
@ -232,20 +233,28 @@ public class ClassLoaders {
* Converts the elements in the given class path to file URLs and adds * Converts the elements in the given class path to file URLs and adds
* them to the given URLClassPath. * them to the given URLClassPath.
*/ */
private static void appendToUCP(String cp, URLClassPath ucp) { private static void addClassPathToUCP(String cp, URLClassPath ucp) {
String[] elements = cp.split(File.pathSeparator); int off = 0;
if (elements.length == 0) { int next;
// contains path separator(s) only, default to current directory while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
// to be compatible with long standing behavior addURLToUCP(cp.substring(off, next), ucp);
elements = new String[] { "" }; off = next + 1;
} }
for (String s: elements) {
try { // remaining
URL url = Paths.get(s).toRealPath().toUri().toURL(); addURLToUCP(cp.substring(off), ucp);
ucp.addURL(url); }
} catch (InvalidPathException | IOException ignore) {
// malformed path string or class path element does not exist /**
} * 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
} }
} }

View File

@ -54,7 +54,7 @@ public final class ModuleInfoWriter {
ClassWriter cw = new ClassWriter(0); ClassWriter cw = new ClassWriter(0);
String name = md.name().replace('.', '/') + "/module-info"; String name = md.name().replace('.', '/') + "/module-info";
cw.visit(Opcodes.V1_8, ACC_MODULE, name, null, null, null); cw.visit(Opcodes.V1_9, ACC_MODULE, name, null, null, null);
cw.visitAttribute(new ModuleAttribute(md)); cw.visitAttribute(new ModuleAttribute(md));
cw.visitAttribute(new ConcealedPackagesAttribute(md.conceals())); cw.visitAttribute(new ConcealedPackagesAttribute(md.conceals()));

View File

@ -46,12 +46,12 @@ public final class SystemModules {
* and read module-info.class from the run-time image instead of * and read module-info.class from the run-time image instead of
* the fastpath. * the fastpath.
*/ */
public static final String[] MODULE_NAMES = new String[1]; public static final String[] MODULE_NAMES = new String[0];
/** /**
* Hash of system modules. * Hash of system modules.
*/ */
public static String[] MODULES_TO_HASH = new String[1]; public static String[] MODULES_TO_HASH = new String[0];
/** /**
* Number of packages in the boot layer from the installed modules. * Number of packages in the boot layer from the installed modules.
@ -67,7 +67,7 @@ public final class SystemModules {
* When running an exploded image it returns an empty array. * When running an exploded image it returns an empty array.
*/ */
public static ModuleDescriptor[] modules() { public static ModuleDescriptor[] modules() {
return new ModuleDescriptor[0]; throw new InternalError("should not reach here");
} }
} }

Some files were not shown because too many files have changed in this diff Show More